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;
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
CodePudding user response:
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>
CodePudding user response:
[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>