ComboBox in ListBox doesn't update IsChecked properly - c#

I have made a CheckedListBox using the following:
<ListBox x:Name="lst_checkBoxList" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and am populating it using the following:
public List<CheckedListItem> listItems = new List<CheckedListItem>();
public class CheckedListItem
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsChecked { get; set; }
public CheckedListItem(int id, string name, bool ischecked)
{
Id = id;
Name = name;
IsChecked = ischecked;
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
listItems.Add(new CheckedListItem(0, "item 1", false));
listItems.Add(new CheckedListItem(0, "item 2", false));
listItems.Add(new CheckedListItem(0, "item 3", false));
listItems.Add(new CheckedListItem(0, "item 4", false));
lst_checkBoxList.ItemsSource = listItems;
listItems[0].IsChecked = true; //This correctly sets the first CheckBox as checked.
}
private void button2_Click(object sender, RoutedEventArgs e)
{
listItems[0].IsChecked = true; //This does not affect the CheckBox, despite changing the value it is bound to.
}
If I change the data behind one of the CheckBoxes immediately after setting the ItemsSource, the CheckBox is ticked accordingly, but if I try to change the value anywhere else in the code the CheckBox remains unchecked...can anyone help me work out why?

You need to notify the control that the property it is bound to has been updated, by implementing the INotifyPropertyChanged interface in CheckedListItem:
public class CheckedListItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _IsChecked;
public bool IsChecked
{
get { return _IsChecked; }
set
{
_IsChecked = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}

You need to implement the INotifyPropertyChanged interface on your CheckedListItem class and then notify on any property changes.

Related

Checkbox binding WPF mvvm pattern

I have to bind the changes of checkbox in the listview.
checkbox should work in such a way that if i select all checkbox and uncheck a single checkbox then header checkbox should deselect. Same way if i have 3 child checkbox ,and individually select all then parent checkbox should select.
i am using MVVM pattern
xaml
<GridViewColumn Width="80" >
<GridViewColumn.Header >
<!--<CheckBox x:Name="cbSelectAll" IsChecked="{Binding ModelDetails.IsChecked}" Command="{Binding cbSelectAll_Checked}"/>-->
<CheckBox x:Name="cbSelectAll" Command="{Binding CbSelectAll_Checked}" IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" />
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<WrapPanel x:Name="Layout" >
<CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}" Command="{Binding CheckSingle}"/>
</WrapPanel>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
viewmodel.cs
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
//publishing the event in current classs
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public Item(string name, string matches, string date, bool isSelected)
{
Name = name;
Type = matches;
Date = date;
IsSelected = isSelected;
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public string Name { get; set; }
public string Type { get; set; }
public string Date { get; set; }
}
here is the another class
public class AddedFilesViewModel : INotifyPropertyChanged
{
public ICommand CbSelectAll_Checked { get; set; }
public ICommand UploadBtnClick { get; set; }
public ICommand CheckSingle { get; set; }
CbSelectAll_Checked = new RelayCommands(SelectAllBtnExecute, SelectAllBtnCanExecute);
UploadBtnClick = new RelayCommands(UploadBtnExecute, UploadBtnCanExecuteUpload);
CheckSingle = new RelayCommands(SingleCheckBoxExecute, SingleCheckBoxExecuteCanExecute);
public void SelectAllBtnExecute(object param)
{
if (selectedStatus == false)
{
foreach (var item in Items)
{
item.IsSelected = true;
}
selectedStatus = true;
}
else
{
foreach (var item in Items)
{
item.IsSelected = false;
}
selectedStatus = false;
}
}
public void SingleCheckBoxExecute(object param)
{
MessageBox.Show("hello");
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}
}
public bool SelectAllBtnCanExecute(object param)
{
return true;
}
public void UploadBtnExecute(object param)
{
List<Item> selectedFiles = new List<Item>();
if (Items != null)
{
foreach (var selectedItems in Items)
{
if (selectedItems.IsSelected)
{
selectedFiles.Add(selectedItems);
}
}
I can see the following block need to be changed, Please share full xaml file so I can understand your data binding.
<CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}" Command="{Binding CheckSingle}"/>
You need to edit it as "DataContext.IsSelected" and need to set binding source, it may be data grid or even full xaml based on your business logic to bind data. An example:
<CheckBox IsChecked="{Binding DataContext.IsSelected,Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Command="{Binding CheckSingle}"/>
I've just given sample example, there are many other ways to achive it.
Maybe I am saying shit but I would try that:
Remove all commands
in isChecked set I would put all you put in selectAllButtonExecute
in isChecked get I would check if all checkbox are checked and return true or false accordingly
in IsSelected set I would add OnPropertyChanged("IsChecked");

C# wpf datagrid, selecting one checkbox should select few others

When a CheckBox is selected, few others also need to be selected based on the condition. Here I am trying to load the DataGrid with list of names, when I select one name, other names that start with same letter should be checked.
Please suggest me how to proceed with this.
How can I access the users list in Users class?
Xaml code:
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<User> users = new List<User>();
users.Add(new User() { Id = 1, Name = "John Doe" });
users.Add(new User() { Id = 2, Name = "Jane Doe"});
users.Add(new User() { Id = 3, Name = "Sammy Doe" });
users.Add(new User() { Id = 3, Name = "Abhi" });
users.Add(new User() { Id = 3, Name = "Amy" });
users.Add(new User() { Id = 3, Name = "Arin" });
users.Add(new User() { Id = 3, Name = "Kate" });
users.Add(new User() { Id = 3, Name = "Kane" });
dgUsers.ItemsSource = users;
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public bool isSelected;
public bool IsSelected
{
get
{
//I can implement my condition here, but how to access the users list?
return this.isSelected;
}
set
{
this.isSelected = value;
}
}
}
}
This way you can not access the list of users. you can add a click such as:
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Click="CheckBox_Click"/>
xaml.cs code,
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var checkBox = sender as CheckBox;
//checkBox.IsChecked
//here you found checkbox IsChecked Property based on value you can write your code here.
}
Note: If you want to notify it on UI than you have to implement INotifyPropertyChanged for updating UI.
First of all ur isSelected property should be private.
Xaml
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Click="CheckBox_OnClick"
/>
MainWindow.cs
private void CheckBox_OnClick(object sender, RoutedEventArgs e)
{
var checkbox = sender as CheckBox;
string name = (checkbox.DataContext as User).Name;
var users = dgUsers.ItemsSource;
foreach (var item in dgUsers.ItemsSource)
{
var test = item as User;
test.IsSelected = true;
}
dgUsers.Items.Refresh();
}
AS said above by Hima_devils if you don't want to Refresh ur whole dataGrid u can implement INotifyPropertyChanged in your User class and inside ur setter u would
NotifyPropertyChanged("IsSelected");
First of all I suggest you to decouple your logic from the UI (i.e. your Window object). That means using data binding and moving your login in an object called ViewModel.
In order to work correctly normally your viewmodels should implement INotifyPropertyChanged. This interface represents an object which notifies if one among its properties changes its value. So you can use this mechanism for selecting the other users which belong to the list.
Let's see how.
First of all the ViewModel:
public class ViewModel : PropertyChangedBase, IWeakEventListener
{
private List<User> users = new List<User>();
private bool suspendListening;
public ViewModel()
{
users.Add(CreateUser(1, "John Doe"));
users.Add(CreateUser(2, "Jane Doe"));
users.Add(CreateUser(3, "Sammy Doe"));
users.Add(CreateUser(3, "Abhi"));
users.Add(CreateUser(3, "Amy"));
users.Add(CreateUser(3, "Arin"));
users.Add(CreateUser(3, "Kate"));
users.Add(CreateUser(3, "Kane"));
}
public IList<User> Users
{
get
{
return users;
}
}
private User CreateUser(int id, string name)
{
User user = new User();
user.Id = id;
user.Name = name;
PropertyChangedEventManager.AddListener(user, this, String.Empty);
return user;
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (managerType == typeof(PropertyChangedEventManager))
{
PropertyChangedEventArgs propertyChangedEventArgs = e as PropertyChangedEventArgs;
User changedUser = sender as User;
if (propertyChangedEventArgs.PropertyName == "IsSelected" && changedUser.IsSelected && !suspendListening)
{
try
{
suspendListening = true;
foreach (User user in users)
{
if (user.Id == changedUser.Id)
{
user.IsSelected = true;
}
}
}
finally
{
suspendListening = false;
}
}
return true;
}
return false;
}
}
where PropertyChangedBase is a base class which implements INotifyPropertyChanged. Moreover I used weak events for checking when a user is selected.
As you can see if you select a user, all the other user with the same Id as automatically selected.
Your User class should derive from PropertyChangedBase too:
public class User : PropertyChangedBase
{
private bool isSelected;
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected
{
get
{
return isSelected;
}
set
{
if (isSelected != value)
{
isSelected = value;
NotifyOfPropertyChange<bool>(() => IsSelected);
}
}
}
}
so your XAML will be:
<DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False" CanUserAddRows="false">
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsSelected, Mode=TwoWay}" />
<DataGridTextColumn Binding="{Binding Id}" />
<DataGridTextColumn Binding="{Binding Name}" />
</DataGrid.Columns>
</DataGrid>
Just remember to initialize the DataContext property of your Window:
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent();
DataContext = new ViewModel();
}
}

