I have a listbox with a datatemplate that contains a checkbox and textblock. How do I get the multiselection working with the checkbox in the template so that selection is based on the isChecked property of the checkbox? The need I have is to have a dropdown with checkboxes that could cater for multiselection. This is what I have sofar. Please feel free to give suggestions on where I could better this code as this is the whole point.
XAML:
<DataTemplate x:Key="WorkCentreItem">
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding WorkCentre}" IsChecked="{Binding IsChecked}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
<telerik:RadListBox
SelectionMode="Multiple"
Grid.Row="2"
Grid.ColumnSpan="2"
Grid.RowSpan="1"
Margin="-1,20,0,3"
ItemsSource="{Binding SampleWorkCentres}"
ItemTemplate="{StaticResource WorkCentreItem}"
ScrollViewer.CanContentScroll="True"
SelectionChanged="RadListBox_SelectionChanged">
</telerik:RadListBox>
Model:
#region SampleWorkCentres
public const string SampleWorkCentresPropertyName = "SampleWorkCentres";
private ObservableCollection<BomWorkCentre> _sampleWorkCentres;
public ObservableCollection<BomWorkCentre> SampleWorkCentres
{
get
{
if (this._sampleWorkCentres == null)
{
using (SysproKitIssueEntities db = new SysproKitIssueEntities())
{
this._sampleWorkCentres = new ObservableCollection<BomWorkCentre>(db.BomWorkCentres.Select(x => x).Distinct().ToList());
}
}
return this._sampleWorkCentres;
}
set
{
if (this._sampleWorkCentres == value)
{
return;
}
this._sampleWorkCentres = value;
this.RaisePropertyChanged(SampleWorkCentresPropertyName);
}
}
#endregion
#region SelectedWorkCentres
public const string SelectedWorkCentresPropertyName = "SelectedWorkCentres";
private ObservableCollection<BomWorkCentre> _selectedWorkCentres = new ObservableCollection<BomWorkCentre>();
public ObservableCollection<BomWorkCentre> SelectedWorkCentres
{
get
{
return this._selectedWorkCentres;
}
set
{
if (this._selectedWorkCentres != value)
{
this._selectedWorkCentres = value;
}
this._sampleGridItems = null;
this.RaisePropertyChanged(SampleGridItemsPropertyName);
this.RaisePropertyChanged(SelectedWorkCentresPropertyName);
}
}
#endregion
You should data bind the Checkbox.IsChecked to the ListBoxItem.IsSelected Property using a RelativeSource Binding:
<CheckBox Content="{Binding WorkCentre}" IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" />
Related
I have a list bound as ItemSource that contains two strings: Option 1 and option 2, I have 2 text boxes where I bind and display these two options. I also have two radio buttons next to the two textboxes. I want to bind these radiobuttons but every time I click on them nothing happens. I found out the reason for this, because now he is always trying to find the bool in my list whether the button is checked or not. Is there a way to set in the xaml code that I can access the bool property which is in my ViewModel?
ViewModel:
public class WortAuswahlViewModel : AntwortMoeglichkeitViewModel, IWortAuswahlViewModel
{
public ObservableCollection<AuswahlOptionen> m_auswahlOptionen;
public WortAuswahlViewModel(WortAuswahl wortAuswahl)
{
if (wortAuswahl?.Optionen == null)
{
return;
}
m_auswahlOptionen = new ObservableCollection<AuswahlOptionen>(wortAuswahl.Optionen);
}
public ObservableCollection<AuswahlOptionen> WortAuswahlOptionen
{
get
{
return m_auswahlOptionen;
}
set
{
if (m_auswahlOptionen != value)
{
m_auswahlOptionen = value;
OnPropertyChanged();
}
}
}
private bool m_isRadioButtonCheckedFirst;
public bool CheckButtonEins
{
get
{
return m_isRadioButtonCheckedFirst;
}
set
{
if (m_isRadioButtonCheckedFirst != value)
{
m_isRadioButtonCheckedFirst = value;
OnPropertyChanged();
}
}
}
private bool m_isRadioButtonCheckedSecond;
public bool CheckButtonZwei
{
get
{
return m_isRadioButtonCheckedSecond;
}
set
{
if (m_isRadioButtonCheckedSecond != value)
{
m_isRadioButtonCheckedSecond = value;
OnPropertyChanged();
}
}
}
}
}
XAML:
<Grid>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="20">
<ItemsControl ItemsSource="{Binding WortAuswahlOptionen}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Height="80" HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel>
<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" IsChecked="{Binding CheckButtonEins}"/>
<DockPanel LastChildFill="True">
<TextBox Grid.Column="1" Margin="20, 0, 0, 0" x:Name="TXT_optionEinsLoesung" Text="{Binding OptionEins}" IsReadOnly="True"/>
</DockPanel>
<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" IsChecked ="{Binding CheckeButtonZwei}"/>
<DockPanel LastChildFill="True">
<TextBox Grid.Column="1" Margin="20, 0, 0, 0" x:Name="TXT_optionZweiLoesung" Text="{Binding OptionZwei}" IsReadOnly="True"/>
</DockPanel>
</StackPanel>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
DataContext of each ItemTemplate and ItemContainerStyle inside ItemsControl is automatically set to the corresponding element of the ItemsSource.
One way to redirect the DataContext to somewhere outside of the elements is to start the binding path from the DataContext of the root object of your Window.
So if your WortAuswahlViewModel is set to the DataContext of a Window, first you need to set the binding source to the Window using RelativeSource={RelativeSource AncestorType=Window} and then set path to Path=DataContext.CheckButtonEins
IsChecked="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.CheckButtonEins}"
If your WortAuswahlViewModel is set to the DataContext of another UI element, replace Window with the type of that element.
I've got a question, I have a list of checkbox in combobox box and it looks like this:
<StackPanel Orientation="Vertical" DataContext="{Binding CandidateEntity}">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding DataContext.SkillSetEntities, ElementName=CrudCandidate }"
IsEditable="True" IsReadOnly="True" Text="Umiejętności">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</StackPanel>
Now I also have a collection of skillset objects in binded item source (CandidateEntity.SkillSets), now how can I check those checkboxes that are in my collection of skillset objects?
I want to create a edition for CandidateEntity object in form and part of that edition is list of skillset that is represented in combobox.
EDIT:
I have solved problem by adding to skillset model prop:
private bool _isSelected = false;
[NotMapped]
public bool IsSelected
{
get
{
return this._isSelected;
}
set
{
_isSelected = value;
}
}
And then in view model:
private List<SkillSet> GetSkillSets()
{
var skillsetList = this._catalog.SkillSets.ToList();
var candidateSkillsetList = this.CandidateEntity.SkillSets.ToList();
foreach (SkillSet skillset in skillsetList)
{
foreach (SkillSet candidateSkillset in candidateSkillsetList)
{
if (skillset.id == candidateSkillset.id)
{
skillset.IsSelected = true;
}
}
}
return skillsetList;
}
and in checkbox in wpf:
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}"/>
BUT I am pretty sure there must be easier way to handle that, is there?
I have a listbox defined in a WPF window as follows:
<ListBox ItemsSource="{Binding Values}" SelectedItem="{Binding SelectedValue}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black" Margin="5">
<StackPanel Margin="5">
<TextBlock FontWeight="Bold" Text="{Binding}"/>
<StackPanel Orientation="Horizontal">
<Label>Is Selected: </Label>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Selected Item:</Label>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=SelectedItem}"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And on the view model:
private string selectedValue;
private ObservableCollection<string> values;
public MainWindowViewModel()
{
this.values = new ObservableCollection<string>(new[] { "Fish", "Chips", "Peas" });
}
public ObservableCollection<string> Values
{
get
{
return this.values;
}
}
public string SelectedValue
{
get { return this.selectedValue; }
set
{
this.selectedValue = value;
if (value == "Peas")
{
this.SelectedValue = null;
}
this.OnPropertyChanged();
}
}
Each entry in the listbox displays its text and also a pair of textblocks indicating whether the listboxitem's IsSelected is set, and also what the current SelectedItem of the listbox is.
Everything works fine, until the "Peas" option is selected.
The view model has a piece of code which sets the viewmodel's SelectedValue to null in that instance, which in turn sets the listbox's SelectedItem property to null (overriding the fact that the user just clicked "Peas").
However, the ListBoxItem's IsSelected property for "Peas" does not get set to false even though the ListBox now has no selected item.
Any suggestions how to force the ListBoxItem to have IsSelected=false as well?
OK, I have found a workaround which seems to do the job. I have replaced the block
if (value == "Peas")
{
this.SelectedValue = null;
}
with
if (value == "Peas")
{
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => this.SelectedValue = null));
}
essentially deferring the setting of the SelectedValue to null until after the block of code handling the user click has completed, and thus ensuring they don't interfere with each other.
I'll mark this as the accepted answer if nobody else has a more "elegant" solution to this!
Am Using the checkbox in listbox items, how to get the selected checkboxes from the list
<ListBox ItemsSource="{Binding NameList}" HorizontalAlignment="Left" Margin="16,68,0,12" Name="listBox1" Width="156" IsEnabled="True" SelectionMode="Multiple" Focusable="True" IsHitTestVisible="True" IsTextSearchEnabled="False" FontSize="12" Padding="5" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Path=CNames}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried to loop thru the selected items in the listboxitems, but it throws exception in listboxitem
private void btnSelected(object sender, RoutedEventArgs e)
{
foreach (ListBoxItem item in listBox1.Items)
{
if (item.ToString() == "true")
{
MessageBox.Show(item.Content.ToString());
}
}
}
You could move the data context for each of these items away from the UI and create an ObservableCollection of objects
public ObservableCollection<CheckedItem> List { get;set;}
public class CheckedItem : INotifyPropertyChanged
{
private bool selected;
private string description;
public bool Selected
{
get { return selected; }
set
{
selected = value;
OnPropertyChanged("Selected");
}
}
public string Description
{
get { return description; }
set
{
description = value;
OnPropertyChanged("Description");
}
}
/* INotifyPropertyChanged implementation */
}
Then in your ListBox ItemTemplate
<ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Selected}"
Content={Binding Path=Description}" />
</DataTemplate>
</ItemTemplate>
Your selected items are now available in the ObservableCollection rather than looping through UI elements
Have your template like this
<ListBox.ItemTemplate>
<DataTemplate>
........
<CheckBox Content=""
IsChecked="{Binding IsSelected, Mode=TwoWay,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListViewItem}}}" />
..........
<!-- Use Other UIElements to Show your Data -->
then the above binding will sync two way with your models isSelected and list view selection, then in code use SelectedItems.
For Each s As myPoco In myListView1.SelectedItems
' do something here with
Next
I would suggest this code:
private void save_Click(object sender, RoutedEventArgs e)
{
foreach (CheckBox item in list1.Items)
{
if (item.IsChecked)
{
MessageBox.Show(item.Content.ToString());
}
}
}
Sorry for the vague description, I can't think of a better way to put it.
Let's say that my ViewModel has a property as follows:
public List<MyClass> SubSystems { get; set; }
and the SubSystems class:
public class SubSystem
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
In the view, I'd like to bind the SubSystems property to, what I think would be, a list of checkboxes where the IsChecked and Name properties of the CheckBox is bound to the their respective properties, IsChecked for IsSelected and Content for Name.
I know I can make a ListBox in the XAML, but I'm not sure how I'd go about doing this using binding and a collection..
Thanks for the help!
Edit -
Here's the XAML:
<GroupBox Header="Sub-Systems" Grid.Column="0" Grid.Row="0" Margin="5">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="checkBox">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding SubSystems}" />
</Grid>
</GroupBox>
Edit #2 -
Just to clarify, all of the examples populate the box, but none of the examples are breaking on the breakpoints in the setters.
I think that instead of a ListBox, you probably want an ItemsControl. ListBoxes assume that you want to select one of the SubSystem but really, you just want to arrange the items with data templates:
<ItemsControl ItemsSource="{Binding SubSystems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Checkbox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Name}" />
</DataTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>
How about this:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked={Binding IsSelected, Mode=TwoWay} /><TextBlock Text={Binding Name} />
</StackPanel>
</DataTemplate>
Do you mean something like this?
SubSystem class
public class SubSystem : INotifyPropertyChanged
{
private string mName;
private Boolean mIsSelected = false;
public SubSystem()
{
}
public SubSystem(string name, Boolean isSelected)
{
this.Name = name;
this.IsSelected = isSelected;
}
public string Name
{
get { return mName; }
set
{
if (mName != value)
{
mName = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public Boolean IsSelected
{
get { return mIsSelected; }
set
{
if (mIsSelected != value)
{
mIsSelected = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
ViewModel
ObservableCollection<SubSystem> mSubSystems = new ObservableCollection<SubSystem>();
public ObservableCollection<SubSystem> SubSystems
{
get { return mSubSystems; }
set { mSubSystems = value; }
}
View
<ListBox x:Name="lstSubsystems" ItemsSource="{Binding SubSystems}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}">
<ContentPresenter Content="{Binding Name}" />
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Hope that helps,
Wts
Modify the ListBox.ItemTemplate to use a checkbox, and bind the CheckBox.IsChecked to SubSystem.IsSelected and CheckBox.Content to SubSystem.Name:
XAML:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" Margin="5" Focusable="False" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C#:
private void window1_Loaded(object sender, RoutedEventArgs e)
{
this.SubSystems = new List<SubSystem>();
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 1", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 2", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 3", IsSelected = true });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 4", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 5", IsSelected = true });
this.DataContext = this.SubSystems;
}
And make sure you set Focusable="False" to the CheckBoxes or else your users will be able to tab into them.
EDIT:
Also from what you added you might be missing the ElementName property (if SubSystems is NOT the DataContext of your window, you need to specify where the SubSystems property is coming from with the ElementName binding property):
<ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding ElementName=window1, Path=SubSystems}" />