1

I have some WPF code that looks like this

C#

namespace ItemEventTest
{
public partial class MainWindow : Window
 {
    public MainWindow()
    {
        DataContext = this;

        MyItems = new ObservableCollection<MyItem>();
        MyItems.Add(new MyItem { Name = "Otto" });
        MyItems.Add(new MyItem { Name = "Dag" });
        MyItems.Add(new MyItem { Name = "Karin" });

        InitializeComponent();
    }

    public ObservableCollection<MyItem> MyItems { get; set; }
}

public class MyItem :INotifyPropertyChanged
{
    private string m_name;

    public string Name
    {
        get { return m_name; }
        set
        {
            m_name = value; 
            OnPropertyChanged();
        }
    }

    public void WhenMouseMove()
    {
        //Do stuff
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
 }
}

Xaml

<Window x:Class="ItemEventTest.MainWindow"
    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:ItemEventTest"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListBox ItemsSource="{Binding MyItems}">
            <ListBox.ItemTemplate>
                <DataTemplate DataType="local:MyItem">
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

What I now want to do is when the mouse moves over an item is to call WhenMouseMove on the object that is the source of that item.
I would like to have the function called directly on the object and not by first going through MainWindow or some view model connected to MainWindow. It feels like it should be possible because the data is bound that way but I haven't managed to find a description of how to do it.

Hampus
  • 137
  • 2
  • 14
  • 1
    Possible duplicate of [WPF Binding UI events to commands in ViewModel](https://stackoverflow.com/questions/4897775/wpf-binding-ui-events-to-commands-in-viewmodel) – ASh Nov 16 '17 at 14:21
  • @Hampus Let me understand. You want to do the stuff contained in WhenMouseMove when the mouse enter in a control? – Daniele Sartori Nov 16 '17 at 14:25
  • @DanieleSartori No, when the mouse moves while being inside a ListBoxItem – Hampus Nov 16 '17 at 14:28
  • What do you mean by "not by first going through"? You need to to write some code that calls the call WhenMouseMove method somewhere. – mm8 Nov 16 '17 at 16:21
  • @mm8 I'm trying to not clutter up the code behind or the if I had a model view, that with event handlers that do the figuring out what the data context of the item that triggered the event and then calling that – Hampus Nov 17 '17 at 09:12
  • How are you supposed to be able to call your method if you don't write some code that calls it? – mm8 Nov 17 '17 at 14:08
  • It feels like the event could trigger a method on the data context of the item directly instead of triggering a method on the Window or ViewModel – Hampus Nov 20 '17 at 08:43

1 Answers1

0

If you are seeking solution in MVVM pattern

Edit: Add a reference to System.Windows.Interactivity dll (which is system defined if Blend or VS2015 installed)

then add following namespace xmlns:i="schemas.microsoft.com/expression/2010/interactivity‌​"

// xaml file

<Grid>
        <ListBox ItemsSource="{Binding MyItems}">
            <ListBox.ItemTemplate>
                <DataTemplate DataType="local:MyItem">
                    <TextBlock Text="{Binding Name}">
                          <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter">
                    <i:InvokeCommandAction Command="{Binding MouseHoveredItemChangedCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

// viewmodel (MyItem class)

  public void WhenMouseMove()
        {
            //Do stuff
            Console.WriteLine(Name);
        }

        private RelayCommand _MouseHoveredItemChangedCommand;
        public RelayCommand MouseHoveredItemChangedCommand
        {
            get
            {
                if (_MouseHoveredItemChangedCommand == null)
                {
                    _MouseHoveredItemChangedCommand = new RelayCommand(WhenMouseMove);
                }
                return _MouseHoveredItemChangedCommand;
            }
        }

// RelayCommand class

 public class RelayCommand : ICommand
        {
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
            private Action methodToExecute;
            private Func<bool> canExecuteEvaluator;
            public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
            {
                this.methodToExecute = methodToExecute;
                this.canExecuteEvaluator = canExecuteEvaluator;
            }
            public RelayCommand(Action methodToExecute)
                : this(methodToExecute, null)
            {
            }
            public bool CanExecute(object parameter)
            {
                if (this.canExecuteEvaluator == null)
                {
                    return true;
                }
                else
                {
                    bool result = this.canExecuteEvaluator.Invoke();
                    return result;
                }
            }
            public void Execute(object parameter)
            {
                this.methodToExecute.Invoke();
            }
        }
Manish Dubey
  • 706
  • 4
  • 17
  • Probably works but I can't seem to be able to include interactions which I guess is needed for this code – Hampus Nov 20 '17 at 08:45
  • Add a reference to System.Windows.Interactivity dll (which is system defined if Blend or VS2015 installed) then add following namespace xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" – Manish Dubey Nov 20 '17 at 12:12