Command & command parameter Tree in Xaml - c#

Trying to change one button to other, I have stuck in a problem with commands handling. It is difficult to describe its source, because nearly all are the same, but when I pass the command via setter it is not working.
My previous code (it is working like a charm):
it is just a split button that passes its menu item header as parameter to executing command.
<xctk:SplitButton.DropDownContent>
<ItemsControl ItemsSource="{Binding Instance.InstanceVM.Names}" x:Name="NamesCtr">
<ItemsControl.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Command="{Binding ElementName=NamesCtr, Path=DataContext.Instance.InstanceVM.Load}" CommandParameter="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</xctk:SplitButton.DropDownContent>
And here is for my dropdown button:
<controls:DropDownButton.DropDownContextMenu>
<ContextMenu x:Name="NamesCtr" ItemsSource="{Binding Instance.InstanceVM.Names}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Template" Value="{StaticResource DropDownMenuItemTemplate}"/>
<Setter Property="Header" Value="{Binding}"/>
<Setter Property="Command" Value="{Binding ElementName=Namestr, Path=DataContext.Instance.InstanceVM.Load}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</controls:DropDownButton.DropDownContextMenu>
This shows a button, a dropdown with correct menu items (so the source, template and header were bound correctly, but the command does not hit its function)
Found a solution here :
How do you bind a command to a MenuItem (WPF)?

As you are binding through a static singleton, you can modify the Binding like this:
<Setter Property="Command" Value="{Binding Source={x:Static <xmlnamespace>:<yourType>.Instance}, Path=InstanceVM.Load}"/
Don't forget to replace the placeholders with valid values, i.e. with an xml namespace prefix that corresponds to the appropriate CLR namespace and the type declaring the Instance property.
Please note that ElementName bindings and RelativeSource bindings are less trustworthy if placed in DataTemplates / Styles and also in case of using Popups in your visual tree.

Related

Textblock won't recieve trigger in HierachicalDataTemplate

I'm trying to get a TreeView to display items as a TextBlock, and then based on a boolean inside the data-bound object to either make the FontWeight Normal or Bold, pretty much the following:
<TreeView x:Name="TreeView" ItemsSource="{Binding Layers}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewModels:Layer}" ItemsSource="{Binding Path=Layers}">
<TextBlock Text="{Binding Path=Name}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ShowInPreview}">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
The Setter outside the trigger actually works, when I set that one to "Bold", everything goes Bold right away. It's just the DataTrigger that never, well... triggers :P
The ItemSource implements INotifyPropertyChanged, and so does the Layer object on all properties (including the ShowInPreview).
I've tried all kinds of different setups I could find on the web (using Window.Resources, putting it in TreeView.ItemContainerStyle, etc. etc), so I'm completely at a loss right now!
Set the Value on your data trigger.
I dont know exactly where is your property, try something like this. I think, issue in binding:
<DataTrigger Binding="{Binding Path=DataContext.ShowInPreview, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}}">

How do I create a "Window" menu in XAML?

I am creating an MVVM Wpf client application. I want create menu in the main View for the application that his a menu item called "Window" on it. That menu item will dynamically update itself with a submenu of menuitems who are made up of the list of active windows running in the application. I created a ViewManager whom each View registers itself with to compile a list of active windows.
I am trying to do this in XAML but getting an error when I click on "Window"
<MenuItem Header="Window">
<ItemsControl ItemsSource="{Binding ViewMgr.Views}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.OpenWindowCmd ,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</MenuItem>
How do I create a dynamically updated list of menuitems on my menu in XAML using a MVVM style of data bindings and commands?
You are adding a new ItemsControl as a single child of the menu item, instead of adding each view as one child of the menu item itself. You probably get the error because the styles TargetType doesn't match. MenuItem inherits from ItemsControl itself and exposes a property ItemsSource. Try the following:
<MenuItem ItemsSource="{Binding ViewMgr.Views}" DisplayMemberPath="Title">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.OpenWindowCmd, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>

DataTemplate in ControlTemplate not updating Binding

