I'm building an application with WPF in MVVM style. I'm trying to make filter on my DataGrid when I check or uncheck several CheckBoxes for filtering.
I've found solution with Interaction.Triggers, but it's not working for me in this case.
Here is my code:
<ListBox
ItemsSource="{Binding PortsFilterSource}"
Background="LightGray"
BorderThickness="0"
Grid.Column="1">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox
Content="{Binding Name}"
IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding FilterCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding FilterCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Everything is working great except FilterCommand. I have this in my C# code:
public DelegateCommand<object> FilterCommand { get; set; }
...
FilterCommand = new DelegateCommand<object>(Filter);
Filter(object obj) is a function, but it is not entered when I check or uncheck any of my CheckBoxes.
Any help would be very appreciated.
The problem is, that the data context of the list item is of type FilterModel, but the FilterCommand is in the parent view model.
Try the following binding for the command:
{Binding DataContext.FilterCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}
this is work for me.
<DataGridTemplateColumn Header="IsApved" IsReadOnly="False" CanUserSort="False" Width="55">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<CheckBox
Content="{Binding Name}"
IsChecked="{Binding IsSelect,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding DataContext.CheckCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.CheckCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Related
This question already has answers here:
How to stretch checkbox item the full width of the combobox
(3 answers)
Closed 4 years ago.
I have checkboxes inside of a Combobox and I want to click them:
If I click the Checkbox or the "Content" of the Checkbox it will check the Checkbox, but if I click on empty space right next to the "content", it will just select this Checkbox in the Combobox.
How can I prevent that? I want to check the box if I click on the whole field, not just on the text alone.
Here is my Code:
<ComboBox Margin="2,2,2,0" ItemsSource="{Binding DataContext.AllTags, ElementName=self}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_UpdateTags, ElementName=self}" CommandParameter="{Binding}" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_UpdateTags, ElementName=self}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DropDownOpened">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_ClearTags, ElementName=self}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
Add an ItemContainerStyle that sets the HorizontalContentAlignment property of the ComboBoxItem containers to Stretch:
<ComboBox Margin="2,2,2,0" ItemsSource="{Binding DataContext.AllTags, ElementName=self}" >
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ComboBox.ItemContainerStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="Name">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_UpdateTags, ElementName=self}" CommandParameter="{Binding}" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_UpdateTags, ElementName=self}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DropDownOpened">
<i:InvokeCommandAction Command="{Binding DataContext.CmdCmx_ClearTags, ElementName=self}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
//I am having a Nested datagrid
and i need to fire the event when inner grid row selection changes.
<DataGrid ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
HeadersVisibility="Row"
Height="{Binding ElementName=itemsgrid,Path=ActualHeight}"
Grid.Row="1"
RowDetailsVisibilityMode="Visible"
CanUserAddRows="false"
VerticalAlignment="Top"
AutoGenerateColumns="False"
SelectedItem="{Binding SelectedBasketItem}"
ItemsSource="{Binding SelectedOrderBasketItems}"
CanUserDeleteRows="True">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
CanUserAddRows="false"
HeadersVisibility="Row"
AutoGenerateColumns="False"
ItemsSource="{Binding SelectedBasketItems}"
SelectedValue="{Binding SelectedBasketItemValue}"
SelectedIndex="{Binding SelectedOrderItemIndex}"
SelectedItem="{Binding SelectedSpecificItemInBasket, Mode=TwoWay}"
DataGrid.SelectionMode="Single"
Style="{StaticResource GridItemsControlStyle}"
ctrls:DragDrop.DropHandler="{Binding DropHandler}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.DgSelectionChangedCommand,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True"
Binding="{Binding Path=ItemName}"
Width="195">
</DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=RulesCount}"
Background="{Binding Path=RulesCount ,Converter={StaticResource ItemColourConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="115">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=LinkedOrderCount}"
Background="{Binding Path=LinkedOrderCount ,Converter={StaticResource ItemColourConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="55">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=SDICount}">
<Label.Background>
<MultiBinding Converter="{StaticResource SdiItemColourConverter}">
<Binding ElementName="SDIMaxCnt"
Path="Value" />
<Binding Path="SDICount" />
</MultiBinding>
</Label.Background>
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
//My Delegate Command initialization in ViewModel
protected override void InitializeCommands()
{
DgSelectionChangedCommand= new DelegateCommand<object>(DGSelectionChanged);
}
//My Method in the view model to be called when selection changed event is fired
void DGSelectionChanged(object obj)
{
//Logic
}
The event gets fired when i use the same event in code behind . i am trying to use interaction trigger to achieve the same in mvvm way .Not sure what i am missing .Any help is greatly appreciated.
Set the AncestorLevel of the RelativeSource to 2:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.DgSelectionChangedCommand,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}, AncestorLevel=2}}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Autopostback is the mechanism, by which the page will be posted back to the server automatically based on some events in the web controls. In some of the web controls, the property called auto post back.
which if set to true, will send the request to the server when an event happens in the control.
AutoPostBack=True;
please go through the link for more:
Difference between AutoPostBack=True and AutoPostBack=False?
I have the following ItemsControl which handles the display of items added to it:
<ControlTemplate x:Key="MyItemsControlTemplate">
<ItemsControl x:Name="MyItemsControl" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mynameSpace:MyClass}}, Path=ItemsSource}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<WrapPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:MyCustomClass}">
<Button Command="{Binding}">
<TextBlock Text="{Binding Path=DisplayValue}"/>
</Button>
</HierarchicalDataTemplate>
</WrapPanel.Resources>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ControlTemplate>
You can see that the Button has a Command="{Binding}" which handles the click event and calls a command.
Now I want to also use a ListView to display the same items and handle the click event. I see from this link WPF: How to bind a command to the ListBoxItem using MVVM? that I have to use Interaction.Triggers so I have did the following:
<ControlTemplate x:Key="MyListViewControlTemplate">
<ListView Name="MyListView" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mynameSpace:MyClass}}, Path=ItemsSource}">
<ListView.View>
<GridView >
<GridViewColumn Header="Details" DisplayMemberBinding="{Binding Path=DisplayValue}"/>
</GridView>
</ListView.View>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
</ControlTemplate>
The items display properly in the ListView so I know the binding is correct for the text display but I find that the click handler for the ListView does not fire the command like the Button object does.
Any ideas?
How
You should apply the interaction trigger to an element within the ListView. You could use a CellTemplate with a TextBlock that you apply the interaction trigger to:
<ControlTemplate x:Key="MyListViewControlTemplate">
<ListView Name="MyListView" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mynameSpace:MyClass}}, Path=ItemsSource}">
<ListView.View>
<GridView >
<GridViewColumn Header="Details">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayValue}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</ControlTemplate>
I am trying to get selected value from list into the command. Is there simple way to bind commandparameter to selected item?
<ComboBox HorizontalAlignment="Left" Margin="-56,10,0,0" VerticalAlignment="Top" Width="120" SelectedIndex="0" ItemsSource="{Binding Time}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding TestCommand}" CommandParameter="{Binding }"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding TestCommand}" CommandParameter="{Binding }"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
When i tried something like
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding TestCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}},Path=SelectionBoxItem}"></i:InvokeCommandAction>
</i:EventTrigger>
it's strange stuck why?
<ComboBox x:Name="Combo" HorizontalAlignment="Left" Margin="-56,10,0,0" VerticalAlignment="Top" Width="120" SelectedIndex="0" ItemsSource="{Binding Time}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding TestCommand}" CommandParameter="{Binding ElementName=Combo, Path=SelectedItem}"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding TestCommand}" CommandParameter="{Binding }"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
if you give your combo box a name you can use the ElementName binding and bind to the Path SelectedItem
I am having an Wpf application it has a Combobox.
which contains a checkbox and Textblock when i click on the checkbox
it shows the selected country string in the combobox but if i click on text it shows me a error string as shown in image.
I want to show the country name even if the user clicks on the textblock.
My xaml looks like this
<ComboBox Text="{Binding CurrentCountries}" ToolTip="{Binding CurrentCountries}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Name="cmbCountry" IsEditable="True" IsReadOnly="True" TextSearch.TextPath="{Binding CountryName}" HorizontalContentAlignment="Left" Margin="80,14,0,0" VerticalAlignment="Top" Width="100 " ItemsSource="{Binding Country, Mode=TwoWay}" SelectedItem="{Binding SelectedCountry,Mode= TwoWay}" Height="22" TabIndex="1">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="Country" HorizontalAlignment="Left" Grid.Column="0" Content="{Binding CountryName}" IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<Commands:EventToCommand Command="{Binding DataContext.CountryCheckedCmd,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type telerik:RadWindow}}}" CommandParameter="{Binding ElementName=Country}" ></Commands:EventToCommand>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<Commands:EventToCommand Command="{Binding DataContext.CountryUnCheckedCmd,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type telerik:RadWindow}}}" CommandParameter="{Binding ElementName=Country}" ></Commands:EventToCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
thank you!
If you want to multiselection ComboBox you should use CheckComboBox from WPF Extended Toolkit.
It's very easy to using, example:
<xctk:CheckComboBox x:Name="_combo"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DisplayMemberPath="Color"
ValueMemberPath="Level"
SelectedValue="{Binding SelectedValue}"
SelectedItems="{Binding SelectedItems}" />