How to access checkbox in ListBox items - c#

I'm trying to make a ListBox with checkboxes into it.
In xaml I have:
<ListBox ItemsSource="{StaticResource ResourceKey=lstMaterialesCL}" SelectionMode="Multiple" Name="lstMaterial" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkMaterial" Content="{Binding DescCompuesta}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and my ListBox looks as:
It is ok, but look it, when I checked "Municipales" the item in the ListBox is not selected, and when I select in the ListBox "Industriales" it is not checked
If I inspect the items selected into the ListBox it don't coincide with the items Checked
foreach (var item in lstMaterial.SelectedItems)
{
MessageBox.Show(((MaterialesCL)item).DescCompuesta);
}
It shows me "Oficiales", "Industriales" and "Destrucciones" but the user was want select "Municipales" and "Destrucciones"
How I can to make coincide the ListBox items selected with the CheckBox checked if the CheckBox checked is mandatory?

XAML:
DescCompuestaList is a list of CheckListGeneric
<ListBox ItemsSource="{Binding DescCompuestaList}" >
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding DescCompuesta}" IsChecked="{Binding IsChecked}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here your CheckListGeneric class
public class CheckListGeneric: ViewModelBase
{
#region ..:: Fields ::..
private bool _isChecked;
#endregion
#region ..:: Properties ::..
public long Id { get; set; }
public string DescCompuesta{ get; set; }
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
#endregion
}
You can get all selected using a simple query
var selectedItems = DescCompuestaList.Where(x => x.IsChecked)
simple as life.

How about binding CheckBox's IsChecked property to ListBoxItem's IsSelected property.
Something like: IsChecked={Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}
In your example:
<ListBox ItemsSource="{StaticResource ResourceKey=lstMaterialesCL}" SelectionMode="Multiple" Name="lstMaterial" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkMaterial" Content="{Binding DescCompuesta}" IsChecked={Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

For me it's always easiest way to use Blend for making templates.
Open project in blend and make one listBox, then select that ListBox and add template like in picture.
just to show purpose i have add simple checkBox and TextBlock, and you can make it as u like it.
in ViewModel i have made simple observable collection just to show purpose and bound ItemsSource to Users:
public class TestVM
{
public ObservableCollection<User> Users { get; set; }
public TestVM()
{
Users = new ObservableCollection<User>
{
new User{ IsChecked=true, Name="User1" },
new User{ IsChecked=false, Name="User2" },
new User{ IsChecked=true, Name="User3" },
new User{ IsChecked=false, Name="User3" },
};
}
}
public class User
{
public bool IsChecked { get; set; }
public string Name { get; set; }
}
This way you can make any template you like.

