【问题标题】:WPF How to bind a command to the ContextMenu in RichTextBox?WPF 如何将命令绑定到 RichTextBox 中的 ContextMenu?
【发布时间】:2018-03-31 10:13:35
【问题描述】:

我创建了 RichTextBox 控件,在 Window 的顶部带有 MenuMenuItems 调用命令 - 完美运行。然后我尝试在 RichTextBox 中创建 ContextMenu 并希望调用与 MenuItems 中相同的命令。 因此,我以与 MenuItems 相同的方式绑定 ContextMenu,但它会抛出 NullReferenceException

可能是什么原因。我应该如何将命令绑定到 ContextMenu?

以下是我的部分代码

菜单项代码:

<MenuItem Name="FontSettings" Header="Font settings" Command="{Binding FontSettingsCommand}" CommandParameter="{Binding ElementName=MainRichTbx}" />

富文本框代码:

  <RichTextBox Name="MainRichTbx" TextBlock.LineHeight="0.1" Margin="5" >
             <RichTextBox.ContextMenu>
                 <ContextMenu>
                     <MenuItem Header="Font settings" Command="{Binding FontSettingsCommand}" CommandParameter="{Binding ElementName=MainRichTbx}" />
                 </ContextMenu>
             </RichTextBox.ContextMenu> 
   </RichTextBox>

我要执行的那个命令:

  private ICommand _FontSettingsCommand;
          public ICommand FontSettingsCommand
          {
              get
              {
                  if (_FontSettingsCommand == null)
                  {
                      _FontSettingsCommand = new RelayCommand(
                          argument => EditorFormat.SetFont(argument),
                          argument => true
                          );
                  }
                  return _FontSettingsCommand;
              }
          }

我在命令中调用的方法:

public static void SetFont(object control)
    {
        FontDialog fontDialog = new FontDialog();

        if (fontDialog.ShowDialog() == DialogResult.OK)
        {
            (control as System.Windows.Controls.RichTextBox).FontFamily = new System.Windows.Media.FontFamily(fontDialog.Font.Name);
            (control as System.Windows.Controls.RichTextBox).FontSize = fontDialog.Font.Size;
            (control as System.Windows.Controls.RichTextBox).FontStyle = fontDialog.Font.Italic ? FontStyles.Italic : FontStyles.Normal;
            (control as System.Windows.Controls.RichTextBox).FontWeight = fontDialog.Font.Bold ? FontWeights.Bold : FontWeights.Regular;
        }
    }

还有 RelayCommand 类

   class RelayCommand : ICommand
     {
         private readonly Action<object> _Execute;
         private readonly Func<object, bool> _CanExecute;

         public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
         {
             if (execute == null) throw new ArgumentNullException("execute");
             _Execute = execute;
             _CanExecute = canExecute;
         }

         public bool CanExecute(object parameter)
         {
             return _CanExecute == null ? true : _CanExecute(parameter);
         }

         public event EventHandler CanExecuteChanged
         {
             add
             {
                 if (_CanExecute != null) CommandManager.RequerySuggested += value;
             }
             remove
             {
                 if (_CanExecute != null) CommandManager.RequerySuggested -= value;
             }
         }

         public void Execute(object parameter)
         {
             _Execute(parameter);
         }
     }

【问题讨论】:

标签: wpf binding command contextmenu richtextbox


【解决方案1】:

我有一个我认为可行的解决方案,绑定到上下文菜单的 PlacementTarget。

<RichTextBox Name="MainRichTbx" TextBlock.LineHeight="0.1" Margin="5" >
  <RichTextBox.ContextMenu>
    <ContextMenu>
      <MenuItem Header="Font settings"
                Command="{Binding FontSettingsCommand}"
                CommandParameter="{Binding  RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}" />
    </ContextMenu>
  </RichTextBox.ContextMenu>
</RichTextBox>

但是,XAML 设计器在 CommandPamameter 下划线并显示工具提示“RelativeSource 未处于 FindAncestor 模式”。尽管如此,它似乎工作。

编辑

Adding Mode=FindAncestor 似乎修复了错误消息。不知道对行为有没有影响。

<RichTextBox Name="MainRichTbx" TextBlock.LineHeight="0.1" Margin="5" >
  <RichTextBox.ContextMenu>
    <ContextMenu>
      <MenuItem Header="Font settings"
                Command="{Binding FontSettingsCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}" />
    </ContextMenu>
  </RichTextBox.ContextMenu>
</RichTextBox>

【讨论】:

    【解决方案2】:

    这可能是因为绑定找不到您的文本框。

    发生这种情况是因为 ContextMenu 不是可视化树的一部分,因此无法找到 CommandParameter 的文本框。 解决此问题的最佳方法是根本不使用 CommandParameter,而是在 ViewModel 中使用变量(例如 SelectedTextBox)。

    但是,您可以通过命名 ContextMenu 并在 View 的构造函数中设置其 NameScope 来获得有效(但略显丑陋)的解决方案:

    NameScope.SetNameScope(myContextMenu, this);
    

    这应该可以正常工作。

    【讨论】:

    • 感谢您的回复,但我根据 MVVM 执行应用程序,不想使用任何代码隐藏
    猜你喜欢
    • 1970-01-01
    • 2011-04-04
    • 2020-03-10
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    相关资源
    最近更新 更多