none
WPF MVVM Mouse Hover Index RRS feed

  • General discussion

  • I need WPF MVVM Mouse Hover Index.

    I Tried below code, Hover True or False is Working, But I Need the Index of the Mouse Hover in the ListView.

    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp16
    {
        public static class MouseOverHelpers
        {
            public static readonly DependencyProperty MouseOverCommand =
                DependencyProperty.RegisterAttached("MouseOverCommand", typeof(ICommand), typeof(MouseOverHelpers),
                    new PropertyMetadata(null, PropertyChangedCallback));
    
            private static void PropertyChangedCallback(DependencyObject dependencyObject,
                DependencyPropertyChangedEventArgs args)
            {
                var ui = dependencyObject as UIElement;
                if (ui == null) return;
                if (args.OldValue != null)
                {
                    ui.RemoveHandler(UIElement.MouseLeaveEvent, new RoutedEventHandler(MouseLeave));
                    ui.RemoveHandler(UIElement.MouseEnterEvent, new RoutedEventHandler(MouseEnter));
                }
    
                if (args.NewValue != null)
                {
                    ui.AddHandler(UIElement.MouseLeaveEvent, new RoutedEventHandler(MouseLeave));
                    ui.AddHandler(UIElement.MouseEnterEvent, new RoutedEventHandler(MouseEnter));
                }
            }
    
            private static void ExecuteCommand(object sender, bool parameter)
            {
                var dp = sender as DependencyObject;
                if (dp == null) return;
                var command = dp.GetValue(MouseOverCommand) as ICommand;
                if (command == null) return;
                if (command.CanExecute(parameter)) command.Execute(parameter);
            }
    
            private static void MouseEnter(object sender, RoutedEventArgs e)
            {
                ExecuteCommand(sender, true);
            }
    
            private static void MouseLeave(object sender, RoutedEventArgs e)
            {
                ExecuteCommand(sender, false);
            }
    
            public static void SetMouseOverCommand(DependencyObject o, ICommand value)
            {
                o.SetValue(MouseOverCommand, value);
            }
    
            public static ICommand GetMouseOverCommand(DependencyObject o)
            {
                return o.GetValue(MouseOverCommand) as ICommand;
            }
        }
    }
     <ListView Name="ListView"  wpfApp16:MouseOverHelpers.MouseOverCommand="{Binding MouseOverCommand}">


    ViewModel

    MouseOverCommand = new RelayCommand<object>(MouseOverEvent);
    
       private void MouseOverEvent(object listView)
            {
               
            }


    • Edited by ID GO Wednesday, October 9, 2019 6:42 AM
    Wednesday, October 9, 2019 6:40 AM

