none
Command to handle the double click on a Grid Control

    Question

  • Hello,

    In my application, I am adding multiple 'Grid' controls inside the 'Canvas' control. Each of this 'Grid' control is binded to a ViewModel object (say 'GridInformationViewModel') which is having a command saying 'ShowPropertiesWindow' to show a new window for respective Grid control. Grids are dynamically getting added in the Canvas control for each the new ViewModel 'GridInformationViewModel'.

    How i can bind this command for each of the 'Grid'?

    Thanks,

    IamHuM

    Saturday, April 18, 2015 8:19 AM

Answers

  • Personally, I prefer the simplicity of the MouseBinding.

        <Grid Background="White">
            <Grid.InputBindings>
                <MouseBinding Gesture="LeftDoubleClick" Command="{Binding ShowPropertiesWindow}" />
            </Grid.InputBindings>
        </Grid>
    Which also allows you to use double click rather than just single click.

    I set the datacontext of my grid to an instance of a vm:

        public class GridVM : ViewModelBase
        {
    
            public RelayCommand ShowPropertiesWindow { get; set; }
            public GridVM()
            {
                ShowPropertiesWindow = new RelayCommand(ShowPropertiesWindowExecute);
            }
            private void ShowPropertiesWindowExecute()
            {  // Break point here
    
            }
        }
    Double click the grid and my break point in  ShowPropertiesWindowExecute() is hit.


    Hope that helps.

    Technet articles: Uneventful MVVM; All my Technet Articles

    Tuesday, April 21, 2015 7:39 AM
    Moderator
  • If the Grid elements are programmatically added to the Canvas the easiest way is to just handle the appropriate event and invoke the command from the event handler:

                Grid grid = new Grid();
         grid.Background = Brushes.Transparent; //set a background for mouse event to get fired
                grid.MouseLeftButtonDown += (ss, ee) =>
                {
                    GridInformationViewModel vm = grid.DataContext as GridInformationViewModel;
                    vm.ShowPropertiesWindowCommand.Execute(null);
                };
    canvas.Children.Add(grid);

    The Grid has no MouseDoubleClick event but you can put it in a UserControl, add the UserControl to the Canvas and handle the MouseDoubleClick event for the UserControl: http://www.dev102.com/2008/05/14/how-to-add-a-mousedoubleclick-event-to-any-wpf-control/.

    Note that his approach does not break the MVVM pattern since you are just invoking the command as a result of a click just as you would do from the XAML markup.

    If you want to bind to the command from the XAML markup you could use an interaction trigger:

    <Grid Background="Transparent">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown" >
                        <i:InvokeCommandAction Command="{Binding ShowPropertiesWindowCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
    ...
            </Grid>

    You will have to add a reference to System.Windows.Interactivity.dll which is part of the Expression Blend SDK which you can download from here: http://www.microsoft.com/en-us/download/details.aspx?id=10801. Please refer to my blog post about how to handle events in MVVM for more information: http://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question.

    Saturday, April 18, 2015 11:16 AM

