2010-09-13 59 views
1

我有一个带有几个文本框控件的wpf窗口。我需要应用将适用于一个上下文菜单到每个控制的一种常用的风格,我也如下全局定义它,WPF CommandParameter在上下文菜单中设置时未更新

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

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

谢谢。

回答

0

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

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

这里是上下文菜单定义:

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

感谢赞博尼。我用稍微不同的方式实现了这一点。看起来命令参数只绑定一次。我所做的是将CommandTarget绑定到展示位置目标,并将CommandTarget绑定到CommandParameter。由于每次打开上下文菜单时都会更新CommandTarget,因此命令参数会返回目标控件。我认为你所建议的是一些类似于这种方法的东西。 – Deshan 2010-09-16 05:22:56

+0

感谢您的评论,请将您的代码/解决方案作为未来其他人的答案。 – Zamboni 2010-09-16 16:47:03