Forums

MouseBinding doesn't work
Last Post 02 Apr 2016 03:29 AM by A T. 9 Replies.
Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
A TUser is Offline
New Member
New Member
Posts:34


--
20 Mar 2016 08:44 PM
    Hi.

    I have a DataGrid, and I've tried to bind a command to a double click, but it doesn't work, nothing happens when I double click on one of the grid's rows. When I bind the same command to the Enter key, it works perfectly:

    <DataGrid x:Name="dg1" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" >
        <DataGrid.InputBindings>
            <MouseBinding MouseAction="LeftDoubleClick"  Command="{Binding MyCommand}" CommandParameter="Add" />
            <KeyBinding Key="Enter" Command="{Binding MyCommand}" CommandParameter="Add" />
        </DataGrid.InputBindings>
        ...
    </DataGrid>
    


    Is it a bug or I am doing something wrong?
    Filip DušekUser is Offline
    Advanced Member
    Advanced Member
    Posts:676


    --
    20 Mar 2016 09:51 PM
    I see. I know that I do double click check on DataGrid with locator pattern, but don't remember why. I will check that tomorrow.
    Filip DušekUser is Offline
    Advanced Member
    Advanced Member
    Posts:676


    --
    21 Mar 2016 05:42 PM
    OK, I did few tests and it's working fine, but you have to understand that if you are clicking on actual row/header any click event will get "eaten" by controls and not fired by actual DataGrid. Do you want to fire up double click event by clicking actual row?
    A TUser is Offline
    New Member
    New Member
    Posts:34


    --
    21 Mar 2016 11:39 PM

    Do you want to fire up double click event by clicking actual row?


    Yes.
    Filip DušekUser is Offline
    Advanced Member
    Advanced Member
    Posts:676


    --
    22 Mar 2016 11:59 AM
    OK. I have list of planets in my game. Here is what I have in my code.

        public interface IGovernmentInfoPanelViewModel
        {
            ICommand ShowPlanetCommand { get; set; }
        }
    
        public class GovernmentInfoPanelViewModel : ViewModelBase, IGovernmentInfoPanelViewModel
        {
            private ICommand showPlanetCommand;
    
            public ICommand ShowPlanetCommand
            {
                get { return showPlanetCommand; }
                set { SetProperty(ref showPlanetCommand, value); }
            }
    
            public GovernmentInfoPanelViewModel() : base()
            {
                ShowPlanetCommand = new RelayCommand<Planet>(new Action<Planet>(OnShowPlanet));
                ServiceManager.Instance.AddService<IGovernmentInfoPanelViewModel>(this);
            }
    
            private void OnShowPlanet(Planet planet)
            {
            }
         }
    
        public class GovInfoPanelViewModelLocator : ViewModelLocatorBase<IGovernmentInfoPanelViewModel>
        {
            public GovInfoPanelViewModelLocator()
                : base()
            {
            }
    
            public GovInfoPanelViewModelLocator(bool isDesignMode = true)
                : base(isDesignMode)
            {
            }
    
            public override void Initialize(bool isDesignMode)
            {
            }
        }
    


    So it's simple interface and two classes. View Model implementing that interface and locator for that View Model. All this code is pretty much locator pattern.

    And XAML code is (XAML project has to have reference to View Model project)

        <Grid>
            <Grid.Resources>
                <vm:GovInfoPanelViewModelLocator x:Key="govPanelViewModelLocator" />
            </Grid.Resources>
            <DataGrid Name="planetsGrid" ItemsSource="{Binding Planets}">
                <DataGrid.Resources>
                    <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Control.MouseDoubleClick" ek:EventTrigger.Command="{Binding Path=ViewModel.ShowPlanetCommand, Source={StaticResource govPanelViewModelLocator}}" />
                        </Style.Triggers>
                    </Style>
                </DataGrid.Resources>
             </DataGrid>
        </Grid>
    


    That's it.
    A TUser is Offline
    New Member
    New Member
    Posts:34


    --
    25 Mar 2016 12:54 AM
    Thank you!

    But now, after I've successfully added a command to handle double-click, I face a new problem: the method I've added doesn't "notice" changes of fields and properties done by other methods, except constructor.

    So, let's say my code looks like this:

    public interface IMyViewModel
    {
        ICommand DoubleClickCommand { get; set; }
    }
    
    public class MyViewModel: ViewModelBase, IMyViewModel
    {
        private uint cash;
        public uint Cash
        {
            get { return cash; }
            private set
            {
                SetProperty(ref cash, value);
            }
        }
    
        private ICommand doubleClickCommand;
        public ICommand DoubleClickCommand 
        {
            get { return doubleClickCommand; }
            private set
            {
                SetProperty(ref doubleClickCommand, value);
            }
        }
    
        public ICommand Enter
        {
            get;
            private set;
        }
    
        private void ChangeCash()
        {
             Cash = 1000;
        }
    
        public MyViewModel() : base()
        {
            DoubleClickCommand = new RelayCommand<ItemViewModel>(new Action<ItemViewModel>(OnDoubleClick));
            ServiceManager.Instance.AddService<IMyViewModel>(this);
            Enter = new RelayCommand(new Action<object>(OnEnter));
            Cash = 500;
            ChangeCash();
        }
    
        private void OnEnter(object obj)
        {
            // breakpoint 1 here
        }
    
        private void OnDoubleClick(ItemViewModel item)
        {
            // breakpoint 2 here
        }
    


    When I press Enter and breakpoint 1 is hit, Cash = 1000. When breakpoint 2 is hit, Cash = 500.

    Do you have any idea what can cause this?
    Filip DušekUser is Offline
    Advanced Member
    Advanced Member
    Posts:676


    --
    25 Mar 2016 01:13 AM
    I don't see anything "bad" in this code, maybe I would use SetProperty even for Enter command. It must be something else like binding etc. Can you make simple example?
    A TUser is Offline
    New Member
    New Member
    Posts:34


    --
    29 Mar 2016 01:56 AM
    I wasn't entirely true: the method that handles double click can't see only changes done to the view model by other event handlers (e. g. button click).

    I have a datagrid of available spaceship parts which player adds to a spaceship by double-clicking on them, and a set of buttons which allow to select what kind of spaceship components (e. g. cannons) player currently sees in the datagrid.

    XAML code:
    <Button x:Name="bCannons" Command="{Binding ButtonClick}" CommandParameter="Cannons" Content="Cannons" />
    
    <DataGrid x:Name="dgAvailableComponents" ItemsSource="{Binding AvailableComponents}" SelectedItem="{Binding SelectedComponent}" AutoGenerateColumns="False" >
       <DataGrid.Resources>
          <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
             <Style.Triggers>
                <EventTrigger RoutedEvent="Control.MouseDoubleClick" ek:EventTrigger.Command="{Binding Path=ViewModel.AddComponentCommand, Source={StaticResource shipDesignerViewModelLocator}}" />
             </Style.Triggers>
          </Style>
       </DataGrid.Resources>
       <DataGrid.InputBindings>
          <KeyBinding Key="Enter" Command="{Binding Enter}" CommandParameter="Add" />
       </DataGrid.InputBindings>
       <DataGrid.Columns>
          ...
       </DataGrid.Columns>
    </DataGrid>
    


    C# code:
        public class ShipDesignerViewModel : ViewModelBase, IShipDesignerViewModel
        {
            private ICommand buttonClick;
            public ICommand ButtonClick
            {
                get { return buttonClick; }
                set { SetProperty(ref buttonClick, value); }
            }
            private ICommand addComponentCommand;
            public ICommand AddComponentCommand 
            {
                get { return addComponentCommand; }
                set { SetProperty(ref addComponentCommand, value); }
            }
            public ICommand Enter
            {
                get;
                private set;
            }
    
            private List<ComponentViewModel> availableComponents;
            public List<ComponentViewModel> AvailableComponents
            {
                get { return availableComponents; }
                set
                {
                    SetProperty(ref availableComponents, value);
                }
            }
    
            public ShipDesignerViewModel() : base()
            {
                ButtonClick = new RelayCommand(new Action<object>(OnButtonClick));
                AddComponentCommand = new RelayCommand<ComponentViewModel>(new Action<ComponentViewModel>(OnComponentAdded));
                ServiceManager.Instance.AddService<IShipDesignerViewModel>(this);
                Enter = new RelayCommand(new Action<object>(OnEnter));
            }
       }
    


    When I click the "Cannons" button, AvailableComponents is filled by a list of spaceship cannons. When I later select a cannon in the datagrid and press Enter, OnEnter method works properly and "sees" an updated AvailableComponents list. But if I set a breakpoint in OnComponentAdded method, I find that AvailableComponents value is still null. And the same is true for every other field or property: if it's value is set in constructor or in OnComponentAdded method, then the next call of OnComponentAdded "sees" this change; if the value is set by button click, OnComponentAdded doesn't "see" this.
    Filip DušekUser is Offline
    Advanced Member
    Advanced Member
    Posts:676


    --
    29 Mar 2016 08:24 PM
    Looks like you have 2 instances of ShipDesignerViewModel running. Double check that you don't create it 2 times.
    A TUser is Offline
    New Member
    New Member
    Posts:34


    --
    02 Apr 2016 03:29 AM
    Thanks. Indeed, I created it twice. When I removed the second constructor call, double-click simply ceased to work because, as it soon became clear, I initialized view model class after UI class (as in the example on Github), thus at the time of UI class initialization service hadn't been added to ServiceManager yet. So all the problems seem to be finally solved.
    You are not authorized to post a reply.