0

I've created RichTextBox control with Menu at the top side of Window. The MenuItems call Commands - It works perfectly. Then I try to create ContextMenu in the RichTextBox and want to call the same commands like in MenuItems. So that, I bind the ContextMenu in the same way like MenuItems but it throws the NullReferenceException.

What can be the reason. How should I bind the Command to the ContextMenu??

Below are the parts of my code

MenuItem code:

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

RichTextBox code:

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

That command which I want to execute:

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

The method which I call within the Command:

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

And The RelayCommand class

   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);
         }
     }
M_K
  • 109
  • 1
  • 15
  • https://stackoverflow.com/questions/3668654/relativesource-binding-from-a-tooltip-or-contextmenu/3668699#3668699 – Rekshino Mar 31 '18 at 11:18

2 Answers2

1

I have a solution which I think works, binding to the PlacementTarget of the context menu.

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

However, the XAML designer underlines the CommandPamameter and shows the tooltip "RelativeSource is not in FindAncestor mode". Nevertheless it seems to work.

Edit

Adding Mode=FindAncestor seems to fix the error message. I don't know if it has any effect on the behavior.

<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>
Phil Jollans
  • 3,605
  • 2
  • 37
  • 50
0

This is probably because the binding can't find your text box.

This happens because the ContextMenu is not part of the visual tree so can't find your Text Box for the CommandParameter. The best way around this is to not use the CommandParameter at all, but use a variable in your ViewModel (such as SelectedTextBox).

However, you can get a working (but slightly uglier) solution by naming your ContextMenu and setting its NameScope in the View's constructor:

NameScope.SetNameScope(myContextMenu, this);

This should then work correctly.

J R
  • 146
  • 1
  • 9
  • Thank you for the respond but I do the app according with MVVM and don't want to use any code-behind – M_K Mar 31 '18 at 21:22