WPF CommandParameter 在上下文菜单中设置时未更新

Posted

技术标签:

【中文标题】WPF CommandParameter 在上下文菜单中设置时未更新【英文标题】:WPF CommandParameter not updated when set in Context Menu 【发布时间】:2011-04-11 18:08:57 【问题描述】:

我有一个带有多个文本框控件的 wpf 窗口。我需要应用一种通用样式,将上下文菜单应用于每个控件,并且我已将其全局定义如下,

<ContextMenu x:Key="textBoxMenu">
        <Separator/>
        <MenuItem Header="Affirm" 
                  Command="Binding Path=AffirmCommand" 
                  CommandParameter="Binding RelativeSource=RelativeSource AncestorType=x:Type TextBox,AncestorLevel=1"/>                      
    </ContextMenu>

    <Style TargetType="x:Type TextBox" x:Key="TextBoxAffirmMenuStyle">
        <Setter Property="ContextMenu" Value="DynamicResource textBoxMenu" />
    </Style>

我已经根据上下文菜单的目标(在本例中为文本框)使用命令来执行适当的方法。

为了唯一标识控件,我为每个控件的“Tag”属性设置了一个唯一的字符串,并从设置为目标文本框控件本身的命令参数访问此标记。

private bool CanAffirmExecute(object param)
        

            string columnName = (param as FrameworkElement).Tag as string;

            if (this.CheckIsAffirmed(columnName))
                return true;
            else
                return false;
        

private void AffirmExecute(object param)
        

            string columnName = (param as FrameworkElement).Tag as string;

            this.Affirm(columnName);
        

这样做的问题是,一旦命令参数设置为特定控件, 当右键单击不同的控件时,它不会在随后的上下文菜单操作中改变。 Command 参数保持静态,仅获取第一个控件中设置的标记值。

我怎样才能让它工作,以便我可以使用命令访问控件的每个标记值?

谢谢。

【问题讨论】:

【参考方案1】:

ContextMenu 位于其自己的可视化树的根部,因此任何使用 RelativeSource.FindAncestor 的绑定都不会越过 ContextMenu。

一种解决方法是使用具有 PlacementTarget 属性的两阶段绑定,如下所示, 并分析方法 OnAffirmCommand(object obj) 中的对象参数以控制您的行为。在这种情况下,对象是实际的 TextBox。

这里是上下文菜单定义:

<Window.Resources>
  <ContextMenu x:Key="textBoxMenu">
    <Separator/>
    <MenuItem Header="Affirm"  
          Command="Binding Path=AffirmCommand"  
          CommandParameter="Binding PlacementTarget.Tag, 
                                     RelativeSource=RelativeSource FindAncestor, 
                                     AncestorType=x:Type ContextMenu"/>
   </ContextMenu>

   <Style TargetType="x:Type TextBox" x:Key="TextBoxAffirmMenuStyle">
       <Setter Property="ContextMenu" Value="StaticResource textBoxMenu" />
   </Style>
</Window.Resources>

这里是文本框:

<Grid>
    <Grid.RowDefinitions>
       <RowDefinition/>
       <RowDefinition/>
       <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBox Grid.Row="0" ContextMenu="StaticResource textBoxMenu" Tag="Binding RelativeSource=RelativeSource Self" Text="text in box 1"/>
    <TextBox Grid.Row="1" ContextMenu="StaticResource textBoxMenu" Tag="Binding RelativeSource=RelativeSource Self" Text="text in box 2"/>
     <TextBox Grid.Row="2" ContextMenu="StaticResource textBoxMenu" Tag="Binding RelativeSource=RelativeSource Self" Text="text in box 3"/>
</Grid>

这是来自 ViewModel 的命令代码:

public class MainViewModel : ViewModelBase

  public ICommand AffirmCommand  get; set; 

  public MainViewModel()
  
     AffirmCommand = new DelegateCommand<object>(OnAffirmCommand, CanAffirmCommand);
  

  private void OnAffirmCommand(object obj)
  
  

  private bool CanAffirmCommand(object obj)
  
     return true;
  

【讨论】:

谢谢赞博尼。我以稍微不同的方式实现了这一点。似乎命令参数只绑定一次。我所做的就是像您一样将 CommandTarget 绑定到放置目标,并将 CommandTarget 绑定到 CommandParameter。由于每次打开上下文菜单时都会更新 CommandTarget,因此命令参数返回目标控件。我认为您的建议与这种方法有些相似。 感谢您的评论,请在以后发布您的代码/解决方案作为其他人的答案。

以上是关于WPF CommandParameter 在上下文菜单中设置时未更新的主要内容,如果未能解决你的问题,请参考以下文章

WPF CommandParameter 绑定未更新

代码中无法识别 WPF CommandParameter

理解WPF Binding CommandParameter =“{Binding}”

使用 WPF + MVVM 中的 Command + CommandParameter 删除列表视图中的行

WPF CommandParameter 在第一次调用 CanExecute 时为 NULL

WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参