WPF DataGrid ComboBox SelectedItem Property Setter - c#

I am looking for an example of how to use the SelectedItem property inside a combobox in a WPF DataGrid, I have
<DataGridComboBoxColumn SelectedValueBinding="{Binding CID, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedValuePath="CID"
Header="CID"
Width="70">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.ListCustomerCollection,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
<Setter Property="SelectedItem" Value="{Binding DataContext.Customer, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"></Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.ListCustomerCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="SelectedItem" Value="{Binding DataContext.Customer, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"></Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle>
The DataContext I bind to (ListCustomerCollection) is a List object
List<Customer>
so the property in the ViewModel property I have set is
private Customer m_Customer = null;
public Customer Customer
{
get { return m_Customer; }
set
{
m_Customer = value;
OnPropertyChanged("Customer");
}
}
So how do I writethe XAML to set the above property with the SelectedItem?

If property resides in window's ViewModel, you have to get window's DataContext like you did for ItemsSource.
<Setter Property="SelectedItem"
Value="{Binding DataContext.Customer,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>

Related

Issue with binding WPF DataGrid Combobox columns using ObservableCollection

Getting issue when binding WPF Combobox columns using the following Model:
public class Game
{
public string Name;
ObservableCollection<Player> Players{get; set;}
}
public class Player
{
public int ID;
public string PlayerName;
public List<string> AllSelectionStatus = new List<string> {"Yes", "No", "Waiting"};
public string PlayerSelectionStatus;
}
public class PlayerModel
{
ObservableCollection<Game> Games {get; set;}
}
I need to display the above structure as shown below in a WPF DataGrid.
Each combobox 'ItemSource' Property Value is set with AllSelectionStatus and 'SelectedItem' Property Value is set wth PlayerSelectionStatus.
Here is my XAML code.
<DataGrid Name="dgRowDetails" Background="Transparent" Foreground="Black" SelectionMode="Single" HeadersVisibility="Column"
ItemsSource="{Binding Games[0].Players}">
<DataGrid.Resources>
<Style x:Key="DataGridComboBoxColumnStyle0" BasedOn="{StaticResource BaseComboBoxBoxStyle}" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding AllSelectionStatus, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="SelectedItem" Value="{Binding PlayerSelectionStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSystemEnabled}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="DataGridComboBoxColumnStyle1" BasedOn="{StaticResource BaseComboBoxBoxStyle}" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding AllSelectionStatus, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="SelectedItem" Value="{Binding PlayerSelectionStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSystemEnabled}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
<!-- The 3rd Combobox style not shown as it is similar to the one above-->
</Style>
The issue with this XAML is, the Game2 & Game3 comboboxes are not having their own PlayerSelectionStatus. Both Game2 & Game3 are getting Game1 PlayerSelectionStatus.
Need help to resolve this. Appreciate your help.
Just set IsSynchronizedWithCurrentItem to false inside your ComboBox styles.
<Setter Property="IsSynchronizedWithCurrentItem" Value="False"/>
For your example it should be:
<DataGrid Name="dgRowDetails" Background="Transparent" Foreground="Black" SelectionMode="Single" HeadersVisibility="Column"
ItemsSource="{Binding Games[0].Players}">
<DataGrid.Resources>
<Style x:Key="DataGridComboBoxColumnStyle0" BasedOn="{StaticResource BaseComboBoxBoxStyle}" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding AllSelectionStatus, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="SelectedItem" Value="{Binding PlayerSelectionStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="IsSynchronizedWithCurrentItem" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSystemEnabled}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="DataGridComboBoxColumnStyle1" BasedOn="{StaticResource BaseComboBoxBoxStyle}" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding AllSelectionStatus, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="SelectedItem" Value="{Binding PlayerSelectionStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="IsSynchronizedWithCurrentItem" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSystemEnabled}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
<!-- The 3rd Combobox style not shown as it is similar to the one above-->
</Style>
The ItemSource of your datagrid is only the first Game,
ItemsSource="{Binding Games[0].Players}
and each game object only has one PlayerSelectionStatus, which is bound to all three comboboxes. Nothing is bound to Games[1] or Games[2], or the complete PlayerModel Games list.
I think you need to rethink your datastructure, so that each player has a list of games (or three Game properties), each with it's own status.

Tooltip for Textbox with maxlength property