Listbox First Item Selected in mvvm

I am new to mvvm. I have a listbox in my silverlight application which is binded to a observable collection in view model i want to make the listbox with first item selected. I tired this but it doesnt work.
<ListBox Height="431" Canvas.Left="17" Canvas.Top="77" Width="215" FontSize="13" ItemsSource="{Binding Path=Categorys, Mode=TwoWay}" DataContext="{Binding}" SelectedItem="{Binding CurrentCategory, Mode=TwoWay}" ItemTemplate="{StaticResource CategoryDataTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Name="lst_category">
then i added this in mainpage load of mainpage viewmodel
CurrentCategory = Categorys[0];
Can any one Help me
Do the following steps:
Make sure that the collection Categorys is filled already. You might need to use AsycCTP, Asynchronous Programming with Async and Await or some other mechanism to first wait for the collection to be filled.
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
Implement INotifyPropertyChanged in ViewModel exposing the Property, CurrentCategory and raise the event of PropertyChanged from within the Setter of the Property.
private Category _currentCategory = null;
public Category CurrentCategory
{
get { return _currentCategory; }
set
{
if (_currentCategory != value)
{
_currentCategory = value;
// Update bindings
RaisePropertyChanged("CurrentCategory");
}
}
}
Now you can use the same piece of code:
CurrentCategory = Categorys[0];
Try using ICollectionView and IsSynchronizedWithCurrentItem. The CollectionView has all the functionality you need. For example MoveToFirst().
Xaml:
<ListBox ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True" />
ViewModel:
public class ViewModel :INotifyPropertyChanged
{
private ObservableCollection<Category> _categories = new ObservableCollection<Category>();
private Category _currentCategory;
public ObservableCollection<Category> Categories
{
get { return _categories; }
set { _categories = value; OnPropertyChanged("Categories");}
}
public Category CurrentCategory
{
get { return _currentCategory; }
set { _currentCategory = value; OnPropertyChanged("CurrentCategory");}
}
public ICollectionView CategoriesView { get; private set; }
public ViewModel()
{
Categories.Add(new Category{Id = Guid.NewGuid(), Name = "Cat1"});
Categories.Add(new Category{Id = Guid.NewGuid(), Name = "Cat2"});
Categories.Add(new Category{Id = Guid.NewGuid(), Name = "Cat3"});
CategoriesView = CollectionViewSource.GetDefaultView(Categories);
CategoriesView.CurrentChanged += OnCategoriesChanged;
CategoriesView.MoveCurrentToFirst();
}
private void OnCategoriesChanged(object sender, EventArgs e)
{
var selectedCategory = CategoriesView.CurrentItem as Category;
if (selectedCategory == null) return;
CurrentCategory = selectedCategory;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Category
{
public Guid Id { get; set; }
public string Name { get; set; }
}
You Should Try This Way also.................
List c = new List
CurrentCategory = c.firstOrDefault()

Update listview from code behind

I have the following code in xaml:
<ListView Name="listView1" IsSynchronizedWithCurrentItem="True" >
<ListView.View>
<GridView>
<GridViewColumn Header="MyList">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Cost, Mode=TwoWay}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
on my code behind I have:
public partial class LogIn : UserControl, INotifyCollectionChanged
{
class Product
{
public string Name { get; set; }
public int Cost { get; set; }
}
ObservableCollection<Product> MyList = new ObservableCollection<Product>()
{
new Product(){ Cost=14},
new Product(){ Cost=15},
new Product(){ Cost=5},
new Product(){ Cost=20}
};
event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
// constructor
public LogIn()
{
InitializeComponent();
listView1.DataContext = MyList;
}
private void button5_Click(object sender, RoutedEventArgs e)
{
this.MyList[0].Cost = 123456789;
// !!!!!!!!!!!!!!! I want the listview to update when I press this button
}
The listview does not change when I update on the last method. what do I have to do so that I can update the listview cost values with code behind?
Edit
Thanks to SLaks I made the following changes to my Product class and it worked.
public class Product : INotifyPropertyChanged
{
private int _cost;
public string Name { get; set; }
public int Cost
{
get
{
return _cost;
}
set
{
_cost = value;
OnPropertyChanged("Cost");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
also I added the following line in the constructor of the usercontroll:
listView1.ItemsSource = MyList;
You need to implement INotifyPropertyChanged in the Product class so that WPF knows when your properties change.

How to check for Specific Item checked or Unchecked

i made check box in wpf ,Got it from Internet.I want to see which item is checked or unchecked.Any idea how to do this
here goes the code
Class
public class CheckedListItem
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsChecked { get; set; }
public string Email { get; set; }
}
Usage
List<CheckedListItem> AvailablePresentationObjects = new List<CheckedListItem>();
CheckedListItem item = new CheckedListItem();
for (int i = 0; i < 10; i++)
{
item = new CheckedListItem();
item.Id = i;
item.Name = i.ToString();
item.IsChecked = false;
AvailablePresentationObjects.Add(item);
}
list.ItemsSource = AvailablePresentationObjects;
XMAL
<ListBox x:Name="list" Margin="3,277,0,0" Height="234" VerticalAlignment="Top" Selec
tionMode="Extended">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<my:RibbonCheckBox Label="{Binding Name}" IsChecked="{Binding IsChecked}" />
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
took it from Here
Checked ListBox
Question is
How to implement property change so
that i can know which item was checked
and which was unchecked
My Code solution
You can get collection of selected items: list.SelectedItems.
Each item you can cast to CheckedListItem and check that item is checked.
If you want to handle property changing, you should implement interface INotifyPropertyChanged in CheckedListItem class
Example of INotifyPropertyChanged:
Add this to your class and call OnPropertyChanged in properties:
private boolean _isChecked;
public boolean IsChecked
{
get { return _isChecked; }
set
{
_isChecked= value;
OnPropertyChanged("IsChecked");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}

Categories

Resources