I have a simple checkbox items and when items are selected, it works fine.
I put a button to unselect all selected items . In the debug mode, I can see the checked state being set to unchecked (false) although it is not reflected in the UI. Here is the code:
XAML for Listbox-Checkbox:
<ListBox x:Name="Listitems" Grid.Column="0" SelectionMode="Multiple" ItemsSource="{Binding MonthlyResults}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding logdate}" IsChecked="{Binding Checked ,Mode=TwoWay}" Click="CheckBox_Click"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
XAML for UncheckALL button:
<Button Grid.Row="0" Name="ClearALL" Margin="4,10,4,75" Content="Unselect All" FontFamily="Tahoma" FontSize="12" Click="Button_Click"/>
Code behind:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
var item = cb.DataContext;
Listitems.SelectedItem = item;
HornerPlotPluginModel model = DataContext as HornerPlotPluginModel;
var checkedItems1 = model.MonthlyResults.Where(B => B.Checked == true);
//monthlyresults is the observable collection that populates the checkbox items
model.CDFResults.Clear(); // some function
Chart1.Series.Clear();
Chart1.Axes.Clear();
model.DisplayLogs(); // some function
DrawCurves(); // some function
}
Code behind for the UncheckAll button:
private void Button_Click(object sender, RoutedEventArgs e)
{
HornerPlotPluginModel model = DataContext as HornerPlotPluginModel;
var checkedItems1 = model.MonthlyResults.Where(B => B.Checked == true);
Listitems.SelectedItems.Clear(); //SET CHECKED ITEMS TO FALSE!!!
model.CDFResults.Clear();
Chart1.Series.Clear();
}
I did look at similar post here: WPF UserControl property change not updating
but it went over my head!
Make sure that the class where the Checked property is defined implements the INotifyPropertyChanged interface and raises the PropertyChanged event in the setter of the Checked property:
public class MonthlyReport : INotifyPropertyChanged
{
private bool _checked;
public bool Checked
{
get { return _checked; }
set { _checked = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Then you should be able to simply set the Checked property of all those objects to false to refresh the CheckBox:
HornerPlotPluginModel model = DataContext as HornerPlotPluginModel;
foreach(var item in model.MonthlyResults)
{
item.Checked = false;
}
HornerPlotPluginModel model = DataContext as HornerPlotPluginModel;
foreach(var item in model.MonthlyResults)
{
item.Checked = false;
}
Related
I am trying to capture the SelectedItem for a ListBox when then data template click event is triggered for the Button. I put a breakpoint in the notifypropertychanged event handler, but it never triggers. What am I doing wrong here?
xaml:
<ListBox x:Name="lstbox_playerContainer"
ItemsSource="{Binding ChildObjectOC}"
SelectedItem="{Binding SelectedChildObject, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Name="btn_childButton" Click="btn_childButton_Click"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
c#:
public partial class PlayerCrowdPromptPage: INotifyPropertyChanged {
public PlayerCrowdPromptPage() {
InitializeComponent();
DataContext = this;
}
private ObservableCollection<PlayerCrowdObjectBO> childObjectOC = new ObservableCollection<PlayerCrowdObjectBO>();
public ObservableCollection<PlayerCrowdObjectBO> ChildObjectOC {
get {
return childObjectOC;
}
set {
childObjectOC = value;
}
}
private PlayerCrowdObjectBO selectedChildObject;
public PlayerCrowdObjectBO SelectedChildObject {
get { return selectedChildObject; }
set {
selectedChildObject = value;
OnPropertyChanged("SelectedChildObject");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
if (PropertyChanged != null){
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Clicking on the Button won't automatically select the corresponding item. You may select it programmatically in the event handler though:
private void btn_childButton_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
ListBoxItem lbi = lstbox_playerContainer.ItemContainerGenerator.ContainerFromItem(btn.DataContext) as ListBoxItem;
lbi.IsSelected = true;
}
This should set the SelectedChildObject property and raise the PropertyChanged event.
I implemented a ListBox using this and this. I bind my actual list of 29 objects to it and it works well.
In XAML:
<ListBox Name="WBauNrList" ItemsSource="{Binding}" Grid.Row="7" Grid.Column="2" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" Height="100" >
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding Baunr}" IsChecked="{Binding IsChecked,Mode=TwoWay}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In code:
datenpunktList = new ObservableCollection<Datenpunkt>();
foreach (var d in WerkstattList.DistinctBy(p => p.lokNr))
{
var newd = new Datenpunkt() { Baunr = d.lokNr };
datenpunktList.Add(newd);
}
WBauNrList.ItemsSource = datenpunktList;
But the problem:
I want to have a select-all CheckBoxes to able the user to select and deselect all items. It works strangely!
After checking the selectAll CheckBox, all items will be checked that is not in the scope of the scrollbar (the list is scrolled), then I should scroll down and up to see that all items are checked.
XAML:
<CheckBox Name="selectAll" Click="selectAll_Click" >Secelct all</CheckBox>
Code:
private void selectAll_Click(object sender, RoutedEventArgs e)
{
foreach (Datenpunkt item in WBauNrList.Items)
{
item.IsChecked = true ;
}
}
I don't have any idea what to do.
Thanks in advance, Mo
Your property IsChecked implementation could look like this.
public class Datenpunkt : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
Notify("IsChecked");
}
}
}
Have a look at the MSDN INotifyPropertyChanged page for more information.
I use the ComboBox for binding to string property of view model. I choose the ComboBox instead of TextBox, because i want to have an option to choose from the list (as a suggestion), but I don't want to change the selected text if the ItemsSource changes.
I tried to set the IsSynchronizedWithCurrentItem property to false, but when the list of suggestions change (at the position of the selected text), the Text changes to empty.
It seems that the ComboBox has remembered that the entered text was also in the list and when this item disappears, the Text property is also cleared.
So my question is: Is that a bug, or am I doing something wrong?
If it is a bug, could you suggest some work around?
I created a sample project which preproduces this:
in XAML:
<Window x:Class="TestProject1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox IsSynchronizedWithCurrentItem="False" ItemsSource="{Binding Items}"
IsEditable="True" Text="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Margin="10,39,0,0" VerticalAlignment="Top" Width="120"/>
<Button Click="Button_Click" Content="Update list"
HorizontalAlignment="Left" Margin="10,82,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
In code behind:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow() {
InitializeComponent();
this.DataContext = this;
Items = new List<string>() { "0", "1", "2" };
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private List<string> _items;
public List<string> Items {// I use IEnumerable<string> with LINQ, but the effect is the same
get { return _items; }
set {
if (_items != value) {
_items = value;
RaisePropertyChanged("Items");
}
}
}
private string _selectedText;
public string SelectedText {
get { return _selectedText; }
set {
if (_selectedText != value) {
_selectedText = value;
RaisePropertyChanged("SelectedText");
}
}
}
private void Button_Click(object sender, RoutedEventArgs e) {
var changed = Items.ToList();//clone
int index = changed.IndexOf(SelectedText);
if (index >= 0) {
changed[index] += "a";//just change the currently selected value
}
Items = changed;//update with new list
}
}
This is my fix for that issue:
public class ComboBox : System.Windows.Controls.ComboBox
{
private bool ignore = false;
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (!ignore)
{
base.OnSelectionChanged(e);
}
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
ignore = true;
try
{
base.OnItemsChanged(e);
}
finally
{
ignore = false;
}
}
}
After your ItemsSource has changed, raise a property changed on your selected text to refresh the UI.
So in your Items collection setter, make the change:
RaisePropertyChanged("Items");
RaisePropertyChanged("SelectedText");
EDIT: in your example you aren't just changing the ItemSource, you are changing the text of the item that is the currently selected one but having a text binding on the old text. What are you expecting to see/happen? Are you wanting the selected item to stay the same, even if its text changes?
Modify Button_Click like this (commented lines are new):
private void Button_Click(object sender, RoutedEventArgs e)
{
string tempCopy = SelectedText; // Create a copy of the current value
var changed = Items.ToList();
int index = changed.IndexOf(SelectedText);
if (index >= 0)
{
changed[index] += "a";
}
Items = changed;
SelectedText = tempCopy; // Replace the selected text with the copy we made
}
All this does is makes a copy of SelectedText before Items changes, and then replaces it once the change has been made.
Copy SelectedText
Modify items source
Replace SelectedText with the copy
I have a CheckBox in DataTemplate in Devexpress of GridControl. Which is binded to boolean field of Grid. I am adding the Checked Item (selected Row ID) in Custom List. And on UnChecked of Checkbox removing the item from Custom List . and finally on button click i am inserting the records on button click.
Issue: When i open form first time select an item using CheckBox the Checked event of CheckBox doesn't fire but property change event fires. and on clicking INSERT button it says no item selected. but when i select other row and Click on Insert it Inserts the First Selected item only and not the both previous and Current. It misses the current. Why does this happen? Any Idea?
Infill.cs
public partial class Infill:INotifyPropertyChanged
{
public int InfillID { get; set; }
//some other fields here
private bool isChecked;
public bool IsChecked { get { return isChecked; } set { SetField(ref isChecked, value, "IsChecked"); } }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
InfillForm.xaml
<dxg:GridControl Height="500" Name="grdInfill" VerticalAlignment="Center">
<dxg:GridControl.Columns>
<dxg:GridColumn AllowEditing="True" Width="10">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkSelect" Visibility="Hidden" HorizontalAlignment="Center" IsChecked="{Binding Path=RowData.Row.IsChecked, Mode=TwoWay}" Checked="CheckEdit_Checked" Unchecked="CheckEdit_Unchecked"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
<dxg:GridColumn FieldName="IsChecked" Header="Select" />
<dxg:GridControl.View>
<dxg:TableView Name="grdInfillInner" ShowTotalSummary="True" AutoWidth="True" DetailHeaderContent="True" ShowIndicator="False" ShowGroupPanel="False" CellValueChanging="grdInfillInner_CellValueChanging">
</dxg:TableView>
</dxg:GridControl.View>
</dxg:GridControl>
InfillForm.xaml.cs
private void CheckEdit_Checked(object sender, RoutedEventArgs e)
{
e.Handled = ProcessItem(true);
}
private void CheckEdit_Unchecked(object sender, RoutedEventArgs e)
{
e.Handled = ProcessItem(false);
}
private bool ProcessItem(bool IsChecked)
{
bool result = false;
Infill item = grdInfillInner.FocusedRow as Infill;
if (IsChecked)
{
if (item != null)
{
// DO STUFF HERE EXAMPLE ADD or REMOVE Item to a list, BASED on CHECKED or UNCHECKED!!!
int infillid = item.InfillID;
infillListIDs.Add(infillid);
result = true;
}
}
else
{
if (item != null)
{
if (infillListIDs.Contains(item.InfillID))
{
// if uncheked the checked item then remove from custom list
infillListIDs.Remove(item.InfillID);
}
}
}
grdInfillInner.FocusedRowHandle = -1;
return result;
}
protected void OpenWindow()
{
ReportPopup popup = new ReportPopup();
popup.Owner = this;
popup.WindowStartupLocation = WindowStartupLocation.CenterScreen;
popup.ShowDialog();
}
private void MnuBtnInsert_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
//Delete existing and insert new items in table on every click
BLL.DeleteAllInfillPO();
if (infillListIDs.Count > 0)
{
for (int i = 0; i < infillListIDs.Count; i++)
{
//insert selected Checked items id in database
BLL.GetInfillIDAndInsertIntoInfillPO(infillListIDs[i]);
}
BtnView.Visibility = Visibility.Visible;
BtnInsert.Visibility = Visibility.Hidden;
//show report of inserted items
OpenWindow();
}
else
{
MessageBox.Show("Please select item/s from list", "Select Option", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
I am not able to get the Checkbox by name that is inside DataTemplate so added boolean field and binded to CheckBox that is inside datatemplate.
Help Appreciated!
The CellTemplate should have an element named "PART_Editor".
change this
<CheckBox Name="chkSelect" .../>
for this:
<CheckBox x:Name="PART_Editor" .../>
and please use MVVM when programming in WPF. winforms-like code behind type of stuff is disgusting.
<grid:GridColumn AllowEditing="True" Header="Completed">
<grid:GridColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="PART_Editor" IsChecked="{Binding Path=Data.CompletedField}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DataTemplate>
</grid:GridColumn.CellTemplate>
</grid:GridColumn>
Remember to add the Data.Field in the Binding Path. Good luck.
Am Using the checkbox in listbox items, how to Checked and Unchecked all checkboxes from the listbox?
<ListBox Height="168" HorizontalAlignment="Left" Margin="45,90,0,0" Name="listBox1" VerticalAlignment="Top" Width="120">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding Ck, Mode=TwoWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
DataBinding is :
List<uu> xx = new List<uu>();
xx.Add(new uu { Name = "A", Ck = false });
xx.Add(new uu { Name = "A", Ck = false });
listBox1.ItemsSource = xx;
Update :
Is it possible to do something like this:
foreach (ListBoxItem item in listBox1.Items)
{
CheckBox ch = (CheckBox)item;
ch.IsChecked = true;
}
A couple of things to consider.
1) First use an ObservableCollection (preferred) or a BindingList instead of a List as your datasource
2) Make sure you implement INotifyPropertyChanged on your class. See an example here
3) Now that you have your binding setup correctly, loop through the collection and set the checked property to false using a foreach or other loop. The binding system will handle the rest and the changes in your list will be properly reflected on the UI
UPDATE: Added a brief code example
In your code-behind:
ObservableCollection<uu> list = new ObservableCollection<uu>();
MainWindow()
{
InitializeComponent();
// Set the listbox's ItemsSource to your new ObservableCollection
ListBox.ItemsSource = list;
}
public void SetAllFalse()
{
foreach (uu item in this.list)
{
item.Ck = false;
}
}
Implementing INotifyPropertyChanged in uu class:
public class uu: INotifyPropertyChanged
{
private bool _ck;
public bool Ck
{
get { return _ck; }
set
{
_ck = value;
this.NotifyPropertyChanged("Ck");
}
}
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
You would typically just use databindings as demonstrated below.
List<uu> items = listbox1.ItemsSource as List<uu>();
foreach (var item in items)
item.Ck = true;
I am inferring the Ck variable name from your databindings and the ItemsSource type from your sample code.