I'm messing around with MVVM and I've hit a bit of a roadblock with binding commands to buttons. I have a few buttons in a View ( = UserControl) that are generated based on a list of objects I have.
My code looks like this:
(MainWindow)
<ItemsControl ItemsSource="{Binding ViewModels}" Margin="12,57,12,12" />
(UserControl)
<ItemsControl ItemsSource="{Binding AllConnections}" Margin="0,34,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Password}" Height="23" HorizontalAlignment="Left" Margin="114,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=ConnectCommand}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But ConnectCommand isn't being called and I assume it's because XAML is looking for it in the AllConnections binding, rather than the ViewModels binding where it should. How do I specify this?
You should use Relative source to specify the ancestor. Something like this:
Command = "{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=ViewModel.CommandToBind}"
You can add your command to Resources and just use {StaticResource yourCommand}. This could significally simplify xaml.
Useful links: WPF Commands, How to declare Application level commands?Commands as XAML ResourcesMVVM Commanding inside of a datatemplate
Related
I have a ListView on my Windows Universal page. I am using a UserControl to define my ItemTemplate so that I can use the RelativePanel and VisualStateManager to control how my items appear depending on the screen size...
<ListView ItemsSource="{Binding Path=AllThings}"
ItemContainerStyle="{StaticResource ListViewItemStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<local:CrossingControl />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have a button in my UserControl where I want to bind its Command to a command property in the ViewModel that is the DataContext of the list itself...
<UserControl ...>
<RelativePanel>
<StackPanel x:Name="crossedEntryPanel">
<Button Command="{Binding DataContext.DeleteCommand,
RelativeSource={RelativeSource Mode=TemplatedParent}}"
CommandParameter="{Binding}"
I have tried using the ElementName binding, but it doesn't seem to work (I suppose because my listview element name is defined in another xaml file). I have also tried the above RelativeSource binding, but that doesn't seem to work either. How can I bind this properly?
You can make use of Tag property to save the DataContext of ListView and use it in UserControl
Here how it is done
<ListView ItemsSource="{Binding Path=AllThings}" x:Name="listview"
ItemContainerStyle="{StaticResource ListViewItemStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<local:CrossingControl Tag="{Binding DataContext,ElementName=listview}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<UserControl x:Name="usercontrol" ...>
<RelativePanel>
<StackPanel x:Name="crossedEntryPanel">
<Button Command="{Binding Tag.DeleteCommand,ElementName=usercontrol}"
CommandParameter="{Binding}"
RelativeSource={RelativeSource Mode=TemplatedParent}}":- this points to controltemplate of button
I'm implementing the search contract (results page) of a Windows 8 application. I've designed everything to follow MVVM. With that, I'm trying to wire up a command to the 'filtersItemsControl' that is provided in the search contract template for Windows 8.
<ItemsControl
x:Name="filtersItemsControl"
Canvas.ZIndex="1"
ItemsSource="{Binding Source={StaticResource filtersViewSource}}"
Visibility="{Binding ShowFilters, Converter={StaticResource BooleanToVisibilityConverter}}"
Margin="120,-3,120,30">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton
GroupName="Filters"
IsChecked="{Binding Active, Mode=TwoWay}"
common:CheckedCommandBehavior.Command="{Binding RelativeSource={RelativeSource Self}, Path=FilterChangedCommand}"
Style="{StaticResource TextRadioButtonStyle}">
<TextBlock Text="{Binding Description}" Margin="3,-7,3,10" Style="{StaticResource GroupHeaderTextStyle}" />
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The code above is my attempt to hook into 'FilterChangedCommand' which is a property of the ViewModel. The ViewModel also contains a list of properties that the ItemsControl is bound to (filtersViewSource). I think my issue is that I'm trying to bind the Command of the RadioButton to a property of filtersViewSource (which obviously does not exist) vs. the ViewModel.
So with that, I THINK the question here is basically, what binding expression can I used on the above RadioButton such that it will reference the ViewModel property.
FiltersViewSource should a property in viewmodel of some type, say "Foo". In that case, radio button will get datacontext of type Foo. So the property "FilterChangedCommand" should be in Foo class.
I am facing problem of data binding in user control.
<UserControl.Resources>
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"
d:Source="{Binding AllGroups[0].Items, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
</UserControl.Resources>
<UserControl.DataContext>
<Binding>
<Binding.Source>
<local:SampleDataSource />
</Binding.Source>
</Binding>
</UserControl.DataContext>
<StackPanel Margin="20,60">
<TextBlock Style="{StaticResource PageHeaderTextStyle}">Categories</TextBlock>
<ListBox>
<ListBoxItem Content="{Binding Title}" />
</ListBox>
</StackPanel>
The Title property binding is showing in the XAML designer window but nothing is showing during execution of the program.
I am using the default flipview layout in which there is a "Title" in SampleDataSource.cs file
The "d:" prefix is for properties that you would define solely for use in the designer, so you should try replacing "d:Source" with "Source".
did you fix following line
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
it's defined at the top where all the page declarations are.
Also
Source="{Binding Items}"
is referring to a List named Items in your DataContext.
I want to add a contextmenu to items in a listbox. Typically the answer is to add the contextmenu to the root of the item template. However, I am using a template selector, so there are multiple templates in use, depending on the data of each item in the listbox. This means I need to add the same contextmenu definition to each template, which is not very appealing.
One solution is to wrap the datatemplate in a ContentControl, which would give me a single place for the context menu definition. However, I believe this would add layout overhead that isn't necessary.
Another solution I tried is adding the ContextMenu to the resource dictionary, but I believe this ends up sharing the same object instance across all the uses, and due to the way ContextMenu is implemented, this also does not work.
A third solution is using the Loaded event to call a function which populates the context menu appropriately. However, this ends up moving a lot of code that ought to be in the XAML into code, and looks quite ugly. If there's some way of defining the context menu in xaml, and then just referencing that from code, I would find it appealing, but I don't quite see how to do that.
What is the right way to share the same ContextMenu across the templates in a template selector?
This is the ContentControl method, which works, but ends up adding two content controls to each item:
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu Loaded="ContextMenu_Loaded">
<toolkit:MenuItem Header="Delete"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<ContentControl ContentTemplate="{StaticResource MyTemplate}" Content="{Binding}"/>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
How about adding the ContextMenu to the TemplateSelector?
<ListBox ItemsSource="{Binding}">
<ListBox.Resources>
<DataTemplate x:Key="MyTemplate">
<StackPanel>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<local:CustomTemplateSelector Content="{Binding}">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Delete"
Click="MenuItem_Click" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<local:CustomTemplateSelector.TemplateOne>
<DataTemplate>
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource MyTemplate}"
Foreground="Blue" />
</DataTemplate>
</local:CustomTemplateSelector.TemplateOne>
<local:CustomTemplateSelector.TemplateTwo>
<DataTemplate>
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource MyTemplate}"
Foreground="Red" />
</DataTemplate>
</local:CustomTemplateSelector.TemplateTwo>
<local:CustomTemplateSelector.TemplateThree>
<DataTemplate>
<ContentControl Content="{Binding}"
ContentTemplate="{StaticResource MyTemplate}"
Foreground="Yellow" />
</DataTemplate>
</local:CustomTemplateSelector.TemplateThree>
</local:CustomTemplateSelector>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I ran this and it worked for me - give it a try and let me know if this was the effect you were looking for or not.
I want to add a trigger to a dynamically created control but I couldn't. The event doesn't fire. This is my code.
<sdk:HierarchicalDataTemplate x:Key="NameTemplate"
ItemsSource="{Binding LstRs}"
ItemTemplate="{StaticResource RsTemplate}">
<TextBlock Text="{Binding Nom}" FontWeight="Bold" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<gs:EventToCommand Command="{Binding Path=StateCommand}"
CommandParameter="{Binding Text, ElementName=TextBoxSearch, Mode=OneWay}"
MustToggleIsEnabledValue="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</sdk:HierarchicalDataTemplate>
and the command is implemented in the view model.
IMHO, the most common error in such a case is that the command was not created - i.e. StateCommand == null - when the data is bound. Make sure you created the command in the constructor of you view-model.