I'm having a problem binding to my command in my ListBox ItemTemplate. My command is defined in my ViewModel, but because I'm using ItemsSource for my listbox, that's set as the DataContext.
<ListBox ItemsSource="{Binding CreatureModel.TypeFlagsValues}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" Command="{Binding SetCommand">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've tried using RelativeSource
Command="{Binding SetCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type vm:CreatureEditorViewModel}}}"
And
<DataTemplate DataType="vm:CreatureEditorViewModel">
<CheckBox Content="{Binding}" Command="{Binding SetCommand}" CommandParameter="test">
</CheckBox>
</DataTemplate>
I feel like I'm missing something simple here.
You almost did it right with RelativeSource.
Try this:
Command="{Binding Path=DataContext.SetCommand,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ItemsControl}} }"
Alternatively you may give a name to your listbox (e.g. "_listBox" and use the following binding:
Command="{Binding DataContext.SetCommand, ElementName=_listBox}
Try setting the ElementName and Path on the Command; you have to set the x:Name on the ListBox, then you can reference the parent DataContext.
<ListBox x:Name="list" ItemsSource="{Binding CreatureModel.TypeFlagsValues}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" Command="{Binding ElementName=list,
Path=DataContext.SetCommand}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Related
I have a stack panel for which I need a mouse event to be handled in the ViewModel but the binding doesn't work - the command isn't found although the other elements are also binded to the ViewModel and they work. Here is the xaml:
<Window.DataContext>
<vm:Ticker/>
</Window.DataContext>
<ListView Grid.Row="3"
ItemsSource ="{Binding TickersCollectionView}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Name="STPListView">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding MouseLeftButtonDownCommand}"
CommandParameter="{Binding ElementName=STPListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock
Width="130"
Text="{Binding Market}"
Foreground="WhiteSmoke"/>
<TextBlock
Width="110"
Text="{Binding Price}"
Foreground="{Binding LastPrice, Converter={StaticResource BoolToForeground}}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The command is a property of the ViewModel. How can I bind it?
If the MouseLeftButtonDownCommand property is defined in the same view model as the TickersCollectionView property, you should bind to it using a RelativeSource:
Command="{Binding DataContext.MouseLeftButtonDownCommand,
RelativeSource={RelativeSource AncestorType=ListView}}"
I am learning navigation with MVVM as seen here:
Navigation with MVVM
In this tutorial, binding a command for button control is implemented by using ItemsControl like this:
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeViewModel}">
<local:HomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsViewModel}">
<local:ProductsView />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<ContentControl Content="{Binding CurrentPageViewModel}" />
</DockPanel>
If I understand it correctly, it iterates through collection of PageViewModels and binds a button command for every VIewModel. This example works fine and I am able to switch between pages with no problem.
However, I don't want to create buttons iteratively. I want to have two buttons inside a grid with the same command that switches views as in example above. Something like this:
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeViewModel}">
<local:HomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsViewModel}">
<local:ProductsView />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="{Binding HomeView.Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"/>
<Button Grid.Column="1"
Content="{Binding ProductsView.Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"/>
</Grid>
But this doesn't work as I expected. I am able to bind View's names but not the Command. Clicking buttons is doing nothing. DataContext is set to an instance of my ApplicationViewModel. What could be a problem here?
The problem is in the CommandParameter="{Binding }", in the first example that binding is pointing to ItemsSource="{Binding PageViewModels}". The second example doesn't have that part, so that binding is failing.
EDIT>>>>
To clarify, you must bind the command parameter to an instanciated viewModel in your datacontext.
ViewModel:
public IPageViewModel homeViewModel{get; set;}
public IPageViewModel productsViewModel{get; set;}
...
IPageViewModel homeViewModel = new HomeViewModel();
IPageViewModel productsViewModel = new ProductsViewModel();
View:
CommandParameter="{Binding DataContext.homeViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
I dont have a code editor right now, but hope it helps.
I'm building a treeview with HierarchicalDataTemplates and would like to bind the nodes to a command from my MainViewModel. I guess there is some conflict with the scopes, since the binding works if I e.g. use a button and define it outside of the treeview. If I define it inside, however, it does not work.
I've searched through Stackoverflow and found several solutions but none that worked for me. Jehof e.g. suggested here to use
<Button Command="{Binding DataContext.Command,
RelativeSource={RelativeSource AncestorLevel=2, AncestorType=TreeViewItem}}"
CommandParameter="{Binding}" />
but that did not work. Thank you for any suggestions!
<TreeView ItemsSource="{Binding _questions}" Grid.Row="0" Margin="10" BorderThickness="1">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Question}" ItemsSource="{Binding Converter={StaticResource QuestionConverter}}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MainOption}" ItemsSource="{Binding MainOptions}">
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Path=Name}" />
/////////////////////////////////////
<Button Command="{Binding ThisIsMyCommand}" Content="Click Me"/>
/////////////////////////////////////
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
Is your TreeView-Control inside a Window or UserControl?
If you are inside a Window:
<Button Command="{Binding DataContext.Command, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" CommandParameter="{Binding}" />
and for UserControl
<Button Command="{Binding DataContext.Command, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" CommandParameter="{Binding}" />
I have the following DataTemplate used in a TreeView.
How do I have LeftMouseClick on the ContentPresenter to bind to a property of the DataType in MVVM fashion?
Thanks for any help (or better idea).
<DataTemplate x:Key="sharedTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox
Focusable="False"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
/>
<ContentPresenter
Content="{Binding Name, Mode=OneTime}"
Margin="2,0"
/>
</StackPanel>
</DataTemplate>
<TreeView
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
ItemsSource="{Binding ReportTree}" >
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type r:ReportViewModel}"
ItemsSource="{Binding Children}"
>
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource sharedTemplate}" />
</HierarchicalDataTemplate>
................
Addendum: This works!
<DataTemplate DataType="{x:Type r:PrinterViewModel}">
<!--Bind the ContentControl to the DataType-->
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource sharedTemplate}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<h:EventToCommand
Command="{Binding DataContext.SelectItem, RelativeSource={RelativeSource FindAncestor, AncestorType=TreeView}}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ContentControl>
</DataTemplate>
Addendum: As it turns out, the above Interaction.Trigger does work to correctly send the selected viewmodel back to the DataContext of the TreeView. Problem solved.
i want those buttons next to each other and not under each other
this is a mvvm, so the buttons are generated by a class
<ItemsControl ItemsSource="{Binding Pages}" Grid.Column="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Margin="8" Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You just have to change the default ItemsPanel from your ItemsControl into a horizontal oriented one, here's an example :
<ItemsControl ...>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Margin="8" Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By defining an horizontal StackPanel as your ItemsControl panel, each item will be aligned next to each other (Note that the default one is a vertical StackPanel).