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

时间:2010-09-13 16:01:06

标签: wpf contextmenu command

我有一个带有几个文本框控件的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>

我已经使用Command来执行适当的方法,具体取决于上下文菜单的目标,在本例中是文本框。

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

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 个答案:

答案 0 :(得分:0)

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

解决方法是使用与PlacementTarget属性的两阶段绑定,如下所示, 并分析方法OnAffirmCommand(object obj)中的object参数来控制你的行为。在这种情况下,对象是实际的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;
  }
}