In WPF, in Xaml markup, there is a binding to data and to a dynamic dictionary:

<MenuItem Header="{DynamicResource menu_File}" ItemsSource="{Binding Path=FileCommands}"> <MenuItem.ItemTemplate> <DataTemplate> <MenuItem Header="{Path=DisplayName}" Command="{Binding Path=Command}"/> </DataTemplate> </MenuItem.ItemTemplate> </MenuItem> 

The code above works correctly; The menu name is taken from the dynamic dictionary by the menu_file key, the menu items with the display name DisplayName from the FileCommands collection are FileCommands correctly and the Command is executed.

My question is: is it possible to use the DisplayName as a key to access the dynamic collection?

The fact is that the above dictionaries are used to change the interface language on the fly. And if for the menu Header="{DynamicResource menu_File}" language changes, then the submenu needs a forced update. Tried the following options:

 <MenuItem Header="{DynamicResource DisplayName}"/> <MenuItem Header="{DynamicResource ResourceKey={Path=DisplayName}}"/> <MenuItem Header="{DynamicResource ResourceKey=DisplayName}"/> 

and all sorts of other options, but I received nothing except errors. I myself am just starting to learn C # and WPF and I apologize for a possibly stupid question.

    1 answer 1

    The question is really good.

    So just will not work. In order to bind to the data from the VM, and so that it can be updated, you must put a key for the DynamicResource in the VM. (This is how I understand you did.)

    Now you need to bind on this key. There are several ways, the general meaning of which is to tie the key somewhere, and to change it, change the Dynamic Resource binding.

    For example, you can. Let's set auxiliary class:

     static class ResourceKeyBinding { // стандартное attached property ResourceKey public static object GetResourceKey(DependencyObject obj) => obj.GetValue(ResourceKeyProperty); public static void SetResourceKey(DependencyObject obj, object value) => obj.SetValue(ResourceKeyProperty, value); public static readonly DependencyProperty ResourceKeyProperty = DependencyProperty.RegisterAttached( "ResourceKey", typeof(object), typeof(ResourceKeyBinding), // callback при изменении значения ResourceKey new PropertyMetadata(OnResourceKeyChanged)); // стандартное attached property ResourceValue public static object GetResourceValue(DependencyObject obj) => obj.GetValue(ResourceValueProperty); public static void SetResourceValue(DependencyObject obj, object value) => obj.SetValue(ResourceValueProperty, value); public static readonly DependencyProperty ResourceValueProperty = DependencyProperty.RegisterAttached( "ResourceValue", typeof(object), typeof(ResourceKeyBinding)); // это будет вызвано при изменении значения ResourceKey: static void OnResourceKeyChanged( DependencyObject self, DependencyPropertyChangedEventArgs e) { // SetResourceReference устанавливает dynamic resource-привязку ((FrameworkElement)self).SetResourceReference(ResourceValueProperty, e.NewValue); } } 

    Use this:

     <MenuItem Command="{Binding Path=Command}" local:ResourceKeyBinding.ResourceKey="{Binding Path=DisplayName}" Header="{Binding Path=(local:ResourceKeyBinding.ResourceValue), RelativeSource={RelativeSource Self}}" /> 

    Explanation: We added two attached property: ResourceKeyBinding.ResourceKey and ResourceKeyBinding.ResourceValue . First tied via Binding to VM. On changing the first to the second, set the DynamicResource with the key equal to the current value. Now Header bound to this second attached property via Binding .


    In principle, it would be possible to simplify the code, costing only one attached property:

     static class ResourceKeyBinding { // standard attached property ResourceKey public static object GetResourceKey(DependencyObject obj) => obj.GetValue(ResourceKeyProperty); public static void SetResourceKey(DependencyObject obj, object value) => obj.SetValue(ResourceKeyProperty, value); public static readonly DependencyProperty ResourceKeyProperty = DependencyProperty.RegisterAttached( "ResourceKey", typeof(object), typeof(ResourceKeyBinding), new PropertyMetadata((d, e) => ((FrameworkElement)d).SetResourceReference( MenuItem.HeaderProperty, e.NewValue))); } 

    and using just like

     <MenuItem Command="{Binding Path=Command}" local:ResourceKeyBinding.ResourceKey="{Binding Path=DisplayName}"/> 

    But such a solution would only work with MenuItem , and you probably need to localize other types of items.

    • Thank you very much for a more than a detailed answer! The solution you proposed completely solved the described problem, but another one arose related to incorrect display of the MenuItem . I am new to StackOverflow, but it seems to me that the difficulties encountered are beyond the scope of this issue. So I created a new question here . - XelaNimed