【问题标题】:WPF CommandParameter not updated when set in Context MenuWPF CommandParameter 在上下文菜单中设置时未更新
【发布时间】: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 参数保持静态,仅获取第一个控件中设置的标记值。

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

谢谢。

【问题讨论】:

    标签: wpf contextmenu 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,因此命令参数返回目标控件。我认为您的建议与这种方法有些相似。
    • 感谢您的评论,请在以后发布您的代码/解决方案作为其他人的答案。
    猜你喜欢
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多