none
DataGrid and context menu: losing focus RRS feed

  • Question

  • Hi group, I've a problem with the WPF toolkit DataGrid: I have a DataGrid bound to some data, with an editable column represented by DataGridTextBox. Everything works fine, except for the fact that if the user right-clicks in the text box when editing the default context menu for the TextBox pops up as expected with Copy/Cut/Paste, but all the commands are grayed out (disabled) because the right-click causes the cell to lose focus and thus terminates the edit. Is there a workaround for this?
    Thanks to all!
    Tuesday, November 10, 2009 6:14 PM

Answers

  • Hi Naftis,

    I performed a test based on your description and did reproduce the problem on my side.

    It seems that when the ContextMenu pops up, the DataGridTexCell loses keyboard focus and then ends editing.

    A workaround is to cancel cell editing in this case. To do this, use a DataGridTemplateColumn instead of DataGridTextColumn, thus we can subscribe the mouse rightclick down event of the hosted editing control. We can set a variable of type bool to true when the user right-clicks on the hosted editing control. When the CellEditEnding event of the DataGrid is raised, cancel the edit ending operation if the variable is true.

    The following is a complete sample.

    XAML

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
      <Window.Resources>
          
          </Window.Resources>

    <my:DataGrid  Name="dataGrid1" DataContext="{StaticResource people}" ItemsSource="{Binding}" AutoGenerateColumns="false"
          CellEditEnding="dataGrid1_CellEditEnding">
                <my:DataGrid.Columns>
                    <my:DataGridTemplateColumn Header="Name">

                       <my:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                       </my:DataGridTemplateCoumn.CellTemplate>

                       <my:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                               <TextBox Text="{Binding Name}" BorderThickness="0" PreviewMouseRightButtonDown = "TextBox_PreviewMouseRightButtonDown"/>
                            </DataTemplate>
                       </my:DataGridTemplateColumn.CellEditingTemplate>
                     </my:DataGridTemplateColumn>
                </my:DataGrid.Columns>
            </my:DataGrid>
    </Window>

    code behind
     public partial class Window1 : Window
     {  
         bool rightclicked = false;

         public Window1()
         {
             InitializeComponent();     
         }
         void dataGrid1_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
         {
             if (rightclicked)
             {
                 e.Cancel = true;
                 rightclicked = false;
             }           
         }
         
         private void TextBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
         {
              rightclicked = true;
         }
      }

      public class Person:INotifyPropertyChanged
      {      
              
            private string name;
            public string Name { get { return name; }
                set { name = value;
                OnPropertyChanged("Name");
                }
            }
                 
            private void OnPropertyChanged(string propname)
            {
                if (propertychanged != null)
                {
                    propertychanged(this, new PropertyChangedEventArgs(propname));
                }
            }
            private PropertyChangedEventHandler propertychanged;
            event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
            {
                add { propertychanged += value; }
                remove { propertychanged -= value; }
            }
        }
        public class People : ObservableCollection<Person>
        { }

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Naftis Friday, November 13, 2009 5:34 PM
    • Edited by Linda Liu Friday, December 11, 2009 9:07 AM
    Thursday, November 12, 2009 8:27 AM

All replies

  • Hi Naftis,

    I performed a test based on your description and did reproduce the problem on my side.

    It seems that when the ContextMenu pops up, the DataGridTexCell loses keyboard focus and then ends editing.

    A workaround is to cancel cell editing in this case. To do this, use a DataGridTemplateColumn instead of DataGridTextColumn, thus we can subscribe the mouse rightclick down event of the hosted editing control. We can set a variable of type bool to true when the user right-clicks on the hosted editing control. When the CellEditEnding event of the DataGrid is raised, cancel the edit ending operation if the variable is true.

    The following is a complete sample.

    XAML

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
      <Window.Resources>
          
          </Window.Resources>

    <my:DataGrid  Name="dataGrid1" DataContext="{StaticResource people}" ItemsSource="{Binding}" AutoGenerateColumns="false"
          CellEditEnding="dataGrid1_CellEditEnding">
                <my:DataGrid.Columns>
                    <my:DataGridTemplateColumn Header="Name">

                       <my:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                       </my:DataGridTemplateCoumn.CellTemplate>

                       <my:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                               <TextBox Text="{Binding Name}" BorderThickness="0" PreviewMouseRightButtonDown = "TextBox_PreviewMouseRightButtonDown"/>
                            </DataTemplate>
                       </my:DataGridTemplateColumn.CellEditingTemplate>
                     </my:DataGridTemplateColumn>
                </my:DataGrid.Columns>
            </my:DataGrid>
    </Window>

    code behind
     public partial class Window1 : Window
     {  
         bool rightclicked = false;

         public Window1()
         {
             InitializeComponent();     
         }
         void dataGrid1_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
         {
             if (rightclicked)
             {
                 e.Cancel = true;
                 rightclicked = false;
             }           
         }
         
         private void TextBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
         {
              rightclicked = true;
         }
      }

      public class Person:INotifyPropertyChanged
      {      
              
            private string name;
            public string Name { get { return name; }
                set { name = value;
                OnPropertyChanged("Name");
                }
            }
                 
            private void OnPropertyChanged(string propname)
            {
                if (propertychanged != null)
                {
                    propertychanged(this, new PropertyChangedEventArgs(propname));
                }
            }
            private PropertyChangedEventHandler propertychanged;
            event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
            {
                add { propertychanged += value; }
                remove { propertychanged -= value; }
            }
        }
        public class People : ObservableCollection<Person>
        { }

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Naftis Friday, November 13, 2009 5:34 PM
    • Edited by Linda Liu Friday, December 11, 2009 9:07 AM
    Thursday, November 12, 2009 8:27 AM
  • Thank you very much Linda, this workaround works fine!

    (Anyway, hope some good guy at MS will release an updated version of the Wpf Toolkit...:)
    Friday, November 13, 2009 5:34 PM