c# - 使用带有 HierarchicalDatatemplate 的附加行为

标签 c# wpf xaml mvvm treeview

目前我正在尝试在 TreeView 中显示自定义类的 ObservableCollection,当用户双击“项目”时,它将触发 ViewModel 中的一个方法,将选定的自定义类作为参数传递。我正在为我的 WPF 应用程序使用 MVVM 结构。

我面临的问题是 Observable Collection 使用 HierarchicalDataTemplate 显示。查看 TreeView 的整个 XAML 代码下方

<TreeView Name="DeviceTreeView" ItemsSource="{Binding ViewableTIADeviceTree}" Grid.Column="3" Margin="5">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type treeviewable:ViewableTIADevice}" ItemsSource="{Binding DeviceItems}">
                        <TextBlock Text="{Binding Path=DeviceName}"/>

                        <HierarchicalDataTemplate.ItemContainerStyle>
                            <Style TargetType="{x:Type treeviewable:ViewableTIADevice}">
                                <Setter Property="commandBehaviors:MouseDoubleClick.Command"
                                    Value="{Binding TIADeviceTreeItemDoubleClick}"/>
                                <Setter Property="commandBehaviors:MouseDoubleClick.CommandParameter"
                                    Value="{Binding}"/>
                            </Style>
                        </HierarchicalDataTemplate.ItemContainerStyle>
                    </HierarchicalDataTemplate>
                    <DataTemplate DataType="{x:Type treeviewable:ViewableDeviceItem}">
                        <TextBlock Text="{Binding Path=Name}"/>
                    </DataTemplate>
                </TreeView.Resources>
            </TreeView>

和 MouseDoubleClick 附加的行为类:
public class MouseDoubleClick
{
    public static DependencyProperty CommandProperty = 
        DependencyProperty.RegisterAttached("Command", 
            typeof(ICommand), 
            typeof(MouseDoubleClick), 
            new UIPropertyMetadata(CommandChanged));

    public static DependencyProperty CommandParameterProperty = 
        DependencyProperty.RegisterAttached("CommandParameter",
        typeof(object),
        typeof(MouseDoubleClick),
        new UIPropertyMetadata(null));

    public static void SetCommand(DependencyObject target, ICommand value)
    {
        target.SetValue(CommandProperty, value);
    }

    public static void SetCommandParameter(DependencyObject target, object value)
    {
        target.SetValue(CommandParameterProperty, value);
    }

    public static object GetCommandParameter(DependencyObject target)
    {
        return target.GetValue(CommandParameterProperty);
    }

    public static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        Control control = target as Control;

        if(control != null)
        {
            if((args.NewValue != null) && (args.OldValue == null))
            {
                control.MouseDoubleClick += OnMouseDoubleClick;
            }
            else if((args.NewValue == null) && (args.OldValue != null))
            {
                control.MouseDoubleClick -= OnMouseDoubleClick;
            }
        }
    }

    private static void OnMouseDoubleClick(object sender, RoutedEventArgs e)
    {
        Control control = sender as Control;
        ICommand command = (ICommand)control.GetValue(CommandProperty);

        object commandParameter = control.GetValue(CommandParameterProperty);
        command.Execute(commandParameter);
    }

}

我面临的问题是它说“ViewableTIADevice”不是 FrameWorkElement,因此我什至无法运行它。

我也尝试过使用
<Style TargetType"{x:Type TreeViewItem}">

确实可以运行,但是在尝试双击 TreeView 中的项目时我没有得到任何响应。

我已经搜索了很多解决方案,我想引用这个帖子:WPF/MVVM - how to handle double-click on TreeViewItems in the ViewModel?

我一直在使用上述线程作为解决方案,但是如何将该解决方案与 HierarchicalDatatemplate 结合使用?

编辑

我试图通过双击一个项目来调用的 ICommand
 public RelayCommand TIADeviceTreeItemDoubleClick { get; set; }

我在这里将其分配给函数的位置
 TIADeviceTreeItemDoubleClick = new RelayCommand(c => tiaDeviceTreeItemDoubleClick(c));

以及它所指的功能:
 private void tiaDeviceTreeItemDoubleClick(object value)
    {
        //code
    }

这是 ViewableTIADevice 类:
public class ViewableTIADevice
{
    public ViewableTIADevice()
    {
        DeviceItems = new List<ViewableDeviceItem>();
    }
    public string DeviceName { get; set; }

    public IList<ViewableDeviceItem> DeviceItems { get; set; }
}

最佳答案

我相信您对您的数据上下文有误解,请考虑以下示例:

<TreeView ItemsSource="{Binding Items}">
        <TreeView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ItemProperty1}"></TextBlock>
            </DataTemplate>
        </TreeView.ItemTemplate>
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="Local:MouseDoubleClick.Command"
                                Value="{Binding ElementName=DeviceTreeView, Path=DataContext.TIADeviceTreeItemDoubleClick}"/>
                <Setter Property="Local:MouseDoubleClick.CommandParameter"
                                Value="{Binding}"/>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

我的 TreeView 的数据上下文是我的 View 模型,所以当我说 ItemsSource="{Binding Items}"时,我正在绑定(bind)到我的 ViewModel 中名为 Items 的可观察集合。

TreeView.ItemTemplate 中的数据上下文是集合项中的一项。这意味着当我说 {Binding ItemProperty1} 时,我正在绑定(bind)的不是 ViewModel.ItemProprty1,而是集合 ViewModel.Items 中的单个项目。这意味着你必须有一个 ViewModel,并且在一个名为 Items 的集合中,在这个集合中你需要有 X 类型的对象,并且 X 类必须有一个名为 ItemProperty1 的属性。

TreeView.ItemContainerStyle 中的数据上下文也是集合 Items 中的一个项目,这意味着当您说 {Binding TIADeviceTreeItemDoubleClick} 时,您正在尝试绑定(bind)到集合 Items 内的类内部的 ICommand 属性。您的数据上下文不是您假设的 ViewModel,而是 ViewModel.Items 中的一个项目

所以当你使用这个时:
Value="{Binding ElementName=DeviceTreeView, Path=DataContext.TIADeviceTreeItemDoubleClick}"

您正在绑定(bind)到 TreeView 的数据上下文,即 ViewModel,它包含一个名为 TIADeviceTreeItemDoubleClick 的 ICommand 属性。

当你写这个:
{Binding TIADeviceTreeItemDoubleClick}

您正在尝试绑定(bind)到当前 TreeViewItem 的数据上下文,这是您的集合项中的一个对象。所以这只有在你将 ICommand 添加到你的集合项目中的类时才有效。

你也用这个:
<Setter Property="Local:MouseDoubleClick.CommandParameter"
                                Value="{Binding}"

在这里,显然,您在集合 Items 中发送一个项目,而不是 ViewModel。

有道理?

关于c# - 使用带有 HierarchicalDatatemplate 的附加行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48807963/

相关文章:

c# - 从鼠标位置缩放和翻译图像

c# - 使用 Angular.js 和 C# 导入文件

c# - 如何在启用分页的 gridview 中维护控件的状态?

c# - 通过 XAML 或代码隐藏进行绑定(bind)

c# - WPF 用户控件可编辑属性

c# - IQueryable<> 序列化 - C#-VS2008-WCF

WPF - 从 UserControl 发出命令时 CanExecute 不会触发

c# - 带有 LineUp/LineDown 重复按钮的自定义 WPF DataGrid 滚动条

wpf - 将 WPF 浏览器应用程序转换为 WPF 桌面应用程序

c# - 未定义的 CLR 命名空间 - 未找到解决方案