I've created a control with 3 PART_s, one PART_ changes depending on the type bound to it, however values changed within the Control do not update the Binding, it seems to work as OneWay Binding.
Here's part of the code I beleive is relevant:
<DataTemplate x:Key="BooleanDAView" DataType="{x:Type sys:Boolean}">
<CheckBox IsChecked="{Binding ., Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="DateTimeDAView" DataType="{x:Type sys:DateTime}">
<extToolkit:DateTimePicker Value="{Binding ., Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="Int32DAView" DataType="{x:Type sys:Int32}">
<extToolkit:IntegerUpDown Value="{Binding ., Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="StringDAView" DataType="{x:Type sys:String}">
<TextBox Text="{Binding ., Mode=TwoWay}"/>
</DataTemplate>
....
<ContentControl x:Name="PART_Content"
Grid.Row="0" Grid.Column="1"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
>
<ContentControl.ContentTemplateSelector>
<controls:TypeBasedDataTemplateSelector>
<controls:TypeBasedDataTemplateSelector.Templates>
<controls:TypedDictionary>
<sys:String x:Key="{x:Type sys:Boolean}">BooleanDAView</sys:String>
<sys:String x:Key="{x:Type sys:DateTime}">DateTimeDAView</sys:String>
<sys:String x:Key="{x:Type sys:Int32}">Int32DAView</sys:String>
<sys:String x:Key="{x:Type sys:String}">StringDAView</sys:String>
</controls:TypedDictionary>
</controls:TypeBasedDataTemplateSelector.Templates>
</controls:TypeBasedDataTemplateSelector>
</ContentControl.ContentTemplateSelector>
</ContentControl>
For Content I've also tried ... RelativeSource={RelativeSource AncestorType=local:DABaseControl} but no change.
If the DataTemplate Binding use "{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" the template doesn't change once set.
Or is there a better way to do this?
Thanks
I just encountered the same problem, I wanted to create a DataTemplate with DataType="{x:Type sys:Boolean} that just had a checkbox. But there were many warning signs along the way telling me this isn't the way it should be done.
At first, the simple binding of {Binding} would throw an exception "Two-way binding requires path or xpath", which was the first warning sign. I changed the binding to {Binding .} which worked (even though this MSDN article clearly states that they're equivalent). That fact that voodoo was helping was the second warning sign. It then displayed correctly and the checked state was according to the boolean value, but when clicking the checkbox (even with UpdateSourceTrigger=PropertyChanged), it refused to update the binding source, no matter what I tried. Using diagnostics:PresentationTraceSources.TraceLevel=High showed that it didn't even try to bind back (third warning sign).
I went ahead and created a simple "box" for the bool value - a class with a single bool property named Value with anINotifyPropertyChanged implementation. I changed the binding to {Binding Value} and now everything worked, including two way binding.
Conclusion: It seems a binding can't update the bound object itself, but only properties of that object (which is why {Binding} throws an exception, but the more explicit {Binding .} suppresses that exception, according to H.B.'s answer). In any case, the approach of creating a ViewModel and creating templates that target it appears to be more than a mere design guideline, but an actual technical requirement.
I've actually never worked with a ContentTemplateSelector, but if I had to hazard a guess I would say either it's not responding to PropertyChanged events on your ContentControl.Content property, or your Content binding is incorrect.
You can easily check if your binding is correct or not by removing the ContentTemplateSelector and seeing if data shows up at all. If it does, your binding is correct. If it doesn't, it's incorrect and you need to fix it.
If the problem is the ContentTemplateSelector, then I would suggest switching to a DataTrigger which determines which ContentTemplate to use based on the Content. This is what I usually do, and it uses a Converter which simply returns typeof(value)
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource StringDAView}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource ObjectToTypeConverter}"
Value="{x:Type sys:Boolean">
<Setter Property="ContentTemplate" Value="{StaticResource BooleanDAView}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource ObjectToTypeConverter}"
Value="{x:Type DateTime">
<Setter Property="ContentTemplate" Value="{StaticResource DateTimeDAView}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource ObjectToTypeConverter}"
Value="{x:Type sys:Int32">
<Setter Property="ContentTemplate" Value="{StaticResource Int32DAView}" />
</DataTrigger>
</Style.Triggers>
</Style>

