WPF: Binding to a (observable) Dictionary - wpf

I'm using this ObservableCollection-Class within my Project: Link
I want to Bind a RibbonMenuButton to a ObservableDictionary<string,bool>:
<r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
<r:RibbonMenuButton.ItemContainerStyle>
<Style TargetType="{x:Type r:RibbonMenuItem}">
<Setter Property="IsCheckable" Value="true"/>
<Setter Property="Header" Value="{Binding Path=Key}"/>
<Setter Property="IsChecked" Value="{Binding Path=Value}"/>
</style>
</r:RibbonMenuButton.ItemContainerStyle>
</r:RibbonMenuButton>
But I get exceptions because the Value-Properties of the internal IDictionary-KeyValuePairs are readonly. Any Idea how to solve this?
I thought about something like:
<Setter Property="IsChecked" Value="{Binding Source=MyDictionary[{Binding Path=Key}]}"/>
But this won't work 'cause of {Binding} in {Binding}...

This doesn't work, because your dictionary isn't treated as a dictionary but as an IEnumerable<KeyValuePair<string, bool>>. So each RibbonMenuItem is bound to a KeyValuePair<string, bool> with readonly properties Key and Value.
You can do two one things:
1. Use an ObservableCollection<Tuple<string, bool>> instead of the dictionary and bind IsChecked to Item2.
2. Create a little helper class that contains a IsChecked property and change your dictionary to contain that class as the value and bind IsChecked to Value.IsChecked.
I would go with answer two, because the needed changes and possible side effects are smaller.
My answer assumes that you want to have a two way binding on IsChecked. If not, go with the answer of slugster.

WPF binding is two-way by default. Make it one-way and see if that solves your issue.
<r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
<r:RibbonMenuButton.ItemContainerStyle>
<Style TargetType="{x:Type r:RibbonMenuItem}">
<Setter Property="IsCheckable" Value="true"/>
<Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
<Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
</style>
</r:RibbonMenuButton.ItemContainerStyle>
</r:RibbonMenuButton>
Here is a reference for you: MSDN Windows Presentation Foundation Data Binding: Part 1 (specifically check the section Binding Mode close to the bottom of the page)

If You want to bind MenuItems to Dictionary<string, bool> without using a helper class, like the accepted answer suggests, here is the minimal-change solution (no need to add anything else):
define a Click event inside the ItemContainerStyle whose ClickEventHandler will update the dicitonary.
declare a dictionary and initialize it inside the UserControl's / Window's constructor
In code:
MainWindow.xaml:
<MenuItem Header="_My settings" ItemsSource="{Binding MySettings}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="IsCheckable" Value="true"/>
<Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
<Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
<!-- this is the main line of code -->
<EventSetter Event="Click" Handler="MySettings_ItemClick"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
// properties...
// Declaration of the dictionary
public Dictionary<string, bool> MySettings{ get; set; }
public MainWindow()
{
InitializeComponent();
// Initialize the dictionary
MySettings = new Dictionary<string, bool>()
{
{ "SettingOne", true}
// Other pairs..
};
}
// other things..
// ClickEvent hanlder
private void MySettings_ItemClick(object sender, RoutedEventArgs e)
{
MenuItem clickedItem = (sender as MenuItem);
MySettings[clickedItem.Header as string] = clickedItem.IsChecked;
}
} // end of MainWindow class
That's it! You're all set!
Credits to slugster and his answer for XAML code for OneWay binding :)

As a general solution to this problem of binding to dictionaries I created an UpdateableKeyValuePair and return that instaed of the usual KeyValuePair. Here is my class:
public class UpdateableKeyValuePair<TKey,TValue>
{
private IDictionary<TKey, TValue> _owner;
private TKey _key;
public UpdateableKeyValuePair(IDictionary<TKey, TValue> Owner, TKey Key_)
{
_owner = Owner;
_key = Key_;
}
public TKey Key
{
get
{
return _key;
}
}
public TValue Value
{
get
{
return _owner[_key];
}
set
{
_owner[_key] = value;
}
}
}

Related

User control parameter in wpf mvvm