Wow, I tested all your suggestions, thank you so much to all, after all tests, the solution how I need it is more or less like this:
On xaml:
<StackPanel Orientation="Horizontal">
<ListBox ItemsSource="{Binding MaterialesVM}" SelectionMode="Multiple"
Name="ListBoxMateriales" Width="300" Height="200"
HorizontalAlignment="Left" VerticalAlignment="Top">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsChecked, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Content="{Binding DescCompuesta}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="btnPrueba" Style="{StaticResource BotonContent}"
Content="Selected" Width="80" Height="30" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,0,0,0" Click="btnPrueba_Click"/>
<Button Name="btnLimpia" Style="{StaticResource BotonRechazar}"
Width="30" Height="30" Click="btnLimpia_Click" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5,0,0,0" ToolTipService.ToolTip="Limpia Todos"/>
<Button Name="btnMarca" Style="{StaticResource BotonAceptar}"
Width="30" Height="30" Click="btnMarca_Click" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5,0,0,0" ToolTipService.ToolTip="Selecciona Todos"/>
</StackPanel>
On this way I don't care on where clicked, the item will be selected or un-selected (on the CheckBox and on the ListItem)
And to see the items selected:
// To show the selected items
private void btnPrueba_Click(object sender, RoutedEventArgs e)
{
var selectedItems = MaterialesVM.Where(x => x.IsChecked);
foreach (var item in selectedItems)
{
MessageBox.Show(((MaterialesCL)item).DescCompuesta);
}
}
To select all items:
// To select all items
private void btnMarca_Click(object sender, RoutedEventArgs e)
{
var Items = ListBoxMateriales.Items;
foreach (MaterialesCL item in Items)
{
item.IsChecked = true;
}
}
To un-select all items:
// To un-select all items
private void btnLimpia_Click(object sender, RoutedEventArgs e)
{
var Items = ListBoxMateriales.Items;
foreach (MaterialesCL item in Items)
{
item.IsChecked = false;
}
}
and my classes are:
MaterialesCL.cs
public class MaterialesCL : INotifyPropertyChanged
{
public int Material { get; set; }
public string Descripcion { get; set; }
public string DescCompuesta { get; set; }
private bool _ischecked;
public bool IsChecked
{
get { return _ischecked; }
set
{
_ischecked = value;
OnPropertyChanged("IsChecked");
}
}
#region PropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
LstMaterialesCL.cs
public class LstMaterialesCL : ObservableCollection<MaterialesCL>, INotifyPropertyChanged
{
public LstMaterialesCL()
{
BasculaEntities _context = new BasculaEntities();
var Query = (from m in _context.Materiales
select new { m.Material, m.Descripcion}
).OrderBy(m => m.Material).ToList();
foreach (var item in Query)
{
this.Add(new MaterialesCL { Material = item.Material,
Descripcion = item.Descripcion, DescCompuesta = item.Material.ToString("000") + " - " + item.Descripcion,
IsChecked=false});
}
}
}
and on my UserControl MaterialesVM is an instance of LstMaterialesCL
LstMaterialesCL MaterialesVM = new LstMaterialesCL();
and so my test of ListBox with CheckBoxes works as I need.
Thank to all you I has learn so much.

Related

WPF - How to trigger an event for each element(button) in a ListBox?

I'd like to trigger event for the elemens which is button in a listbox, the view is as below. It is a listbox with 32 buttons.The purpose is to toggle the button between 0-1 and trigger event for each element.
There are two solutions I am thinking about. The solution one is to set command for each button, it works but the problem is I can't catch a selectedItem or a selectedIndex successfully so that even thougn I know the button is toggled, but I don't know the item index.
<ListBox x:Name="lbDirection"
Grid.Row="1"
Grid.Column="1"
SelectionMode="Extended"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Margin="30,26,44,83"
Style="{StaticResource ListBoxHorz}"
ItemContainerStyle="{StaticResource ItemNoBorder}"
SelectedItem="{Binding SelectedLineItem}"
ItemsSource="{Binding ButtonList}"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource ChangeButton}"
Command="{Binding DataContext.ToggleDirectionCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType= ListBox}}">
<Button.Content>
<TextBlock Text="{Binding BtnText}"
TextDecorations="Underline" />
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ViewModel:
public class DigitalIOViewModel : BindableBase
{
public ICommand ToggleDirectionCommand { get; set; }
public ICommand ToggleStateCommand { get; set; }
private ObservableCollection<LineButtons> btnlist;
private LineButtons _selectedLineItem;
public LineButtons SelectedLineItem
{
get { return _selectedLineItem; }
set {
_selectedLineItem=value;
OnPropertyChanged("SelectedLineItem");
}
}
public DigitalIOViewModel()
{
btnlist = new ObservableCollection<LineButtons>();
CreateButtonList();
ToggleDirectionCommand = new RelayCommand(ToggleDirectionAction);
}
private void ToggleDirectionAction()
{
LineButtons selectedLineItem = SelectedLineItem;
int lineIndex=(SelectedLineItem!= null && ButtonList!=null)? ButtonList.IndexOf(SelectedLineItem) : -1;
if (selectedLineItem.BtnText == "1" && lineIndex == 0)
{
ButtonList[lineIndex] = new LineButtons() { BtnText = "0" };
}
else
ButtonList[lineIndex] = new LineButtons() { BtnText = "1" };
}
public ObservableCollection<LineButtons> ButtonList
{
get { return btnlist; }
set { btnlist = value; OnPropertyChanged("ButtonList"); }
}
public void CreateButtonList()
{
for (int i = 0; i < 32; i++)
{
ButtonList.Add(new LineButtons() { BtnText = "1"});
}
}
}
public class LineButtons : BindableBase
{
private string btnText;
public string BtnText
{
get { return btnText; }
set { btnText = value; OnPropertyChanged("BtnText"); }
}
}
I cannot get a correct selectedIndex from this code.
The second solution is to use the IsSelected/SelectedItem property instead of button command binding, I was wondering if there is conflict with the button command binding for item and IsSelected property fot listbox,so we can't use them at the same time, can someone help me out which is the best solution? Thanks in advance.
In addition to the Command property you can set the CommandParameter to the current LineButtons item (class names should be singular, names of collections use plural):
<ListBox.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource ChangeButton}"
Command="{Binding DataContext.ToggleDirectionCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType= ListBox}}"
CommandParameter="{Binding}">
<Button.Content>
<TextBlock Text="{Binding BtnText, UpdateSourceTrigger=PropertyChanged}"
TextDecorations="Underline" />
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
Then get the current item, the item that triggered the command, by accessing the command parameter:
private void Execute(object commandParameter)
{
var currentLineButton = commandParameter as LineButtons;
...
}