All replies

  • Yes.

    Although a popup or contextmenu are something to consider.

    A popup is in the same data context as it's parent.

    If I just show you code:

    <MouseBinding Gesture="LeftDoubleClick" Command="YourCommand" />

    Note that showing a new view is kind of a view responsibility so maybe this ought to just be an event instead and code behind opens the window.

    Which way to go depends on what your command in the vm would add to the process.


    Hope that helps.

    Technet articles: Uneventful MVVM; All my Technet Articles


    Saturday, April 18, 2015 9:39 AM
    Moderator
  • If the Grid elements are programmatically added to the Canvas the easiest way is to just handle the appropriate event and invoke the command from the event handler:

                Grid grid = new Grid();
         grid.Background = Brushes.Transparent; //set a background for mouse event to get fired
                grid.MouseLeftButtonDown += (ss, ee) =>
                {
                    GridInformationViewModel vm = grid.DataContext as GridInformationViewModel;
                    vm.ShowPropertiesWindowCommand.Execute(null);
                };
    canvas.Children.Add(grid);

    The Grid has no MouseDoubleClick event but you can put it in a UserControl, add the UserControl to the Canvas and handle the MouseDoubleClick event for the UserControl: http://www.dev102.com/2008/05/14/how-to-add-a-mousedoubleclick-event-to-any-wpf-control/.

    Note that his approach does not break the MVVM pattern since you are just invoking the command as a result of a click just as you would do from the XAML markup.

    If you want to bind to the command from the XAML markup you could use an interaction trigger:

    <Grid Background="Transparent">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown" >
                        <i:InvokeCommandAction Command="{Binding ShowPropertiesWindowCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
    ...
            </Grid>

    You will have to add a reference to System.Windows.Interactivity.dll which is part of the Expression Blend SDK which you can download from here: http://www.microsoft.com/en-us/download/details.aspx?id=10801. Please refer to my blog post about how to handle events in MVVM for more information: http://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question.

    Saturday, April 18, 2015 11:16 AM
  • Thanks all for your replies.

    I tried adding code as per your suggestion. But i am not able to get the command working using the 'Interaction.Triggers'. Here is the code which i am using. Binding is working properly for this code only the command is not getting fired for the Grid control 'SelectedGrid'. Can you please help me to find the problem in my code.

    <UserControl x:Class="CustomShapesDesigner.Controls.UserControlCustomShapePanel"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                 d:DesignHeight="300" d:DesignWidth="300">
    
        <Border BorderBrush="Purple" BorderThickness="5" >
            <Grid Name="gridParentItems" Loaded="grid1_Loaded" >
                <ScrollViewer Name="ScrollViewer"
                              Background="Black" HorizontalScrollBarVisibility="Auto"
                              VerticalScrollBarVisibility="Auto" Loaded="DesignerScrollViewer_Loaded" >
    
                    <ItemsControl ItemsSource="{Binding CustomShapeItems}"
                                    ItemContainerStyleSelector="{x:Static designerHelpers:DesignerItemsControlItemStyleSelector.Instance}">
                        <ItemsControl.Resources>
                            <Style x:Key="customShapeItemStyle" TargetType="{x:Type ContentPresenter}">
                                
                                <Setter Property="Width" Value="200"/>
                                <Setter Property="Height" Value="200" />
                                <Setter Property="SnapsToDevicePixels" Value="True" />
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
    
                                            <Grid x:Name="selectedGrid" Loaded="selectedGrid_Loaded" 
                                                  MouseLeftButtonDown="selectedGrid_MouseLeftButtonDown" MouseLeftButtonUp="selectedGrid_MouseLeftButtonUp" >
                                                <i:Interaction.Triggers>
                                                        <i:EventTrigger EventName="MouseLeftButtonDown" >
                                                            <i:InvokeCommandAction Command="{Binding ShowElementPropertiesCommand1}" CommandParameter="{Binding}" />
                                                        </i:EventTrigger>
                                                    </i:Interaction.Triggers>
                                                
                                                <ContentPresenter x:Name="PART_ContentPresenter"
                                                                    HorizontalAlignment="Stretch"
                                                                    VerticalAlignment="Stretch"
                                                                    Content="{TemplateBinding Content}" />
                                                <Border BorderThickness="3" Margin="5" CornerRadius="3" BorderBrush="Aqua">
                                                	<Grid Margin="10" x:Name="PART_ConnectorDecorator"
                                                      MouseLeftButtonDown="selectedGrid_MouseLeftButtonDown" MouseLeftButtonUp="selectedGrid_MouseLeftButtonUp" >
                                                	</Grid>
                                                </Border>
                                            </Grid>
                                            
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </ItemsControl.Resources>
                    </ItemsControl>
                </ScrollViewer>
            </Grid>
        </Border>
    </UserControl>
    

    Thanks,

    IamHuM

    Monday, April 20, 2015 7:57 PM
  • As Magnus has said, you need the Grid to have some kind of background, even if it's transparent.

    noorbakhsh حميد نوربخش

    Monday, April 20, 2015 9:51 PM
  • Personally, I prefer the simplicity of the MouseBinding.

        <Grid Background="White">
            <Grid.InputBindings>
                <MouseBinding Gesture="LeftDoubleClick" Command="{Binding ShowPropertiesWindow}" />
            </Grid.InputBindings>
        </Grid>
    Which also allows you to use double click rather than just single click.

    I set the datacontext of my grid to an instance of a vm:

        public class GridVM : ViewModelBase
        {
    
            public RelayCommand ShowPropertiesWindow { get; set; }
            public GridVM()
            {
                ShowPropertiesWindow = new RelayCommand(ShowPropertiesWindowExecute);
            }
            private void ShowPropertiesWindowExecute()
            {  // Break point here
    
            }
        }
    Double click the grid and my break point in  ShowPropertiesWindowExecute() is hit.


    Hope that helps.

    Technet articles: Uneventful MVVM; All my Technet Articles

    Tuesday, April 21, 2015 7:39 AM
    Moderator
  • As I pointed out in my first reply and as noorbakhsh also suggests, you must set a Backgrond for the Grid for the mouse events to get raised:

      <Grid Background="Transparent" x:Name="selectedGrid" Loaded="selectedGrid_Loaded" 
                                                  MouseLeftButtonDown="selectedGrid_MouseLeftButtonDown" MouseLeftButtonUp="selectedGrid_MouseLeftButtonUp" >
                                                <i:Interaction.Triggers>
                                                        <i:EventTrigger EventName="MouseLeftButtonDown" >
                                                            <i:InvokeCommandAction Command="{Binding ShowElementPropertiesCommand1}" CommandParameter="{Binding}" />
                                                        </i:EventTrigger>
                                                    </i:Interaction.Triggers>

     

    If you don't set a Background the area is considered to belong to the parent window and that's why your event handler doesn't get invoked. 

    Please remember to mark all posts that are part of the solution to your issue as answer to close the thread and then start a new thread if you have a new question. Please don't post several questions in the same thread.

    Tuesday, April 21, 2015 8:12 AM