I want to create a user control with a bool parameter that defines a dynamic behavior, using MVVM pattern, so I can use the user control in another view that way :
<local:MyUserControl BoolParam={Binding aBoolBinding} />
About the coding of the user control, the xaml should use the value of BoolParam to do something like this :
...
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Trigger>
<DataTrigger Binding="{referenceToBoolParam}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
...
Am I supposed to define a property
public bool BoolParam { get; set; }
in the code-behind of the user control, and to code the logic associated to this parameter in the ViewModel of the user control ?
Actually I am a bit confused about it, what is the good practice ?
BoolParam should be a dependency property for you to be able to bind something to it. You define this in the code-behind of MyUserControl:
public bool BoolParam
{
get { return (bool)this.GetValue(BoolParamProperty); }
set { this.SetValue(BoolParamProperty, value); }
}
public static readonly DependencyProperty BoolParamProperty = DependencyProperty.Register(
"BoolParam", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false));
You could then set the DataContext of the UserControl to an instance of a view model that contains a public bool property called aBoolBinding and bind to this one as usual.
View Model:
private bool _b;
public bool aBoolBinding
{
get
{
return _b;
}
set
{
_b = value;
NotifyPropertyChanged();
}
}
View:
<local:MyUserControl BoolParam="{Binding aBoolBinding}" />
This is how data binding works. A target property in the views is bound to a source property of a view model.
Edit:
This binds to the BoolParam property of the UserControl from a TextBox style defined in the UserControl:
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding BoolParam, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Setting the style in ItemContainerStyleSelector based on the property value present in ViewModel

I want to know Can u decide the style in custom Style Selector class based on Property value present in the corresponding ViewModel??
Or
Is there any way to select the ItemContainerstyle based on the Property in the ViewModel??
Yes, ItemsControl provides ItemContainerStyleSelector for this. There could be two different scenarios for choosing Style for ItemContainer.
In this example, we have
public class ViewModel
{
public ObservableCollection<Student> Students { get; set; }
public bool IsGood { get; set; }
}
Choosing based on main ViewModel (this is different from ItemsSource). Use Trigger for this.
<ItemsControl.Style>
<Style TargetType="ItemsControl">
<Style.Triggers>
<DataTrigger Binding="{Binding IsGood}" Value="True">
<Setter Property="ItemContainerStyle" Value="{DynamicResource Style1Key}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
Choosing based on a property (ex, Name) of Student. We have to use ItemsControl.ItemContainerStyleSelector here.
public class MyStyleSelector : StyleSelector
{
public Style Style1 { get; set; }
public Style Style2 { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
Student s = (Student)item;
if(s.Name == "Gopi")
return Style1;
else
return Style2;
}
}
XAML
<Window.Resources>
<Style x:Key="Style1Key">
<Setter Property="Control.Opacity" Value="0.3"/>
</Style>
<Style x:Key="Style2Key">
<Setter Property="Control.Opacity" Value="0.7"/>
</Style>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Students}">
...
<ItemsControl.ItemContainerStyleSelector>
<local:MyStyleSelector Style1="{StaticResource Style1Key}" Style2="{StaticResource Style2Key}"/>
</ItemsControl.ItemContainerStyleSelector>
...
</ItemsControl>

stuck to call view model from view

