WPF command parameter for MiddleClick on CheckBox in ItemsControl - c#

I want to trigger a command when I use a MiddleClick on a Checkbox in an ItemsControl. I need to return the item source as a command parameter. I have tried two methods in XAML.
Method 1:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</ItemsControl.InputBindings>
</ItemsControl>
This method returns the UserControl to the command instead of the item source.
Method 2:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding Path=SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This method does not trigger the SelectOnlyCommand. Thanks for your help.

(Edited)
if you want to pass the single item, it works like this:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding ElementName=CheckBoxItems, Path=DataContext.SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

You can achieve that with way 2 , but problem is you not able to bind Command. You will have to bind it by ElementName.
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding ElementName=CheckBoxItems, Path = DataContext.SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>

Related

Split RadioButtons/Checkbox into 2 columns

I have a lot of RadioButtons and Checkboxes and I basically want to split them in a second Column, to make it look more user friendly. I found some examples but not really for WPF.
Picture of Buttons
and this is my XAML:
<Grid>
<ItemsControl ItemsSource="{Binding AuswahlOptionenViewModelCollection}" Margin="115,50,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="antwortmoeglichkeiten:OptionViewModel">
<Viewbox Height="25" HorizontalAlignment="Left" VerticalAlignment="Top">
<CheckBox Style="{DynamicResource MaterialDesignUserForegroundCheckBox}"
CommandParameter="{Binding}"
Command="{Binding SelectedOptionViewModelCommand}"
IsChecked="{Binding Selected}"
Content="{Binding Value}"/>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
You can change ItemsPanel and use UniformGrid with 2 columns:
<ItemsControl ...>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
...
</ItemsControl.ItemTemplate>
</ItemsControl>

Access current ItemsControl index via binding

I have the following piece of code
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Offers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<wpf:Card Padding="32" Margin="5" d:DataContext="{d:DesignData }">
<StackPanel Margin="0,0,0,-30" Height="107">
<TextBlock
Style="{DynamicResource MaterialDesignTitleTextBlock}">
<Run Text="Offer " />
</TextBlock>
<TextBlock Text="{Binding CarDescription}" />
<Separator Height="1" Visibility="Hidden" />
<Button Content="Select"
Width="72"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="0,20,0,0"
Command="{Binding SelectOfferCommand}"/>
</StackPanel>
</wpf:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This produces a bunch of repeated boxes, every has a button. Every time i click the button i want to access current box index (from ItemsControl's ItemsSource) and pass it as a command parameter. Is it possible to do it?
You can pass the current Index of an ItemsControl using the AlterationIndex.
See more info here
Example:
<ItemsControl x:Name="ItemsControl"
ItemsSource="{Binding Offers}"
AlternationCount="1000">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<wpf:Card Padding="32" Margin="5" d:DataContext="{d:DesignData }">
<StackPanel Margin="0,0,0,-30" Height="107">
<TextBlock
Style="{DynamicResource MaterialDesignTitleTextBlock}">
<Run Text="Offer " />
</TextBlock>
<TextBlock Text="{Binding CarDescription}" />
<Separator Height="1" Visibility="Hidden" />
<Button Content="Select"
Width="72"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="0,20,0,0"
Command="{Binding SelectOfferCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}"/>
</StackPanel>
</wpf:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
May be it will be suitable for you to add index property to each Offer while creating Offers and send this index OnSelectOfferCommand. It will be much easier
ps I think i must explain my answer: My sugestion is not only easier in realisation, but also it is a good practice to seperate busines logic from UI. In this case if UI will be changed, changes will not effect whole ordering process

Custom ItemsControl with optional Paging

I have a slightly extraordinary request ;-)
I'd like to develop an ItemsControl with a "Previous" Control and a "Next" Control. Like this bound to an arbitrary ViewModel:
<controls:PagedItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="system:String">
<Border Background="Gray" Margin="5">
<TextBlock Text="{Binding}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<controls:PagedItemsControl.PreviousControl>
<Button Content="Previous" Command="{Binding PreviousCommand}" />
</controls:PagedItemsControl.PreviousControl>
<controls:PagedItemsControl.NextControl>
<Button Content="Next" Command="{Binding NextCommand}" />
</controls:PagedItemsControl.NextControl>
</controls:PagedItemsControl>
In the example I passed 2 buttons controlled by the ViewModel's commands. It would be awesome if somebody could tell me how to listen to the Control.IsEnable state and show the PreviousControl as first item if enable and the the NextControl as last item if enable.
Thank you
Have a look at the following XAML. We cannot add elements to ItemsPanel while using ItemsSource. But we may try to build a tricky collection which consists of ItemsSource and additional elements. Unfortunately CollectionContainer unable to bound to Items directly. Lucky that good guys already found a solution for this case.
<Grid>
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</Grid.Resources>
<TextBlock Name="TrickyBinder"
Tag="{Binding Items}"
Visibility="Collapsed"/>
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="system:String">
<Border Background="Gray" Margin="5">
<TextBlock Text="{Binding}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer>
<CollectionContainer.Collection>
<col:ArrayList>
<Button Content="Previous" Command="{Binding PreviousCommand}" Visibility="{Binding Path=IsEnabled,RelativeSource={RelativeSource Self},Converter={StaticResource BoolToVisibilityConverter}}" />
</col:ArrayList>
</CollectionContainer.Collection>
</CollectionContainer>
<CollectionContainer Collection="{Binding Path=Tag,Source={x:Reference TrickyBinder}}"/>
<CollectionContainer>
<CollectionContainer.Collection>
<col:ArrayList>
<Button Content="Next" Command="{Binding NextCommand}" Visibility="{Binding Path=IsEnabled,RelativeSource={RelativeSource Self},Converter={StaticResource BoolToVisibilityConverter}}" />
</col:ArrayList>
</CollectionContainer.Collection>
</CollectionContainer>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
</Grid>
Hope this helps!