I want to make a tooltip for my TextBoxes in XAML, and i want do do this with styling in Xaml.
The Tooltip should display something like Enter up to x characters, with x equal to the MaxLength property of the textbox. I only want to display the tooltip if the MaxLength is set.
What i have now is something like:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}, StringFormat='Enter up to {0} characters'}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
The condition is working, so if there is a MaxLength set the tooltip is displayed. Only the binding inside the tooltip is not working.
Other stuff that i've tried is:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}}" ContentStringFormat="{}Enter up to {0} characters"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
This gives the same problem as the option shown above, but i cant style the tooltip properly.
Another thing i've tried is:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, StringFormat='Enter up to {0} characters'}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But this way the string formatting won't work.
Something i've tried before and that has worked was:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding MaxLength ,StringFormat='Enter up to {0} characters'}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But this way the DataContext for the TextBox, and my other bindings dont work anymore.
Does anyone have a solution that (favorably) only includes XAML?
EDIT
While using a converter for MaxLength to the text Enter up to MaxLength characters it worked.
I used:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True">
<Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource textBoxToolTipConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
MultiDataTrigger, as name implies, is meant to be used with many conditions. You actually never used more than one. You can leverage of couple options:
Create style for textBox and within set default ToolTip to "Enter up to.." and in style trigger check whether MaxLength equals either null or 0, if so set ToolTip empty.
Bind ToolTip property to MaxLength and in converter assign value based on whether MaxLength is set
EDIT
<TextBox Text="Text" MaxLength="55">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength,StringFormat='Enter up to {0} characters'}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength}" Value="0">
<Setter Property="ToolTip" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
This will display maxLength since ToolTip needs to have StringFormat set in diffrent way. I refer you to this post. All in all you end up being forced to create converter.
You can try this for the first code example.
Update added full style code for clarification.
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding DataContext.MaxLength, RelativeSource={RelativeSource Mode=Self}, StringFormat=Enter up to {0} characters}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>

DataGridComboBoxColumn binding

I have seen a few posts on here with people getting confused on how to bind to a DataGridComboBoxColumn,
I have
<DataGridComboBoxColumn SelectedItemBinding="{Binding Collection}" DisplayMemberPath="Name" Header="Name" Width="70">
which didnt work..
So I used
<DataGridComboBoxColumn ItemBinding="{Binding Collection}" DisplayMemberPath="Name"> Header="Name" Width="70">
Which again didn't work, why is binding to a datagridcombo different to a original combo box.
<ComboBox ItemsSource="{Binding Collection}" DisplayMemberPath="Name" HorizontalAlignment="Left">
which does work
What is the correct method of binding to a combo box inside a DataGrid?
---Edit---
I might have found the problem, I have a DataGrid binding to a ItemSource, however, I want the ComboBoxColumn to be bounded to a different Itemsource, is this possible?
Cheers
You need to bind to ItemsSource property. Set it in EditingElementStyle.
<DataGridComboBoxColumn>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Collection}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
In case you want ItemsSource to bind to collection which is outside of DataGrid underlying source object, you can do that as well.
Say you have collection AnotherCollection residing in ViewModel of Window/UserControl, you can bind with it using RelativeSource markup extension.
Also, you have to set SelectedItemBinding to the property where you want to set the value selected from ComboBox and declare same style under ElementStyle of DataGridComboBoxColumn.
Suppose property name is Name to which you want to bind.
<DataGridComboBoxColumn SelectedItemBinding="{Binding Name}">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource"
Value="{Binding DataContext.AnotherCollection,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource"
Value="{Binding DataContext.AnotherCollection,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>

How to bind with a relative source that is Ancestor and Self?

I have the following code:
<ItemsControl ItemsSource="{Binding MyDictionary}" >
<Image Width="16">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="False">
<Setter Property="Source" Value="{Binding RelativeSource =
{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}},
Path=DataContext.SecDic}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Value}" Value="True">
<Setter Property="Source" Value="{Binding RelativeSource =
{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}},
Path=DataContext.ThirdDic}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ItemsControl>
MyDictionary - Is a dictionary that the key is of type enum
Now This binding works if I change the SecDic and ThirdDic from dictionaries to BitmapImages. But I want that for each key (enum) in MyDictionary there will be a different True/False image.
So I tried to write:
<Setter Property="Source" Value="{Binding Path=DataContext.SecDic[Key],
RelativeSource={AncestorType={x:ItemsControl}}}"/>
But it doesn't work since the "Key" belongs to the data context of the image (of MyDictionary) and I changed the relative source to be the items control so there is no "Key".
Any suggestions?
What I did to solve this is a multibinding + a custom multibinding converter.
There was one binding for the dictionary and one for the key.

Checkbox Command Not Firing When Initially Unchecked