I have a tree view like below added mousedouble click
<TreeView
Grid.Row="0"
Name="tvTopics"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
MouseDoubleClick="tvTopics_MouseDoubleClick"
ItemsSource="{Binding TierOneItems}"
SelectedItemChanged="treeView1_SelectedItemChanged">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding Topic.IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
<Trigger Property="IsExpanded" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
on my code behind
private void tvTopics_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TreeView tv = sender as TreeView;
if (tv.SelectedItem is TopicTreeItemViewModel)
{
Model.SelectedTopic = ((TopicTreeItemViewModel)tv.SelectedItem).Topic;
}
}
here i am trying to pass my "topic" value to my view model but i have no idea how to pass or call my view model method.
public class TopicTreeViewModel : NotificationObject, ITopicTreeViewModel
{
[ImportingConstructor]
public TopicTreeViewModel(IGatewayService storyService, IEventAggregator eventAggregator)
{
this.storyService = storyService;
this.eventAggregator = eventAggregator;
this.AddTopicCommand = new DelegateCommand<object>(this.AddTopic);
Helper.SubscriptionTokenList_LocationSearch.Add(this.eventAggregator.GetEvent<LocationSearchEvent>().Subscribe(OnLocationSearch, ThreadOption.UIThread));
Helper.SubscriptionTokenList_SubjectSearch.Add(this.eventAggregator.GetEvent<SubjectSearchEvent>().Subscribe(OnSubjectSearch, ThreadOption.UIThread));
}
public void MouseDoubleClick(Topic topic)
{
if (topic != null && topic is Topic)
{
switch (this.searchType)
{
case SearchType.Location:
this.eventAggregator.GetEvent<AddLocationEvent>().Publish((Topic)topic);
break;
case SearchType.Subject:
this.eventAggregator.GetEvent<AddSubjectEvent>().Publish((Topic)topic);
break;
}
}
}
And the interface connect between view and view model
public interface ITopicTreeViewModel
{
ReadOnlyCollection<TopicTreeItemViewModel> TierOneItems { get; }
ICommand SearchCommand { get; }
string SearchText { get; set; }
Topic SelectedTopic { get; set; }
}
All im trying to do here is passing the topic value to my view model when the mousedouble click event triggered.
I have no idea how to pass or bind this value. any help much appreciated.
When using Prism and MVVM in particular, it is reccomended to add the minimal code behind implementation as possible. Therefore, every logic or action performed would be handled directly into the ViewModel.
Instead of handling the event on the View's Code Behind, you should bind the MouseDoubleClick event to a Delegate Command in the ViewModel. So, in order to achieve this, you would need to set the proper ViewModel as the DataContext of the View. This way, Binding would be resolved through the DataContext implementation.
The following MSDN Prism Guide chapter would be helpful to understand the interaction between View and ViewModel:
Implementing the MVVM pattern
Advance MVVM scenarios
In addition, you could take a look at the MVVM Prism QuickStart and undestand how the Binding to the View-ViewModel interaction is implemented.
I hope this helped, Regards.

How to add horizontal separator in a dynamically created ContextMenu?

I was looking for the solution on the internet but was not able to find it within my sample. I need to add a separator between Context menu item that are generated from code behind. I tried to add it with such code lines like below but without success.
this.Commands.Add(new ToolStripSeparator());
I am wondering if someone can help. Thank you in advance.
Context Menu XAML:
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding Commands}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding}" />
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Setter.Value>
</Setter>
C# that added in the method:
this.Commands = new ObservableCollection<ICommand>();
this.Commands.Add(MainWindow.AddRole1);
this.Commands.Add(MainWindow.AddRole2);
this.Commands.Add(MainWindow.AddRole3);
this.Commands.Add(MainWindow.AddRole4);
//this.Add(new ToolStripSeparator());
this.Commands.Add(MainWindow.AddRole5);
this.Commands.Add(MainWindow.AddRole6);
this.Commands.Add(MainWindow.AddRole7);
I did this once and used a null as my separator. From the XAML, I then styled the template to use a separator if the datacontext was null
Code behind:
this.Commands.Add(MainWindow.AddRole4);
this.Add(null);
this.Commands.Add(MainWindow.AddRole5);
XAML was something like this:
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding}" />
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
<Style.Triggers>
<DataTrigger Binding="{Binding }" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContextMenu.ItemContainerStyle>
Hope I got the syntax right - I don't have an IDE on this machine to verify the code
EDIT
Here is an example template for the context menu separator. I am putting it in ContextMenu.Resources, although you could put this anywhere you want in your application as long as the ContextMenu can access it.
<ContextMenu.Resources>
<ControlTemplate x:Key="MenuSeparatorTemplate">
<Separator />
</ControlTemplate>
</ContextMenu.Resources>
EDIT:
My first answer to this question, though it actually worked, does not follow the MVVM design principle. I am now providing an MVVM approach and leaving the original answer below for reference.
You can create a behavior to solve this problem.
XAML:
<Menu>
<MenuItem Header="_File" menu:MenuBehavior.MenuItems="{Binding Path=MenuItemViewModels, Mode=OneWay}">
</MenuItem>
</Menu>
ViewModel:
public IEnumerable<MenuItemViewModelBase> MenuItemViewModels => new List<MenuItemViewModelBase>
{
new MenuItemViewModel { Header = "Hello" },
new MenuItemSeparatorViewModel(),
new MenuItemViewModel { Header = "World" }
};
Behavior:
public class MenuBehavior
{
public static readonly DependencyProperty MenuItemsProperty =
DependencyProperty.RegisterAttached("MenuItems",
typeof(IEnumerable<MenuItemViewModelBase>), typeof(MenuBehavior),
new FrameworkPropertyMetadata(MenuItemsChanged));
public static IEnumerable<MenuItemViewModelBase> GetMenuItems(DependencyObject element)
{
if (element == null)
{
throw (new ArgumentNullException("element"));
}
return (IEnumerable<MenuItemViewModelBase>)element.GetValue(MenuItemsProperty);
}
public static void SetMenuItems(DependencyObject element, IEnumerable<MenuItemViewModelBase> value)
{
if (element == null)
{
throw (new ArgumentNullException("element"));
}
element.SetValue(MenuItemsProperty, value);
}
private static void MenuItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var menu = (MenuItem)d;
if (e.OldValue != e.NewValue)
{
menu.ItemsSource = ConvertViewModelsToFrameworkElements((IEnumerable<MenuItemViewModelBase>)e.NewValue);
}
}
private static IEnumerable<FrameworkElement> ConvertViewModelsToFrameworkElements(IEnumerable<MenuItemViewModelBase> viewModels)
{
var frameworkElementList = new List<FrameworkElement>();
foreach (var viewModel in viewModels)
{
switch (viewModel)
{
case MenuItemViewModel mi:
frameworkElementList.Add(new MenuItem
{
Header = mi.Header,
Command = mi.Command,
Icon = mi.Icon
});
break;
case MenuItemSeparatorViewModel s:
frameworkElementList.Add(new Separator());
break;
}
}
return frameworkElementList;
}
}
Classes:
public class MenuItemViewModelBase
{
}
public class MenuItemViewModel : MenuItemViewModelBase
{
public object Header { get; set; }
public ICommand Command { get; set; }
public object Icon { get; set; }
}
public class MenuItemSeparatorViewModel : MenuItemViewModelBase
{
}
Original Answer:
Or, instead of having your ContextMenu bind to a collection of commands, bind it to a collection of FrameworkElements then you can add either MenuItems or Separators directly to the collection and let the Menu control do all the templating....
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding Commands}" />
</Setter.Value>
</Setter>
</Style>
C#:
this.Commands = new ObservableCollection<FrameworkElement>();
this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole1});
this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole2});
this.Commands.Add(new MenuItem {Header = "Menuitem 3", Command = MainWindow.AddRole3});
this.Commands.Add(new MenuItem {Header = "Menuitem 4", Command = MainWindow.AddRole4});
this.Commands.Add(new Separator);
this.Commands.Add(new MenuItem {Header = "Menuitem 5", Command = MainWindow.AddRole5});
this.Commands.Add(new MenuItem {Header = "Menuitem 6", Command = MainWindow.AddRole6});
this.Commands.Add(new MenuItem {Header = "Menuitem 7", Command = MainWindow.AddRole7});
Just used this approach in my app - the separator looks better this way also.
I have modified the solution provided by Rachel above to correct the Separator style. I realize this post is old, but still one of the top results on Google. In my situation, I was using it for a Menu vs a ContextMenu, but the same should work.
XAML
<Menu ItemsSource="{Binding MenuItems}">
<Menu.Resources>
<ControlTemplate x:Key="MenuSeparatorTemplate">
<Separator>
<Separator.Style>
<Style TargetType="{x:Type Separator}" BasedOn="{StaticResource ResourceKey={x:Static MenuItem.SeparatorStyleKey}}"/>
</Separator.Style>
</Separator>
</ControlTemplate>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding MenuItemHeader}" />
<Setter Property="Command" Value="{Binding MenuItemCommand}" />
<Setter Property="CommandParameter" Value="{Binding MenuItemCommandParameter}" />
<Setter Property="ItemsSource" Value="{Binding MenuItemCollection}" />
<Style.Triggers>
<DataTrigger Binding="{Binding }" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.Resources>
</Menu>
Without Separator Style Change
With Separator Style Change
Use ItemTemplateSelector:
public class MenuItemTemplateSelector : DataTemplateSelector
{
public DataTemplate SeparatorTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var menuItem = container.GetVisualParent<MenuItem>();
if (menuItem == null)
{
throw new Exception("Unknown MenuItem type");
}
if (menuItem.DataContext == null)
{
return SeparatorTemplate;
}
return menuItem.ItemTemplate;
}
}
Xaml:
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"
ItemsSource="{Binding Path=ViewContentMenuItems}" >
<ContextMenu.ItemTemplateSelector>
<templateSelectors:MenuItemTemplateSelector>
<templateSelectors:MenuItemTemplateSelector.SeparatorTemplate>
<DataTemplate>
<Separator />
</DataTemplate>
</templateSelectors:MenuItemTemplateSelector.SeparatorTemplate>
</templateSelectors:MenuItemTemplateSelector>
</ContextMenu.ItemTemplateSelector>
</ContextMenu>
In model:
public ObservableCollection<MenuItem> ViewContentMenuItems
{
get
{
var temp = new ObservableCollection<MenuItem>();
temp.Add(null);
temp.Add(CreateFolderMenuItem);
return temp;
}
}
private MenuItem CreateFolderMenuItem
{
get
{
var createFolderMenuItem = new MenuItem()
{
Header = "New Folder",
Icon = new Image
{
Source = new BitmapImage(new Uri("/icons/folderWinCreate.png", UriKind.Relative)),
Height = 16,
Width = 16
}
};
Message.SetAttach(createFolderMenuItem, "CreateDocumentsFolder");//Caliburn example
return createFolderMenuItem;
}
}
To do this correctly for MVVM you have to define your own item interface (f.e. IMenuItem), create derived classes for Menu / ContextMenu and for MenuItem, in these classes override following virtual protected methods :
ItemsControl.PrepareContainerForItemOverride
ItemsControl.ClearContainerForItemOverride
ItemsControl.GetContainerForItemOverride
ItemsControl.IsItemItsOwnContainerOverride
Ensure that this methods create for items of type IMenuItem containers of your new derived from MenuItem type with binding all needed properties, here you can differentiate different types of IMenuItem to show normal items, separator or some thins else. For unknown types call base implementation.
Now, if you will bind ItemsSource property of your new derived from Menu/ContextMenu control with collection of IMenuItem, it will show you expected result without need to now View-stuff on ViewModel side.