Returning bound checkbox values using MVVM in a WPF form

I have an object that consists of a string and an array. The string populates a ComboBox and the array populates a ListView depending on the selected string value. Each line of the ListViewconsists of a TextBlock and a CheckBox.
On submit I want to be able to verify which items have been selected for further processing but there's a disconnect when using the MVVM approach. I currently have the DataContext of the submit Button binding to the ListView but only the first value is being returned upon submit (somewhere I need to save the selected values to a list I assume but I'm not sure where). I added an IsSelected property to the model which I think is the first step, but after that I've been grasping at straws.
Model
namespace DataBinding_WPF.Model
{
public class ExampleModel { }
public class Example : INotifyPropertyChanged
{
private string _name;
private string[] _ids;
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
public string[] IDs
{
get => _ids;
set
{
if (_ids != value)
{
_ids = value;
RaisePropertyChanged("IDs");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(property));
}
}
}
}
ViewModel
namespace DataBinding_WPF.ViewModel
{
public class ExampleViewModel : INotifyPropertyChanged
{
public ObservableCollection<Example> Examples
{
get;
set;
}
// SelectedItem in the ComboBox
// SelectedItem.Ids will be ItemsSource for the ListBox
private Example _selectedItem;
public Example SelectedItem
{
get => _selectedItem;
set
{
_selectedItem = value;
RaisePropertyChanged(nameof(SelectedItem));
}
}
// SelectedId in ListView
private string _selectedId;
public string SelectedId
{
get => _selectedId;
set
{
_selectedId = value;
RaisePropertyChanged(nameof(SelectedId));
}
}
private string _selectedCheckBox;
public string IsSelected
{
get => _selectedCheckBox;
set
{
_selectedCheckBox = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(property));
}
}
public void LoadExample()
{
ObservableCollection<Example> examples = new ObservableCollection<Example>();
examples.Add(new Example { Name = "Mark", IDs = new string[] { "123", "456" }, IsSelected = false });
examples.Add(new Example { Name = "Sally", IDs = new string[] { "789", "101112" }, IsSelected = false });
Examples = examples;
}
/* BELOW IS A SNIPPET I ADDED FROM AN EXAMPLE I FOUND ONLINE BUT NOT SURE IF IT'S NEEDED */
private ObservableCollection<Example> _bindCheckBox;
public ObservableCollection<Example> BindingCheckBox
{
get => _bindCheckBox;
set
{
_bindCheckBox = value;
RaisePropertyChanged("BindingCheckBox");
}
}
}
}
View
<UserControl x:Class = "DataBinding_WPF.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:DataBinding_WPF"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">
<Grid>
<StackPanel HorizontalAlignment = "Left" >
<ComboBox HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding Path=Examples}"
SelectedItem="{Binding SelectedItem}"
DisplayMemberPath="Name"/>
<ListView x:Name="myListView"
ItemsSource="{Binding SelectedItem.IDs}"
DataContext="{Binding DataContext, ElementName=submit_btn}"
SelectedItem="{Binding SelectedId}"
Height="200" Margin="10,50,0,0"
Width="Auto"
VerticalAlignment="Top"
Background="AliceBlue">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox
Name="myCheckBox"
IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=ListViewItem}}"
Margin="5, 0"/>
<TextBlock Text="{Binding}" FontWeight="Bold" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button HorizontalAlignment="Left" Height="20" Width="100"
Click="Submit" x:Name="submit_btn">Submit</Button>
</StackPanel>
</Grid>
</UserControl>
View.cs
namespace DataBinding_WPF.Views
{
/// <summary>
/// Interaction logic for StudentView.xaml
/// </summary>
public partial class StudentView : UserControl
{
public StudentView()
{
InitializeComponent();
}
private void Submit(object sender, EventArgs e)
{
var selectedItems = ((Button)sender).DataContext;
// process each selected item
// foreach (var selected in ....) { }
}
}
}
The ListView control already exposes a selected items collection as property SelectedItems.
private void Submit(object sender, RoutedEventArgs e)
{
var selectedIds = myListView.SelectedItems.Cast<string>().ToList();
// ...do something with the items.
}
However, I doubt that you want to do this in the code-behind, but rather in the view model. For this purpose, WPF offers the concept of commands.
MVVM - Commands, RelayCommands and EventToCommand
What you need is a relay command or delegate command (the name varies across frameworks). It encapsulates a method that should be executed for e.g. a button click and a method to determine whether the command can be executed as an object that can be bound in the view. Unfortunately, WPF does not provide an implementation out-of-the-box, so you either have to copy an implementation like here or use an MVVM framework that already provides one, e.g. Microsoft MVVM Tookit.
You would expose a property Submit of type ICommand in your ExampleViewModel and initialize it in the constructor with an instance of RelayCommand<T> that delegates to a method to execute.
public class ExampleViewModel : INotifyPropertyChanged
{
public ExampleViewModel()
{
Submit = new RelayCommand<IList>(ExecuteSubmit);
}
public RelayCommand<IList> Submit { get; }
// ...other code.
private void ExecuteSubmit(IList selectedItems)
{
// ...do something with the items.
var selectedIds = selectedItems.Cast<string>().ToList();
return;
}
}
In your view, you would remove the Click event handler and bind the Submit property to the Command property of the Button. You can also bind the SelectedItems property of the ListView to the CommandParameter property, so the selected items are passed to the command on execution.
<Button HorizontalAlignment="Left"
Height="20"
Width="100"
x:Name="submit_btn"
Command="{Binding Submit}"
CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>
Additionally, a few remarks about your XAML.
Names of controls in XAML should be Pascal-Case, starting with a capital letter.
You should remove the DataContext binding from ListView completely, as it automatically receives the same data context as the Button anyway.
DataContext="{Binding DataContext, ElementName=submit_btn}"
You can save yourself from exposing and binding the SelectedItem property in your ExampleViewModel, by using Master/Detail pattern for hierarchical data.
<Grid>
<StackPanel HorizontalAlignment = "Left" >
<ComboBox HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding Path=Examples}"
IsSynchronizedWithCurrentItem="True"
DisplayMemberPath="Name"/>
<ListView ItemsSource="{Binding Examples/IDs}"
SelectedItem="{Binding SelectedId}"
Height="200" Margin="10,50,0,0"
Width="Auto"
VerticalAlignment="Top"
Background="AliceBlue">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox Name="myCheckBox"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"
Margin="5, 0"/>
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button HorizontalAlignment="Left"
Height="20"
Width="100"
Command="{Binding Submit}"
CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>
</StackPanel>
</Grid>
If the view's data context is bound to the view then remove the DataContext from the ListView.
You could remove the item template and instead use a GridView like:
<ListView.View>
<GridView >
<GridViewColumn Header="Selected" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Since the ItemSource is an Observable collection, there are several options to monitor changes in the checkboxes:
Add an event handler to the item changed event of the collection and then you can add the Name or the collection index to a local collection. e.g Examples[e.CollectionIndex].Name
Alternatively iterate over the observable collection and select those Examples where Selected = "true"