How to dynamically inject a user control based on user selection

I have a TreeView control on my window that depending on which selection the user picks should display a user control (figuring out which user control to display is complete). I'm having issues figuring out how to actually display the user control. Essentially, the user would select item from the TreeView and based on the selection a user control would appear (in a ContentControl control I'm assuming).
Currently, for opening new windows I have a window adapter where I can create new windows on the fly and set the parent.
How can I accomplish this in my view model?
Edit
Here is what I believe Rachel was talking about when she mentioned using DataTemplate's instead. Don't be worried of my DataTemplates instead the DataType attribute. That's simply the name of my project.
<Window.Resources>
<DataTemplate DataType="{x:Type DataTemplates:FooEditorViewModel}">
<DataTemplates:FooControl></DataTemplates:FooControl>
</DataTemplate>
<DataTemplate DataType="{x:Type DataTemplates:BarEditorViewModel}">
<DataTemplates:BarControl></DataTemplates:BarControl>
</DataTemplate>
</Window.Resources>
And here is a sample view model.
public class ViewModel
{
public IEditorViewModel Editor
{
get
{
return new BarEditorViewModel();
}
}
}
And glue it all together with
<ContentControl Content="{Binding Editor}" />
I had to create a blank interface called IEditorViewModel in order to return different user control editors. Not sure if there's any way around it.
Hopes this helps someone.
Your SelectedTreeViewItem would be stored in your ViewModel, and that value would be used to determine which item to display.
An example would be something like:
<ContentControl Content="{Binding SelectedItem}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem}" Value="{x:Type local:ItemA}">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateA}" />
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem}" Value="{x:Type local:ItemB}">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateB}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
A better alternative is to use DataTemplates for different Items. Then you just set your Content="{Binding SelectedItem}" and WPF will resolve the correct DataTemplate to use. I just showed the above example first because it can be used to base your Template off a Property of SelectedItem

Trouble binding WPF Menu to ItemsSource

I would like to avoid having to build a menu manually in XAML or code, by binding to a list of ICommand-derived objects. However, I'm experiencing a bit of a problem where the resulting menu has two levels of menu-items (i.e. each MenuItem is contained in a MenuItem):
My guess is that this is happening because WPF is automatically generating a MenuItem for my binding, but the "viewer" I'm using actually already is a MenuItem (it's derived from MenuItem):
<ContextMenu
x:Name="selectionContextMenu"
ItemsSource="{Binding Source={x:Static OrangeNote:Note.MultiCommands}}"
ItemContainerStyleSelector="{StaticResource separatorStyleSelector}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<Viewers:NoteCommandMenuItemViewer
CommandParameter="{Binding Source={x:Static OrangeNote:App.Screen}, Path=SelectedNotes}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
(The ItemContainerStyleSelector is from http://bea.stollnitz.com/blog/?p=23, which allows me to have Separator elements inside my bound source.)
So, the menu is bound to a collection of ICommands, and each item's CommandParameter is set to the same global target (which happens to be a collection, but that's not important).
My question is, is there any way I can bind this such that WPF doesn't automatically wrap each item in a MenuItem?
Unfortunately, the best way I've found to work around this issue is to use a style for the MenuItems, rather than an ItemTemplate. Then each property in the style can be bound to properties on your object. Something like this, for example:
<Style x:Key="SelectionContextMenuStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="Command" Value="{Binding Path=Command}" />
<Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>
It really seems like an ItemTemplate should work, and it would be the better way to go, but this is the only way I've found that actually works properly.
I would be inclined to subclass ContextMenu and override GetContainerForItemOverride:
public class ContextMenuWithNoteCommands : ContextMenu
{
protected virtual DependencyObject GetContainerForItemOverride()
{
return new NoteCommandMenuItemViewer();
}
}
Then set the CommandParameter binding in the NoteCommandMenuItemViewer style, or in ContextMenu.ItemContainerStyle, whichever is more appropriate.
This presumes you can't simply use ItemContainerStyle on a regular MenuItem to get the effect you want:
<ContextMenu ...>
<ContextMenu.ItemContainerStyle>
<Style>
...
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>

Categories