WPF MVVM Dynamic SubMenu Binding Issue

I'm dynamically creating a context menu and the menu items have children.
The first time around the submenus appear, but on the second and there after only the parent menus show. The child submenu are in the collection that is bound to the context menu they just don't appear.
VMMenuItems is a property in my view model and is
ObservableCollection<MenuItemViewModel>
Every time the data in the Listview changes VMMenuItems is totally rebuilt.
A sub menu is just adding another MenuItemViewModel to an existing MenuItemViewModel's Children.
Any ideas as to how to make the submenus work every time?
The code
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}"
ItemsSource="{Binding Path=Children}">
<ContentPresenter Content="{Binding Path=MenuText}" />
</HierarchicalDataTemplate>
</Window.Resources>
<ListView.ContextMenu>
<ContextMenu ItemsSource="{Binding Path=VMMenuItems>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding MenuText}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</ListView.ContextMenu>
public class MenuItemViewModel : ViewModel
{
public MenuItemViewModel()
{
Children = new ObservableCollection<MenuItemViewModel>();
}
private string _menuText;
public string MenuText
{
get { return _menuText; }
set
{
_menuText = value;
OnPropertyChanged("MenuText");
}
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged("IsEnabled");
}
}
private ICommand _command;
public ICommand Command
{
get { return _command; }
set
{
_command = value;
OnPropertyChanged("Command");
}
}
private ObservableCollection<MenuItemViewModel> _children;
public ObservableCollection<MenuItemViewModel> Children
{
get { return _children; }
set
{
_children = value;
OnPropertyChanged("Children");
}
}
I had to not use a HierarchicalDataTemplate and put it all here in ContextMenu.ItemContainerStyle.
I'm not sure why my other way didn't work( well it worked the 1st time but not any others).
Maybe someone else could tell me why it doesn't work...
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding MenuText}"/>
<Setter Property="ItemsSource" Value="{Binding Path=Children}"/>
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding MenuText}"/>
</Style>
</ContextMenu.ItemContainerStyle>
I'm still new to this myself and I don't know for sure without testing it or exactly why, but I believe it has to do with replacing the Children collection with an entirely new collection. I think that would require rebinding the collection. It would be better for items to be added/removed from the existing collection. This would trigger the appropriate binding notifications. Right now, the binding is to a particular instance of that collection which is getting replaced on the Children.set call. Hope this helps.

Resources