Check ckeckbox in wpf by clicking on the whole item

My client has got the problem with the size of the CheckBox inside a ListBox. I agree, it's small and not so easy to check at times.
I've tried to find a way to make a CheckBox bigger but I've found out that it's complicated (and would require using Blend, which I don't want to use).
What I want to do though is to check the CheckBox when clicking on a whole item.
[ ] some text
In this example - on "some text" or inside the item wherever. Right now I have to click inside the CheckBox to have it checked.
I generate my CheckBoxes dynamically.
My xamls of this control looks like this:
<ListBox Name="restoredDBsListBox" ItemsSource="{Binding ProperlyRestoredDatabases}" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="170" Margin="34,160,0,0" VerticalAlignment="Top" Width="276" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox Name="check" IsChecked="{Binding IsChecked, Mode=TwoWay}" Margin="3" VerticalAlignment="Center"/>
<ContentPresenter Content="{Binding Value}" Margin="1"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and my ViewModel:
/// <summary>
/// Defines the _properlyRestoredDatabases
/// </summary>
private CheckableObservableCollection<string> _properlyRestoredDatabases;
/// <summary>
/// Gets or sets the ProperlyRestoredDatabases
/// </summary>
public CheckableObservableCollection<string> ProperlyRestoredDatabases
{
get { return _properlyRestoredDatabases; }
set
{
_properlyRestoredDatabases = value;
OnPropertyChanged("ProperlyRestoredDatabases");
}
}
CheckableObservableCollection class :
public class CheckableObservableCollection<T> : ObservableCollection<CheckedWrapper<T>>
{
private ListCollectionView _selected;
public CheckableObservableCollection()
{
_selected = new ListCollectionView(this);
_selected.Filter = delegate (object checkObject) {
return ((CheckedWrapper<T>)checkObject).IsChecked;
};
}
public void Add(T item)
{
this.Add(new CheckedWrapper<T>(this) { Value = item });
}
public ICollectionView CheckedItems
{
get { return _selected; }
}
internal void Refresh()
{
_selected.Refresh();
}
}
and CheckedWrapper
public class CheckedWrapper<T> : INotifyPropertyChanged
{
private readonly CheckableObservableCollection<T> _parent;
public CheckedWrapper(CheckableObservableCollection<T> parent)
{
_parent = parent;
}
private T _value;
public T Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged("Value");
}
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
CheckChanged();
OnPropertyChanged("IsChecked");
}
}
private void CheckChanged()
{
_parent.Refresh();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler pceh = PropertyChanged;
if (pceh != null)
{
pceh(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The CheckBox has a Content property so there is no reason to use a separate ContentPresenter. If you also add an ItemContainerStyle that stretches the ListBoxItem container horizontally, you will be able to check and uncheck the CheckBox by clicking anywhere on the row:
<ListBox Name="restoredDBsListBox" ItemsSource="{Binding ProperlyRestoredDatabases}" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="170" Margin="34,160,0,0" VerticalAlignment="Top" Width="276" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="check" IsChecked="{Binding IsChecked, Mode=TwoWay}"
Content="{Binding Value}"
Margin="3"
VerticalAlignment="Center"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF XAML can not see checkboxes in ListView

I'm working on a small WPF project,
for now it contains one window which should display as much checkboxes are many values in lists are.
For testing purposes, before I get values from database I tried something like this:
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
public void GetSerialNumbers()
{
List<StatusOption> serialNumbers = new List<StatusOption>();
for(int i = 0; i<10;i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
serialNumbers.Add(x);
}
}
And my xaml looks like this:
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding GetSerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding serialNumbers}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But unfortunatelly nothing is displayed below textbox...
But for now everything is empty, and I can not find out why..
Thanks guys
Cheers
You could not bind a method. Please use property instead.
<ListBox HorizontalAlignment="Left" Height="171" Margin="334,96,0,0" VerticalAlignment="Top" Width="248" AllowDrop="True" x:Name="SerialNumbersListBox"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class SerialNumbersListBoxViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
private ObservableCollection<StatusOption> _SerialNumbers;
public ObservableCollection<StatusOption> SerialNumbers
{
get
{
return _SerialNumbers;
}
set
{
if (value != _SerialNumbers)
{
_SerialNumbers = value;
OnPropertyChanged(nameof(SerialNumbers));
}
}
}
public void GetSerialNumbers()
{
if (_SerialNumbers == null)
_SerialNumbers = new ObservableCollection<StatusOption>();
for (int i = 0; i < 10; i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
_SerialNumbers.Add(x);
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public SerialNumbersListBoxViewModel()
{
GetSerialNumbers();
}
}
You can refer this link for more details
Regard!
You cannot bind to methods, you can only bind to Properties or DependencyProperties.
So you need to create a Property for your serialNumbers. You should also implement INotifyPropertyChanged, so that the ListBox can know when your property changed.
public List<object> SerialNumbers
{
get => this._serialNumbersProperty;
set
{
if (!List<object>.Equals(value, this._serialNumbersProperty))
{
this._serialNumbersProperty = value;
OnPropertyChanged(nameof(this.SerialNumbers));
}
}
}
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Checkboxes in listbox not getting checked via binding

I'm trying to check all the checkboxes through a binding..
The getChecked property does get changed to true after clicking the button but the checkboxes are just not getting checked. Does someone see what I'm doing wrong here? This is the XAML code for the listbox.
<ListBox Name="scroll" ItemContainerStyle ="{StaticResource _ListBoxItemStyle}" Tag="{Binding SortingIndex}" BorderBrush="#C62828" BorderThickness="1" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Name="checkboxStack">
<CheckBox IsChecked="{Binding Path=getChecked}" Content="{Binding Path=vraag}" Style="{StaticResource LifesaversCheckBoxesA}"/>
<StackPanel Margin="20,0,0,0">
<RadioButton GroupName="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=Tag}" Content="{Binding Path=antwoorden[0]}" FontSize="15" />
<RadioButton GroupName="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=Tag}" Content="{Binding Path=antwoorden[1]}" FontSize="15" />
<RadioButton GroupName="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=Tag}" Content="{Binding Path=antwoorden[2]}" FontSize="15" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is the event handler for the button I made to change the getChecked boolean to true for each vraag in vragenLijst. The sample data is just to generate some random strings.
public partial class LivesaversWindow : UserControl
{
ObservableCollection<Vraag> vragenLijst;
public LivesaversWindow()
{
InitializeComponent();
vragenLijst = new VragenList(SampleData.vragen());
scroll.ItemsSource = vragenLijst;
}
private void alles_Selecteren(object sender, RoutedEventArgs e)
{
if ((string)select.Content == "Alles selecteren")
{
foreach(Vraag vraag in vragenLijst)
{
vraag.getChecked = true;
}
select.Content = "Alles deselecteren";
}
else
{
foreach (Vraag vraag in vragenLijst)
{
vraag.getChecked = false;
}
select.Content = "Alles selecteren";
}
}
And these are the 2 classes I'm using.
public class Vraag
{
public List<string> antwoorden { get; set; }
public string vraag { get; set; }
public Boolean getChecked { get; set; }
}
public class VragenList : ObservableCollection<Vraag>
{
public VragenList(List<Vraag> vragen) :base()
{
foreach (var vraag in vragen)
{
Add(vraag);
}
}
}
Your class Vraag is not implementing the INotifyPropertyChanged Interface. Therefore the UI is not registering any changes that are made to your objects displaying in the view:
So bascially what you need to do is implementing the INotifyPropertyChanged-Interface kind of like this:
public class Vraag : INotifyPropertyChanged
{
public List<string> antwoorden { get; set; }
public string vraag { get; set; }
private bool isChecked;
public bool getChecked
{
get { return isChecked; }
set
{
isChecked = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
Hope this helps!
Your class Vraag must implement INotifyPropertyChanged interface

Categories

Resources