So I have a ListBox
with CheckBox
-es that have the IsChecked
property bound to the Item's property called IsSelected
. That produces a weird behavior where if I click on the item itself it checks the checkbox (good) and sets the property on the item (good), but doesn't actually select the item in the list box, ie. the highlighting isn't there. I am guessing that the ListBox
IsSelected
property needs to be set as well for that right? Now, I am trying to get the multi-select behavior to work so I changed the SelectionMode
to Extended
. Now, I can select only Items, not the checkboxes. What happens is that if I use SHIFT + click by pointing at the area next to the item, not the item itself, then it select multiple items, but clicking on the items themselves doesn't do the trick of multi-selection not does it check the checkboxes. What is going on in here?
I would like to be able to select multiple items by holding shift etc, and have that trigger the property on the Elevation item so I know which ones are checked. Any help is appreciated.
Here's my XAML:
<ListBox x:Name="LevelsListBox" ItemsSource="{Binding Elevations, UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended" BorderThickness="0"> <ListBox.ItemTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
My View Model:
public class AxoFromElevationViewModel : ViewModelBase { public AxoFromElevationModel Model { get; } public RelayCommand CheckAll { get; } public RelayCommand CheckNone { get; } public AxoFromElevationViewModel(AxoFromElevationModel model) { Model = model; Elevations = Model.CollectElevations(); CheckAll = new RelayCommand(OnCheckAll); CheckNone = new RelayCommand(OnCheckNone); } private void OnCheckNone() { foreach (var e in Elevations) { e.IsSelected = false; } } private void OnCheckAll() { foreach (var e in Elevations) { e.IsSelected = true; } } /// <summary> /// All Elevation Wrappers. /// </summary> private ObservableCollection<ElevationWrapper> _elevations = new ObservableCollection<ElevationWrapper>(); public ObservableCollection<ElevationWrapper> Elevations { get { return _elevations; } set { _elevations = value; RaisePropertyChanged(() => Elevations); } } }
Finally my Elevation Class:
public sealed class ElevationWrapper : INotifyPropertyChanged { public string Name { get; set; } public ElementId Id { get; set; } public object Self { get; set; } private bool _isSelected; public bool IsSelected { get { return _isSelected; } set { _isSelected = value; RaisePropertyChanged("IsSelected"); } } public ElevationWrapper(View v) { Name = v.Name; Id = v.Id; Self = v; IsSelected = false; } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propname) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); } }
2 Answers
Answers 1
You should bind the IsSelected
property of your ListBoxItem
s to the IsSelected
property of your view model. This way CheckBox
es will trigger the selection and when you select an item, the related CheckBox
will be checked.
<ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="IsSelected" Value="{Binding IsSelected}"/> </Style> </ListBox.ItemContainerStyle>
Answers 2
It seems to me you want to sync 3 properties ListBoxItem.IsSelected, CheckBox.IsChecked and your models IsSelected. My advice is that only one of the templates/styles should bind to the underlying model so I will add Yusuf answer as I will use the ListBoxItem style to bind to your model property. After that you should bind the Checkbox.IsChecked to the ListBoxItem.IsSelected and your ListBox should look like this:
<ListBox x:Name="LevelsListBox" ItemsSource="{Binding Elevations, UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended" BorderThickness="0"> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="IsSelected" Value="{Binding IsSelected}"/> </Style> </ListBox.ItemContainerStyle> <ListBox.ItemTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Content="{Binding Name}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Always try to bind XAML properties in a chain way, e.g. model.A binds to Model.B binds to Model.C, doing this should help you keep updates consistent and avoid wierd cases.
There is an issue with this code though, after you select multiple items and click one check box it will only unselect that item but if you click another item it will unselect all except that item.
0 comments:
Post a Comment