I have a column of checkboxes in a datagrid.
<DataGridTemplateColumn CanUserResize="False" Header="" Width="auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Style="{StaticResource CheckBoxSelectTypeStyle}" IsChecked="{Binding Path=Selected}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I have a command bound to unchecking and checking.
<Style x:Key="CheckBoxSelectTypeStyle" TargetType="{x:Type CheckBox}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Command" Value="{Binding DataContext.CheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Command" Value="{Binding DataContext.UncheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
</Trigger>
</Style.Triggers>
</Style>
My problem is that if the checkboxes start as unchecked and you check one, then no commands are fired (This is the problem). If you then uncheck the same checkbox, the uncheck command will fire (As expected). If you then check the same checkbox again, the check command will fire (As expected). Everything will work fine for that checkbox at that point, but the others still have the same problem.
If a checkbox starts as checked it will work fine. My question is how do I make the command fire when the checkbox starts as unchecked. I can't find any reason for it not to work.
Response to suggestion:
I tried to add a trigger for Null, but it has the exact same problem, nothing changed.
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Command" Value="{Binding DataContext.CheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Command" Value="{Binding DataContext.UncheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Command" Value="{Binding DataContext.UncheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
</Trigger>
</Style.Triggers>
ViewModel Code
public ICommand CheckedCommand { get; set; }
public ICommand UncheckedCommand { get; set; }
CheckedCommand = new RelayCommand<IList>(Checked);
UncheckedCommand = new RelayCommand<IList>(Unchecked);
private void Checked(IList selectedItems)
{
ChangedChecked(selectedItems, true);
}
private void Unchecked(IList selectedItems)
{
ChangedChecked(selectedItems, false);
}
private void ChangedChecked(IList selectedItems, bool selected)
{
if (selectedItems.HasValue())
foreach (var item in selectedItems)
if(item is SelectedTypeModel) (item as SelectedTypeModel).Selected = selected;
}
RelayCommand implements ICommand. As I mentioned before, the Checked method is not called when the checkbox starts as unchecked, but it is called when it is checked, unchecked, and checked again or if it starts checked and is unchecked.
What I'm Trying To Do
I have a DataGrid with a column of CheckBoxs. I want to be able to highlight multiple rows, then check/uncheck a CheckBox in one of the selected rows and have all the other rows update to be the same. I also have a keyword filter for the datagrid, so the DataGrid is binding to a ListCollectionView.
Output Information
I enabled debug information for data binding and get this message:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Selected; DataItem=null; target element is 'CheckBox' (Name=''); target property is 'IsChecked' (type 'Nullable`1')
I'm still not sure how to use this information to correct the problem though.
SOLUTION
I did not fix my original problem and I still don't know why it doesn't work correctly, but I have used another method with the same desired result. Here is the changed code:
<Style x:Key="CheckBoxSelectTypeStyle" TargetType="{x:Type CheckBox}">
<Setter Property="Command" Value="{Binding DataContext.CheckedChangedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource SelectedItemsCheckedMultiValueConverter}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}" Path="SelectedItems"/>
<Binding RelativeSource="{RelativeSource Self}" Path="IsChecked"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
public ICommand CheckedChangedCommand { get; set; }
CheckedChangedCommand = new RelayCommand<Tuple<IList, bool>>(CheckedChanged);
Solution
I think you can achieve your goals without any need in triggers (I've tested this solution in small sample app):
so your style would looks like this:
<Style x:Key="CheckBoxSelectTypeStyle" TargetType="{x:Type CheckBox}">
<Setter Property="Command" Value="{Binding DataContext.CheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<Setter Property="CommandParameter" Value="{Binding Path=SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
...
There will be only one command in your view model. And as parameter that command will receive list of selected items. So only one thing is missing - whether user is about to check or uncheck checkbox. At the moment I can think of one possible way of passing this info along with SelectedItems - write MultiBinding with custom converter which will put selectedItems and current value of IsChecked in something like Tuple<..., bool>
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding Converter="{x:Static PackTupleConverter.Instance}">
<Binding RelativeSource="{RelativeSource AncestorType=DataGrid}" Path="SelectedItems"/>
<Binding RelativeSource="{x:Static RelativeSource.Self}" Path="IsChecked"/>
</MultiBinding>
</Setter.Value>
</Setter>
end
I was able to repro your problem by simply putting same checkbox inside ListBox. Once that done first time I click on checkbox - command don't get called
here is sample window xaml:
<Window.Resources>
<Style x:Key="CheckBoxSelectTypeStyle" TargetType="{x:Type CheckBox}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Command" Value="{Binding DataContext.Test, RelativeSource={RelativeSource AncestorType=Window}}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Command" Value="{Binding DataContext.Test, RelativeSource={RelativeSource AncestorType=Window}}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ListBox>
<ListBox.Items>
<CheckBox Style="{StaticResource CheckBoxSelectTypeStyle}" />
</ListBox.Items>
</ListBox>
</Grid>
and sode behaind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Test = new DelegateCommand(TestCommand);
}
public ICommand Test { get; set; }
private void TestCommand()
{
}
}
Here is what I've discovered in output regarding binding:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=DataContext.Test; DataItem=null; target element is 'CheckBox' (Name=''); target property is 'Command' (type 'ICommand')

Categories