wpf 我可以使用触发器写回DataContext中的数据模型吗?

myss37ts  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(89)

这类似于this question,但这个问题没有得到适用于我的情况的答案。
我有一个带有DataTemplate的列表框,用于显示项目列表。我希望当鼠标悬停在列表中的每个项目上时,都能被告知。下面是一个XAML示例:

<ListBox ItemsSource="{Binding Items}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Label x:Name="name" Content="{Binding Name}" />
                <DataTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="{Binding MouseOverPropertyInModel}" Value="True" />
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

C#:

public partial class DataTriggerSetter : Window
{
    public DataTriggerSetter()
    {
        InitializeComponent();
        this.DataContext = new DataTriggerSetterViewModel();
    }
}

public class DataTriggerSetterViewModel : ObservableObject
{
    public ObservableCollection<SomeModel> Items { get; } = new ObservableCollection<SomeModel>
    {
        new SomeModel { Name = "Larry", },
        new SomeModel { Name = "Atari", },
    };
}

public class SomeModel
{
    private bool mouseOver;

    public string Name { get; set; }
    public bool MouseOverPropertyInModel { get => mouseOver; set => throw new NotImplementedException(); }
}

当鼠标悬停在MouseOverPropertyInModel上时,设置MouseOverPropertyInModel的值。这个例子不起作用,因为你不能在trigger setter属性上设置绑定。
我想我可以通过将一个不可见的复选框绑定到属性来做到这一点,但似乎触发器应该能够写回驱动数据模板的数据,我只是不知道正确的方法。有什么建议吗?

ftf50wuq

ftf50wuq1#

一种实现方法是使用附加行为。附加行为允许您将行为附加到UI元素,而无需子类化它。
下面是一个附加行为的示例实现,当鼠标在UI元素上时,该行为在视图模型上设置属性:

public static class MouseOverBehavior
{
    public static readonly DependencyProperty IsMouseOverProperty = DependencyProperty.RegisterAttached(
        "IsMouseOver",
        typeof(bool),
        typeof(MouseOverBehavior),
        new PropertyMetadata(false, OnIsMouseOverChanged));

    public static bool GetIsMouseOver(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsMouseOverProperty);
    }

    public static void SetIsMouseOver(DependencyObject obj, bool value)
    {
        obj.SetValue(IsMouseOverProperty, value);
    }

    private static void OnIsMouseOverChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (obj is FrameworkElement element)
        {
            element.MouseEnter += (sender, args) =>
            {
                var viewModel = element.DataContext as SomeModel;
                if (viewModel != null)
                {
                    viewModel.MouseOverPropertyInModel = true;
                }
            };

            element.MouseLeave += (sender, args) =>
            {
                var viewModel = element.DataContext as SomeModel;
                if (viewModel != null)
                {
                    viewModel.MouseOverPropertyInModel = false;
                }
            };
        }
    }
}

要在XAML中使用附加的行为,您需要将MouseOverBehavior.IsMouseOver属性添加到DataTemplate中的Label元素:

<ListBox ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Label x:Name="name" Content="{Binding Name}" local:MouseOverBehavior.IsMouseOver="{Binding MouseOverPropertyInModel}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

请注意,XAML中的本地名称空间前缀是指定义MouseOverBehavior类的名称空间。

相关问题