c# - 在具有多种对象类型的 TreeView 中处理 SelectedItemChanged

标签 c# wpf mvvm treeview

我正在尝试使用 WPF TreeView ,但在获取我想要的 SelectedItemChanged 时遇到了一些问题。我的设置目前是这样的:

一类:

[ImplementPropertyChanged]
public class TestCase
{
   public string Name { get; set; } 
   public ObservableCollection<string> DataSets { get; set; }
}

然后我在我的 View 模型中创建一个带有几个测试用例的可观察集合,并将它们绑定(bind)到 xaml,如下所示:
<TreeView
    x:Name="TestCases"
    ItemsSource="{Binding TestCases}"
    Margin="0, 10, 0, 0">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectedItemChanged">
            <i:InvokeCommandAction Command="{Binding SelectedTestCaseChangedCommand}" CommandParameter="{Binding ElementName=TestCases, Path=SelectedItem}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type testCases:TestCase}" ItemsSource="{Binding DataSets}">
                <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type system:String}" >
                <TextBlock Text="{Binding}" />
        </DataTemplate>
        </TreeView.Resources>
</TreeView>

这给了我一个很好的 TreeView ,看起来像这样:
Name 
  - DataSet
  - DataSet 
Name2 
  - DataSet
  - etc

但问题是这部分:
<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
        <i:InvokeCommandAction Command="{Binding SelectedTestCaseChangedCommand}" CommandParameter="{Binding ElementName=TestCases, Path=SelectedItem}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

如果用户选择“名称”,这可以正常工作,但如果他们单击数据集,当然会失败,因为它无法将字符串转换为 TestCase。

所以我想在这里做几件事:
  • 让它不能选择名称(只是展开它),这可能吗?
  • 当您选择一个数据集时,我希望将“父”TestCase 与所选数据集的名称一起获取。是否有可能以某种方式操纵命令参数来获得这个?

  • 我想通过做一些手动检查从后面的代码中完成它应该很容易,但是像这样的 mvvm 呢?

    更新 1 我的 View 模型中的命令方法:
        [OnCommand("SelectedTestCaseChangedCommand")]
        public void SelectedTestCaseChanged(TestCase testCase)
        {
            currentTestCase = testCase;
            MessengerInstance.Send(new SelectedTestCaseChangedMessage(testCase));
        }
    

    最佳答案

    假设你的命令是用 RelayCommand 实现的正如你提到的那样,命令看起来例如像这样:

    private ICommand _selectedTestCaseChangedCommand;
    
    public ICommand SelectedTestCaseChangedCommand
    {
        get
        {
            if (_selectedTestCaseChangedCommand == null)
            {
                _selectedTestCaseChangedCommand = new RelayCommand<object>(SelectedTestCaseChanged);
            }
    
            return _selectedTestCaseChangedCommand;
        }
    }
    

    你你定义SelectedTestCaseChanged方法与您一样,但我建议将参数类型用作 object因为对象可以是一切。然后你只需要检查你的参数/所选项目是什么。你有两种可能做到这一点。 is运算符或 as在它后面加上一个空检查。
    private void SelectedTestCaseChanged(object obj)
    {
        if (obj is TestCase)
        {
            var testCase = (TestCase)obj;
            // Work with testCase
        }
    
        if (obj is string)
        {
            // Do nothing or whatever
        }
    
        // Another option is
        var testCase = obj as TestCase;
        if (testCase != null)
        {
            //...
        }
    }
    

    如果你想得到 TreeViewItem 的父级你需要上Visual Tree WPF,因为 TreeViewItems没有父元素。

    方法描述in this SO Question .

    您可以获取所选元素的父元素并使用父元素触发命令。我会在后面的代码中执行此操作,但我在那里没有经验。

    我不会禁用名称的选择,因为通过上面的解决方案,您可以处理您不想要的情况。此外,用户觉得禁用的名称是一个错误..

    希望能帮助到你

    关于c# - 在具有多种对象类型的 TreeView 中处理 SelectedItemChanged,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33652451/

    相关文章:

    c# - WiX 工具集 PermissionEx 问题 - 安装后应用程序无法运行

    c# - 在处理继承和集合时是否有 is/as 的替代方案?

    wpf - 如何在 WPF 中的圆中创建一个带孔的圆?

    c# - 将文本绑定(bind)到组合框中的选定项目

    c# - 从 XAML 将 ViewModel 传递给用户控件构造函数

    c# - MVVM DataGrid在刷新内容后如何设置焦点

    c# - 如何使用 C# 从网页打开事件查看器?

    C# 与 MySQL - 错误 : "Guid should contain 32 digits with 4 dashes" when trying to open the connection

    WPF 3.5 WebBrowser 控件和 ZIndex

    wpf - 如何在listview的datatemplate中订阅事件