Binding is not working with data template in data template

I have a ListView with an nested ItemTemplate for presenting orders.
Each order is presented within a Expander. These Expanders have a ContentTemplate for presenting all positions within each order. And these order positions are also in a Expander.
The ListView gets its data from an ObservableCollection (AvailableOrders) which contains all orders. These order object have a ObservableCollection "Items" holding all positions for this order.
But I'm not able to get the bindings work properly. How should I properly set the binding for the "inner expander" to show information about the items?
All ideas are appreciated!
<ListView ItemsSource="{Binding VMOrder.AvailableOrders}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Order " />
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.Template>
<ControlTemplate>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Material.Name}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="TEST" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I've figured it out now.
I need to use a relative source in the data templates and set the content property of each expander.
<ListView ItemsSource="{Binding VMOrder.AvailableOrders}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Order " />
<TextBlock Text="{Binding DataContext.Id, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.Material.Name, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.Material.Description, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For the inner ItemsControl, you have defined the control template for the whole control. You have to define the ItemTemplate instead
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Material.Name}" />
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<TextBlock Text="TEST" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Alignment of nested databinding with ItemsControl in C# WPF

I have the following datatemplate:
<ItemsControl x:Name="Groups" ItemsSource="{Binding Groups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="GroupStackPanel" Orientation="Horizontal">
<GroupBox Header="{Binding Path=GroupName}">
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="BtnStackPanel" Orientation="Horizontal">
<Button Content="{Binding Path=LabelString}"
Command="{Binding Path=ButtonCommand}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</GroupBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This includes some ButtonGroups and Buttons which are in this Group.
The class Group includes a string-property "GroupName" and an ObservableCollection-property "Buttons". The allocation of buttons and groups is working correctly.
So here is my problem: I want to have this buttongroups in a ribbontab in the dockpanel. But the alignment or the orientation is false, so the buttons are one below the other and not next to each other.
Has anyone an idea what is wrong in my code?
At the moment, you're using a Stackpanel with horizontal orientation, which is the right idea, but the Stackpanel is in the wrong place (the ItemTemplate). The ItemTemplate is applied to every item in an ItemsControl, which means that your XAML represents a collection of buttons where each is surrounded by its very own StackPanel.
To have the desired effect, you instead need to specify the Stackpanel as the ItemsPanelTemplate of the ItemsControl.
Try changing your inner clause to:
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=LabelString}" Command="{Binding Path=ButtonCommand}"/>
</DataTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="BtnStackPanel" Orientation="Horizontal">
</ItemsPanelTemplate>
<ItemsControl.ItemsPanel>
</ItemsControl>
Edit
If you want both groups and buttons to display horizontally, you can do the same thing to both:
<ItemsControl x:Name="Groups" ItemsSource="{Binding Groups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<GroupBox Header="{Binding Path=GroupName}">
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=LabelString}" Command="{Binding Path=ButtonCommand}"/>
</DataTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="BtnStackPanel" Orientation="Horizontal"/>
</ItemsPanelTemplate>
<ItemsControl.ItemsPanel>
</ItemsControl>
</GroupBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="GroupStackPanel" Orientation="Horizontal"/>
</ItemsPanelTemplate>
<ItemsControl.ItemsPanel>
</ItemsControl>

Categories

Resources