Search code examples
c#wpfmvvmdatagrid

Update binding on WPF Datagrid hover


I have a simple WPF datagrid in an MVVM design that is bound to a List<Object>. My goal is to update one of the properties when the user hovers over that row. I've been investigating style triggers, interaction.trigger, and just can't seem to find something that works. Thanks for the help!

The model:

public class CarrierInvDetails : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged
    private bool _IsHover;
    public bool IsHover
    {
        get
        {
            return _IsHover;
        }
        set
        {
            PropertyChanged.ChangeAndNotify(ref _IsHover, value, () => IsHover);
        }
    }
}

The Viewmodel:

private List<CarrierInvDetails> _CarrierInvList;
public List<CarrierInvDetails> CarrierInvList
{
    get
    {
        return _CarrierInvList;
    }
    set
    {
        PropertyChanged.ChangeAndNotify(ref _CarrierInvList, value, () => CarrierInvList);
    }
}

The View:

<DataGrid ItemsSource="{Binding CarrierInvList}" 
            Margin="5"
            SelectedItem="{Binding SelectedCarrierInv}"
            CanUserAddRows="False"
            CanUserDeleteRows="False"
            IsReadOnly="True">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow" BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <!--This is kind of what Id like to do.  When the mouse is over the row, update IsHover to True, but it complains about having a "Binding" here -->
                    <Setter Property="{Binding IsHover}" Value="True"/> 
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

Solution

  • For anyone in the future, I was able to get a working solution by using a combination of Events, interface, and Style triggers.

    First, setting the datagrid style:

    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow" BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
            <!-- This is where we will set the IsHover property -->
            <EventSetter Event="MouseEnter" Handler="DataGridRow_Enter" /> 
            <EventSetter Event="MouseLeave" Handler="DataGridRow_Leave" />
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsHover}" Value="True">
                    <Setter Property="Background" Value="DarkSeaGreen"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
    

    The interface:

    public interface IHover
    {
        public bool IsHover
        {
            get;
            set;
        }
    }
    

    Then the code-behind that actually sets the values

    private void DataGridRow_Enter(object sender, MouseEventArgs e)
    {
        if (sender.GetType() != typeof(DataGridRow))
            return;
    
        if (typeof(Models.IHover).IsAssignableFrom((sender as DataGridRow).DataContext.GetType()))
        {
            ((Models.IHover)((sender as DataGridRow).DataContext)).IsHover = true;
        }
    }
    
    private void DataGridRow_Leave(object sender, MouseEventArgs e)
    {
        if (sender.GetType() != typeof(DataGridRow))
            return;
    
        if (typeof(Models.IHover).IsAssignableFrom((sender as DataGridRow).DataContext.GetType()))
        {
            ((Models.IHover)((sender as DataGridRow).DataContext)).IsHover = false;
        }
    }
    

    And finally the model that utilizes the interface

    public class ClientInvDetails : INotifyPropertyChanged, IHover
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private bool _IsHover;
        public bool IsHover
        {
            get
            {
                return _IsHover;
            }
            set
            {
                //This is simply an extension that handles the notification of a property change.  You can use a standard "OnPropertyChanged" function that is available elsewhere
                PropertyChanged.ChangeAndNotify(ref _IsHover, value, () => IsHover);
            }
        }
    
        private bool _IsSelected;
        public bool IsSelected
        {
            get
            {
                return _IsSelected;
            }
            set
            {
                PropertyChanged.ChangeAndNotify(ref _IsSelected, value, () => IsSelected);
            }
        }
    }