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

发布于 2024-09-19 04:30:48 字数 1339 浏览 1 评论 0原文

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

我使用命令根据上下文菜单的目标执行适当的方法,在本例中是文本框。

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

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 参数保持静态,仅获取第一个控件中设置的标记值。

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

谢谢。

I have a wpf window with several text box controls. I need to apply a common style that would apply a context menu to each control and i have defined it globally as follows,

<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>

I Have used a Command to execute the appropriate method depending on the target of the context menu, which is in this case the text box.

To identify the controls uniquely, i have set the "Tag" property of each control with a unique string and i access this tag from the command parameter which is set to the target text box Control itself.

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);
        }

The problem with this is that once the command parameter gets set to a particular control,
it will not change on subsequent context menu operations when right clicked on a different control. the Command parameter remains static and gets only the tag value set in the first control.

How can i get this to work so that i can access each of the tag values of the controls using the command?

thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苍白女子 2024-09-26 04:30:48

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;
  }
}

ContextMenu is at the root of its own visual tree, so any binding using RelativeSource.FindAncestor does not go past the ContextMenu.

A work around is to use a two stage binding with the PlacementTarget property as follows,
and to analyse the object parameter in the method OnAffirmCommand(object obj) to control your behaviour. In this case the object is the actual TextBox.

Here is the context menu definition:

<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>

Here are the text boxes:

<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>

Here is the command code from a 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;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文