简体   繁体   中英

How do I bind an object that is periodically modified to a treeview in C# WPF using the CommunityToolkit.MVVM?

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" Background="#282828" BorderThickness="0" Padding="0,5,0,0"
                  SelectedValuePath="Uid">
                 <TreeViewItem x:Name="tLines" 
                        ItemsSource="{Binding Source={StaticResource myLines}, Path=MyLines}"
                        Style="{StaticResource custTVItem}" Header="Lines" Uid="tabLines">
                <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; 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" 
                        ItemsSource="{Binding Source={StaticResource myLines}, Path=linesCollection}"
                        Style="{StaticResource custTVItem}" Header="Lines" Uid="tabLines">

Please advise if you can help

Replace all List<T> properties with ObservableCollection<T> . Then the view will be updated whenever you add or remove items from these collections.

For the view to also update when you change a property of an individual item in a collection, the class of the property that you change should implement the INotifyPropertyChanged interface and raise change notifications.

Here is an example of how you should implement the Lines class:

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

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

Bind to the generated properties (starting with an uppercase letter):

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

[NotifyPropertyChangedFor(nameof(MainWindow.treeData.ItemsSource))] does not need to be added.

There is no need to implement additional notifications. Because [ObservableProperty] is already implementing the notification function. 在此处输入图像描述 Check out the auto-generated sources.

[NotifyPropertyChangedFor(parameter)] 's parameter should be the name of property inside the class.

public partial class TreeLines : ObservableObject
{
    [ObservableProperty]
    private List<Lines>? myLines;

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

In this case, the possible Arguments of [NotifyPropertyChangedFor] are only MyLines, OtherProperty1, and OtherProperty2.

[NotifyPropertyChangedFor] is an attribute indicating that other properties connected within the class have changed

Here's an example.

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

When calling the setter of Num1 Property, simultaneously update the Num1 value and Sum value bound to the screen.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM