XAML 如何使用CommunityToolkit.MVVM在C# WPF中将定期修改的对象绑定到树视图?

lzfw57am  于 2022-12-07  发布在  C#
关注(0)|答案(2)|浏览(465)

I have a treeView defined in XAML as:

<UserControl.Resources>
    <models:TreeLines x:Key="myLines" x:Name="myLinesData"/>
</UserControl.Resources>

<TreeView
    x:Name="treeData"
    Grid.Column="1"
    Padding="0,5,0,0"
    Background="#282828"
    BorderThickness="0"
    SelectedValuePath="Uid">
    <TreeViewItem
        x:Name="tLines"
        Uid="tabLines"
        Header="Lines"
        ItemsSource="{Binding Source={StaticResource myLines}, Path=MyLines}"
        Style="{StaticResource custTVItem}">
        <TreeViewItem.Resources>
            <HierarchicalDataTemplate DataType="{x:Type models:Lines}" ItemsSource="{Binding lineSet}">
                <TextBlock Text="{Binding productName}" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type models:LineSets}" ItemsSource="{Binding lineName}">
                <TextBlock Text="{Binding setName}" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type models:LineNames}" ItemsSource="{Binding dataTypes}">
                <TextBlock Text="{Binding lineName}" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type models:LineData}" ItemsSource="{Binding dataVals}">
                <TextBlock Text="{Binding dataType}" />
            </HierarchicalDataTemplate>
        </TreeViewItem.Resources>
    </TreeViewItem>
</TreeView>

The UserControl.Resources is pointing towards a class:

public partial class TreeLines : ObservableObject
{
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(MainWindow.treeData.ItemsSource))]
    private List<Lines>? myLines;
}

The error I get here is:
The target(s) of [NotifyPropertyChangedFor] must be a (different) accessible property
The object myLines I'm trying to bind to has the classes behind, as seen in the TreeView `HierarchicalDataTemplates:

public class Lines
{
    public string productName { get; set; }
    public List<LineSets> lineSet { get; set; }
}

public class LineSets
{
    public string setName { get; set; }
    public List<LineNames> lineName { get; set; }
}

public class LineNames
{
    public string lineName { get; set; }
    public List<LineData> dataTypes { get; set; }
}

public class LineData
{
    public string dataType { get; set; }
    public List<double> dataVals { get; set; }
}

If I remove all the CommunityToolkit.MVVM aspects and set my variable: private List<Lines>? myLines; manually by changing it to public and assigning data to it on loading, then it populates on load only.
I need to modify myLines on the fly within my C# code which in-turn should update the treeView. You can see I'm trying to achieve this automatically with the data binding but something isn't right.
I think the mistakes could possibly be in the line:
[NotifyPropertyChangedFor(nameof(MainWindow.treeData.ItemsSource))]
and/or possibly the StaticResource usage in XAML:

<TreeViewItem
    x:Name="tLines"
    Uid="tabLines"
    Header="Lines"
    ItemsSource="{Binding Source={StaticResource myLines}, Path=linesCollection}"
    Style="{StaticResource custTVItem}">

Please advise if you can help

sz81bmfz

sz81bmfz1#

将所有List<T>属性替换为ObservableCollection<T>。这样,每当您在这些集合中添加或删除项时,视图都会更新。
若要让检视在您变更集合中个别项目的属性时也更新,您所变更之属性的类别应该实作INotifyPropertyChanged界面并引发变更告知。
下面是一个如何实现Lines类的示例:

public class Lines : ObservableObject
{
    [ObservableProperty]
    private string productName { get; set; }

    [ObservableProperty]
    private ObservableCollection<LineSets> lineSet { get; set; }
}

绑定到生成的 * 属性 *(以大写字母开头):

<HierarchicalDataTemplate DataType="{x:Type models:Lines}"
                          ItemsSource="{Binding LineSet}">
    <TextBlock Text="{Binding ProductName}"/>
</HierarchicalDataTemplate>
gwbalxhn

gwbalxhn2#

不需要添加**[通知属性更改对象((主窗口.树数据.项源)的名称)]
不需要实现其他通知。因为
[ObservableProperty]**已经实现了通知函数。

请查看自动生成的源代码。

  • *[NotifyPropertyChangedFor(参数)]**的参数应该是类别内的属性名称。
public partial class TreeLines : ObservableObject
{
    [ObservableProperty]
    private List<Lines>? myLines;

    public string OtherProperty1 { get; set; }
    public string OtherProperty2 { get; set; }
}

在这种情况下,**[NotifyPropertyChangedFor]**的可能参数只有MyLines、OtherProperty1和OtherProperty2。

  • *[NotifyPropertyChangedFor]**是一个属性,指示类内连接的其他属性已更改

这里有一个例子。

public partial class GetSum : ObservableObject
{
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Sum))]
    private int num1;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Sum))]
    private int num2;

    public int Sum { get => num1 + num2; }
}

调用Num1属性的setter时,同时更新绑定到屏幕的Num1值和Sum值。

<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp2"
        Height="450" Width="800">
    <Window.DataContext>
        <local:GetSum/>
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Num1}"/>
        <TextBox Text="{Binding Num2}"/>
        <TextBlock Text="{Binding Sum}"/>
    </StackPanel>
</Window>

相关问题