Is there a general way to set the DataContext of an ItemContainer under the mouse on a property of some other control?

When I hover over an item in a list, how can I set a property for another item in the DataContext of a list item?

I am trying to create an area where I can display a preview of an item under the mouse cursor. I can do this with code, but I would like to find an alternative way to use EventSetters / Binding / Triggers / AttachedProperties or any other means.

The goal is to apply the solution in a more loosely coupled scenario where the ListView control can be in a separate resource file, and the PreviewControl can be divided by several ListViews to view different types of previews.

The following code snippet works, but requires code:

<Window x:Class="Previewer.PreviewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="PreviewWindow" Height="300" Width="300">
<Window.Resources>
    <x:Array x:Key="Data" Type="sys:String">
        <sys:String>First</sys:String>
        <sys:String>Second</sys:String>
    </x:Array>

    <CollectionViewSource x:Key="DataSource" Source="{StaticResource Data}"/>
</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <ContentControl Grid.Row="0" x:Name="PreviewControl"/>

    <ListView Grid.Row="1" ItemsSource="{Binding Source={StaticResource DataSource}}">
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListViewItem}">
                <EventSetter Event="MouseEnter" Handler="ListViewItem_MouseEnter"/>
                <EventSetter Event="MouseLeave" Handler="ListViewItem_MouseLeave"/>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>
</Grid>

The code that is currently doing the trick:

public partial class PreviewWindow : Window
{
    public PreviewWindow()
    {
        InitializeComponent();
    }

    private void ListViewItem_MouseEnter(object sender, MouseEventArgs e)
    {
        var listViewItem = (ListViewItem)sender;
        PreviewControl.Content= listViewItem.DataContext;
    }

    private void ListViewItem_MouseLeave(object sender, MouseEventArgs e)
    {
        var listViewItem = (ListViewItem)sender;
        PreviewControl.Content= null;
    }
}
+3
source share
1 answer

Solution 1 (not that generic, but simple and works):

encapsulate already implemented logic in a user control that has a new dependency property (typeof (object)) that represents the HoveredItemContext. In the constructor of your custom list, you can create a ContainerStyle and attach events. Set the HoveredItemContext in this EventHandlers, and you can bind this property from the outside:

 <ContentControl Grid.Row="0" x:Name="PreviewControl" 
     Content="{Binding ElementName=MyListView, Path=HoveredItemContext}"/>
 <local:MyListView Grid.Row="1" x:Name="MyListView" 
     ItemsSource="{Binding Source={StaticResource DataSource}}" />

And here is the user control (works):

public class MyListView : ListView
{
    public static readonly DependencyProperty HoveredItemContextProperty = DependencyProperty.Register(
        "HoveredItemContext",
        typeof(object),
        typeof(MyListView),
        new PropertyMetadata(null));

    public object HoveredItemContext
    {
        get { return GetValue(HoveredItemContextProperty); }
        set { SetValue(HoveredItemContextProperty, value); }
    }

    public MyListView()
    {
        this.ItemContainerStyle = new Style()
        {
            TargetType = typeof(ListViewItem),
        };

        this.ItemContainerStyle.Setters.Add(new EventSetter(ListViewItem.MouseEnterEvent,
            (MouseEventHandler)((s, e) =>
            {
                this.HoveredItemContext = (s as ListViewItem).DataContext;
            })));

        this.ItemContainerStyle.Setters.Add(new EventSetter(ListViewItem.MouseLeaveEvent,
            (MouseEventHandler)((s, e) =>
            {
                this.HoveredItemContext = null;
            })));
    }
}

Solution 2 (more general):

I am still working on this on a similar issue, but it is not finished yet;) If I bring it, I will post it here.

+1

Source: https://habr.com/ru/post/1758609/


All Articles