是否有一种通用的方法将鼠标下方的ItemContainer的DataContext设置为某个其他控件的属性?

时间:2010-08-08 13:58:50

标签: wpf xaml

将鼠标悬停在列表中的某个项目上时,如何将另一个元素的属性设置为列表项的DataContext?

我正在尝试创建一个区域,我可以在其中显示鼠标光标下方当前项目的预览。我可以使用代码隐藏来实现这一点,但我想找到一种可以使用EventSetters / Binding / Triggers / AttachedProperties或任何其他方法的替代方法。

目标是在更松散耦合的场景中应用解决方案,其中ListView控件可以位于单独的资源文件中,并且PreviewControl可能由多个ListView共享以显示不同类型的预览。

以下代码可以使用,但需要代码隐藏:

<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>

目前的代码隐藏技巧:

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;
    }
}

1 个答案:

答案 0 :(得分:1)

解决方案1 ​​(不是通用但简单且有效):

将已实现的逻辑封装到自定义控件中,该控件具有新的依赖项属性(typeof(object)),表示HoveredItemContext。在自定义列表视图的构造函数中,您可以创建ContainerStyle并附加事件。在此EventHandlers中设置HoveredItemContext,您可以从外部绑定到此属性:

 <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}}" />

这里的自定义控件(有效):

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;
            })));
    }
}

解决方案2 (更通用):

我仍在研究类似的问题,但还没有完成;)如果我把它结束,我会在这里发布。