All replies

  • Hi,
    use the System.Windows.InterActivity from Nuget to catch the reference to the ListView. This reference you can store in the ViewModel (via DataContext). With this reference you can add handler to every event of ListView and read the values of all properties.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Wednesday, October 9, 2019 9:35 AM
  • Hello Peter, How ru,

    I can't use external dll to this project...I can use attached or dependency Property or anything without dll.

    Wednesday, October 9, 2019 9:38 AM
  • Hi,
    use the System.Windows.InterActivity from Nuget to catch the reference to the ListView. This reference you can store in the ViewModel (via DataContext). With this reference you can add handler to every event of ListView and read the values of all properties.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Hello Peter, How ru,

    I can't use external dll to this project...I can use attached or dependency Property or anything without dll.


    Wednesday, October 9, 2019 9:38 AM
  •    public class BindingProxy : Freezable
        {
            #region Overrides of Freezable
    
            protected override Freezable CreateInstanceCore()
            {
                return new BindingProxy();
            }
    
            #endregion
    
            public object Data
            {
                get { return (object)GetValue(DataProperty); }
                set { SetValue(DataProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DataProperty =
                DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
        }
       public class MouseOverArg : EventArgs
        {
            public MouseOverArg(int index, bool isOver)
            {
                Index = index;
                IsOver = isOver;
            }
            public int Index { get; private set; }
            public bool IsOver { get; private set; }
        }
    
        public static class MouseOverHelpers
        {
            public static readonly DependencyProperty MouseOverCommand =
                DependencyProperty.RegisterAttached("MouseOverCommand", typeof(ICommand), typeof(MouseOverHelpers),
                    new PropertyMetadata(null, PropertyChangedCallback));
    
            private readonly static MouseEventHandler mouseEnterHandler = (s, arg)
                => ExecuteCommand(s, true, arg);
    
    
            private readonly static MouseEventHandler mouseLeaveHandler = (s, arg)
                => ExecuteCommand(s, false, arg);
    
            private static void PropertyChangedCallback(DependencyObject dependencyObject,
                DependencyPropertyChangedEventArgs args)
            {
                var ui = dependencyObject as UIElement;
                if (ui == null) return;
                if (args.OldValue != null)
                {
                    ui.MouseLeave -= mouseLeaveHandler;
                    ui.MouseEnter -= mouseEnterHandler;
                }
    
                if (args.NewValue != null)
                {
                    ui.MouseLeave += mouseLeaveHandler;
                    ui.MouseEnter += mouseEnterHandler;
                }
            }
    
            private static void ExecuteCommand(object sender, bool isOver, MouseEventArgs arg)
            {
                var source = (sender as DependencyObject);
                var selector = source.FindParent<System.Windows.Controls.ListView>();
                if (selector == null) return;
                var command = source.GetValue(MouseOverCommand) as ICommand;
                if (command == null) return;
    
                var index = -1;
    
                if (selector.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
    
                    index = selector.ItemContainerGenerator.IndexFromContainer(arg.OriginalSource as DependencyObject);
                }
                else
                {
                    index = selector.Items.IndexOf(arg.OriginalSource);
                }
    
                var parameter = new MouseOverArg(index, isOver);
    
                if (command.CanExecute(parameter)) command.Execute(parameter);
            }
         
            public static void SetMouseOverCommand(DependencyObject o, ICommand value)
            {
                o.SetValue(MouseOverCommand, value);
            }
    
            public static ICommand GetMouseOverCommand(DependencyObject o)
            {
                return o.GetValue(MouseOverCommand) as ICommand;
            }
        }
    <Window ...
    
                     >
    
      <Window.Resources>
         ...
         <l:BindingProxy x:Key="proxy" Data="{Binding}"/>
      </Window.Resources>
       ...
    
            <ListView ItemsSource="{Binding Items}"
                      >
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="lb:MouseOverHelpers.MouseOverCommand" Value="{Binding Data.MouseOverCommand, Mode=OneTime, Source={StaticResource proxy}}"/>
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.View>
                    <GridView>
                        .....
                    </GridView>
                </ListView.View>
            </ListView>
        ...
    </Window> 


    MouseOverCommand = new RelayCommand<MouseOverArg>(MouseOverEvent);
    
       private void MouseOverEvent(MouseOverArg parameter)
       {
               System.Diagnostics.Debug.Print($"Mouse IsOver={parameter.IsOver} at item {parameter.Index}");
       }
        static class DependencyObjectExtensions
        {
            public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
            {
                //get parent item
                var parentObject = child;
                while (parentObject != null && typeof(T).IsAssignableFrom(parentObject.GetType()) == false)
                {
                    parentObject = VisualTreeHelper.GetParent(parentObject);
                }
    
                //we've reached the end of the tree
    
                return parentObject as T;
    
            }
        }

    the symbol "..." are omissis




    • Edited by Spaccabit Wednesday, October 9, 2019 1:46 PM
    Wednesday, October 9, 2019 1:36 PM
  • Hi,
    here is another simple demo without additional dll.

    XAML:

    <Window x:Class="WpfApp1.Window71"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window71" Height="450" Width="800">
      <Window.Resources>
        <local:Window71ViewModel x:Key="vm"/>
      </Window.Resources>
      <StackPanel DataContext="{StaticResource vm}">
        <TextBlock Text="{Binding Info}"/>
        <ListView ItemsSource="{Binding View}">
          <ListView.ItemTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Member}" local:Window71Data.Init="{StaticResource vm}"/>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
      </StackPanel>
    </Window>

    And classes:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      public class Window71ViewModel : INotifyPropertyChanged
      {
        public Window71ViewModel()
        {
          for (int i = 0; i < 10; i++) col.Add(new Window71Data() { Member = $"Item {i}" });
          cvs.Source = col;
        }
    
        private ObservableCollection<Window71Data> col = new ObservableCollection<Window71Data>();
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView View { get => cvs.View; }
    
        public string Info { get; set; }
    
        public void SetInfo(Window71Data sender, string msg)
        {
          var index = col.IndexOf(sender);
          Info = $"{msg}, Position. {index}, Member: {sender.Member}";
          OnPropertyChanged(nameof(Info));
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
           => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      public partial class Window71Data
      {
        public string Member { get; set; }
      }
    
      public partial class Window71Data
      {
        public static readonly DependencyProperty InitProperty =
          DependencyProperty.RegisterAttached("Init",
          typeof(Window71ViewModel),
          typeof(Window71Data),
          new PropertyMetadata(null, OnInit));
    
        public static Window71ViewModel GetInit(DependencyObject obj) => (Window71ViewModel)obj.GetValue(InitProperty);
        public static void SetInit(DependencyObject obj, Window71ViewModel value) => obj.SetValue(InitProperty, value);
        private static void OnInit(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          var element = d as FrameworkElement;
          if (element == null) return;
          var obj = e.NewValue as Window71ViewModel;
          if (obj != null) { element.MouseEnter += OnMouseEnter; element.MouseLeave += OnMouseLeave; }
          else { element.MouseEnter -= OnMouseEnter; element.MouseLeave -= OnMouseLeave; }
          ((Window71Data)element.DataContext).VM = obj;
        }
    
        public Window71ViewModel VM { get; set; }
    
        private static void OnMouseEnter(object sender, MouseEventArgs e)
        {
          var element = sender as FrameworkElement;
          if (element == null) return;
          var d = element.DataContext as Window71Data;
          d.VM.SetInfo(d, $"Enter");
        }
    
        private static void OnMouseLeave(object sender, MouseEventArgs e)
        {
          var element = sender as FrameworkElement;
          if (element == null) return;
          var d = element.DataContext as Window71Data;
          d.VM.SetInfo(d, $"Leave");
        }
      }
    }
    


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Wednesday, October 9, 2019 3:55 PM
  • Thanks Spaccabit...
    Thursday, October 10, 2019 5:15 AM
  • Thanks Peter.....
    Thursday, October 10, 2019 5:15 AM
  • Hi,
    here is another simple demo without additional dll.

    XAML:

    <Window x:Class="WpfApp1.Window71"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window71" Height="450" Width="800">
      <Window.Resources>
        <local:Window71ViewModel x:Key="vm"/>
      </Window.Resources>
      <StackPanel DataContext="{StaticResource vm}">
        <TextBlock Text="{Binding Info}"/>
        <ListView ItemsSource="{Binding View}">
          <ListView.ItemTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Member}" local:Window71Data.Init="{StaticResource vm}"/>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
      </StackPanel>
    </Window>

    And classes:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      public class Window71ViewModel : INotifyPropertyChanged
      {
        public Window71ViewModel()
        {
          for (int i = 0; i < 10; i++) col.Add(new Window71Data() { Member = $"Item {i}" });
          cvs.Source = col;
        }
    
        private ObservableCollection<Window71Data> col = new ObservableCollection<Window71Data>();
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView View { get => cvs.View; }
    
        public string Info { get; set; }
    
        public void SetInfo(Window71Data sender, string msg)
        {
          var index = col.IndexOf(sender);
          Info = $"{msg}, Position. {index}, Member: {sender.Member}";
          OnPropertyChanged(nameof(Info));
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
           => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      public partial class Window71Data
      {
        public string Member { get; set; }
      }
    
      public partial class Window71Data
      {
        public static readonly DependencyProperty InitProperty =
          DependencyProperty.RegisterAttached("Init",
          typeof(Window71ViewModel),
          typeof(Window71Data),
          new PropertyMetadata(null, OnInit));
    
        public static Window71ViewModel GetInit(DependencyObject obj) => (Window71ViewModel)obj.GetValue(InitProperty);
        public static void SetInit(DependencyObject obj, Window71ViewModel value) => obj.SetValue(InitProperty, value);
        private static void OnInit(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          var element = d as FrameworkElement;
          if (element == null) return;
          var obj = e.NewValue as Window71ViewModel;
          if (obj != null) { element.MouseEnter += OnMouseEnter; element.MouseLeave += OnMouseLeave; }
          else { element.MouseEnter -= OnMouseEnter; element.MouseLeave -= OnMouseLeave; }
          ((Window71Data)element.DataContext).VM = obj;
        }
    
        public Window71ViewModel VM { get; set; }
    
        private static void OnMouseEnter(object sender, MouseEventArgs e)
        {
          var element = sender as FrameworkElement;
          if (element == null) return;
          var d = element.DataContext as Window71Data;
          d.VM.SetInfo(d, $"Enter");
        }
    
        private static void OnMouseLeave(object sender, MouseEventArgs e)
        {
          var element = sender as FrameworkElement;
          if (element == null) return;
          var d = element.DataContext as Window71Data;
          d.VM.SetInfo(d, $"Leave");
        }
      }
    }


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Peter , The event is Firing Only if I Hover the Mouse on Text, Can it be Entire Row.

    Friday, October 11, 2019 4:49 AM
  • HI,
    stretch the content:

    <Window x:Class="WpfApp1.Window74"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window74" Height="450" Width="800">
      <Window.Resources>
        <local:Window74ViewModel x:Key="vm"/>
        <Style TargetType="ListViewItem" x:Key="LBStyle">
          <Setter Property="ContentTemplate">
            <Setter.Value>
              <DataTemplate>
                <TextBlock Text="{Binding Member}" local:Window74Data.Init="{StaticResource vm}" HorizontalAlignment="Stretch"/>
              </DataTemplate>
            </Setter.Value>
          </Setter>
          <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
      </Window.Resources>
      <StackPanel DataContext="{StaticResource vm}">
        <TextBlock Text="{Binding Info}"/>
        <ListView ItemsSource="{Binding View}" ItemContainerStyle="{StaticResource LBStyle}"/>
      </StackPanel>
    </Window>


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Friday, October 11, 2019 7:12 AM
  • Super Peter, Now Working Fine..
    Friday, October 11, 2019 8:38 AM
  •    public class BindingProxy : Freezable
        {
            #region Overrides of Freezable
    
            protected override Freezable CreateInstanceCore()
            {
                return new BindingProxy();
            }
    
            #endregion
    
            public object Data
            {
                get { return (object)GetValue(DataProperty); }
                set { SetValue(DataProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DataProperty =
                DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
        }
       public class MouseOverArg : EventArgs
        {
            public MouseOverArg(int index, bool isOver)
            {
                Index = index;
                IsOver = isOver;
            }
            public int Index { get; private set; }
            public bool IsOver { get; private set; }
        }
    
        public static class MouseOverHelpers
        {
            public static readonly DependencyProperty MouseOverCommand =
                DependencyProperty.RegisterAttached("MouseOverCommand", typeof(ICommand), typeof(MouseOverHelpers),
                    new PropertyMetadata(null, PropertyChangedCallback));
    
            private readonly static MouseEventHandler mouseEnterHandler = (s, arg)
                => ExecuteCommand(s, true, arg);
    
    
            private readonly static MouseEventHandler mouseLeaveHandler = (s, arg)
                => ExecuteCommand(s, false, arg);
    
            private static void PropertyChangedCallback(DependencyObject dependencyObject,
                DependencyPropertyChangedEventArgs args)
            {
                var ui = dependencyObject as UIElement;
                if (ui == null) return;
                if (args.OldValue != null)
                {
                    ui.MouseLeave -= mouseLeaveHandler;
                    ui.MouseEnter -= mouseEnterHandler;
                }
    
                if (args.NewValue != null)
                {
                    ui.MouseLeave += mouseLeaveHandler;
                    ui.MouseEnter += mouseEnterHandler;
                }
            }
    
            private static void ExecuteCommand(object sender, bool isOver, MouseEventArgs arg)
            {
                var source = (sender as DependencyObject);
                var selector = source.FindParent<System.Windows.Controls.ListView>();
                if (selector == null) return;
                var command = source.GetValue(MouseOverCommand) as ICommand;
                if (command == null) return;
    
                var index = -1;
    
                if (selector.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
    
                    index = selector.ItemContainerGenerator.IndexFromContainer(arg.OriginalSource as DependencyObject);
                }
                else
                {
                    index = selector.Items.IndexOf(arg.OriginalSource);
                }
    
                var parameter = new MouseOverArg(index, isOver);
    
                if (command.CanExecute(parameter)) command.Execute(parameter);
            }
         
            public static void SetMouseOverCommand(DependencyObject o, ICommand value)
            {
                o.SetValue(MouseOverCommand, value);
            }
    
            public static ICommand GetMouseOverCommand(DependencyObject o)
            {
                return o.GetValue(MouseOverCommand) as ICommand;
            }
        }
    <Window ...
    
                     >
    
      <Window.Resources>
         ...
         <l:BindingProxy x:Key="proxy" Data="{Binding}"/>
      </Window.Resources>
       ...
    
            <ListView ItemsSource="{Binding Items}"
                      >
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="lb:MouseOverHelpers.MouseOverCommand" Value="{Binding Data.MouseOverCommand, Mode=OneTime, Source={StaticResource proxy}}"/>
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.View>
                    <GridView>
                        .....
                    </GridView>
                </ListView.View>
            </ListView>
        ...
    </Window> 


    MouseOverCommand = new RelayCommand<MouseOverArg>(MouseOverEvent);
    
       private void MouseOverEvent(MouseOverArg parameter)
       {
               System.Diagnostics.Debug.Print($"Mouse IsOver={parameter.IsOver} at item {parameter.Index}");
       }
        static class DependencyObjectExtensions
        {
            public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
            {
                //get parent item
                var parentObject = child;
                while (parentObject != null && typeof(T).IsAssignableFrom(parentObject.GetType()) == false)
                {
                    parentObject = VisualTreeHelper.GetParent(parentObject);
                }
    
                //we've reached the end of the tree
    
                return parentObject as T;
    
            }
        }

    the symbol "..." are omissis




    Thanks Spaccabit
    Monday, October 21, 2019 7:10 AM
  • what is this?
    Monday, October 21, 2019 7:21 AM