WPF: элементы меню связывают только параметры команды

Я заметил это несколько раз при использовании меню с командами, они не очень динамичны, проверьте это. Я создаю меню из коллекции цветов, я использую его для цветной колонки в datagrid. В любом случае, когда я сначала вывожу меню (его контекстное меню), происходит привязка параметра команды и привязывается к столбцу, в котором было открыто контекстное меню. Однако в следующий раз, когда я его подниму, кажется, что wpf кэширует меню и не перегружает параметр команды. поэтому я могу установить цвет только в начальном столбце, в котором появилось контекстное меню.

У меня обошла эту ситуацию в прошлом, сделав меню полностью динамичным и уничтожив коллекцию, когда меню закрыто и заставляет перестроить при следующем открытии, мне не нравится этот хак. кто-нибудь получил лучший способ?

    <MenuItem
       Header="Colour"
       ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColumnColourCollection}"
       ItemTemplate="{StaticResource colourHeader}" >
       <MenuItem.Icon>
          <Image
             Source="{StaticResource ColumnShowIcon16}" />
       </MenuItem.Icon>
       <MenuItem.ItemContainerStyle>
          <Style
             TargetType="MenuItem"
             BasedOn="{StaticResource systemMenuItemStyle}">
             <!--Warning dont change the order of the following two setters
                                otherwise the command parameter gets set after the command fires,
                                not mush use eh?-->
             <Setter
                Property="CommandParameter">
                <Setter.Value>
                   <MultiBinding>
                      <MultiBinding.Converter>
                         <local:ColumnAndColourMultiConverter/>
                      </MultiBinding.Converter>
                      <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGridColumnHeader}}" Path="Column"/>
                      <Binding Path="."/>
                   </MultiBinding>
                </Setter.Value>
             </Setter>
             <Setter
                Property="Command"
                Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColourColumnCommand}" />
          </Style>
       </MenuItem.ItemContainerStyle>
    </MenuItem>

Ответ 1

Проблема заключается в том, что ContextMenu по-видимому, корень собственного визуального дерева. Я где-то читал, что он берет datacontext его родительский элемент, но только один раз при загрузке, поэтому if родители datacontext меняют элементы меню. (к сожалению, я не могу найти ссылку для этого права)

Я столкнулся с этой проблемой раньше, и то, что я сделал, было использовать Josh Smith Virtual Branch Pattern. Это довольно технически, но статья помогла мне очень хорошо понять, что происходит с этим визуальным деревом.

По существу вы создаете этот мост, который привязывается к представлению datacontext. Мост создается как статический ресурс, что позволяет вам привязываться к нему из контекстного меню, даже если оно находится вне визуального дерева.

Добавьте это в свой xaml:

<Window.Resources>
   <!-- This is the "root node" in the virtual branch
   attached to the logical tree. It has its
   DataContext set by the Binding applied to the
   Window DataContext property. -->
   <FrameworkElement x:Key="DataContextBridge" />
</Window.Resources>

<Window.DataContext>
   <!-- This Binding sets the DataContext on the "root node"
   of the virtual logical tree branch.  This Binding
   must be applied to the DataContext of the element
   which is actually assigned the data context value. -->
   <Binding
    Mode="OneWayToSource"
    Path="DataContext"
    Source="{StaticResource DataContextBridge}"
   />
</Window.DataContext>

Это мост, о котором я говорил. Он берет datacontext и __pushes it_ к моменту datacontext мостов, который (как я сказал ранее) статический ресурс.

Затем вы просто это примените к контекстному контексту datacontext:

 DataContext="{Binding
               Source={StaticResource DataContextBridge},
               Path=DataContext}"

Теперь выбросьте все относительные пути и т.д. и используйте регулярное связывание внутри элементов меню, и все должно быть в порядке. Datacontext будет обновляться, как обычно.

Только одно примечание:

Очевидно, вам придется иметь какое-то свойство в datacontext, чтобы определить, какую команду использовать, но я уверен, что вы можете понять это. Это решение просто связано с тем, как контекстное меню не обновляет