WPF 绑定到三级 ObservableCollection<T> 属性
WPF Binding to three level ObservableCollection<T> property
我有 3 个级别的 subclasses,彼此具有 ObservableCollection<T>
属性。在 MainViewModel
中,我创建了 ObservableCollection<Group>
属性 Group
class 中的哪些元素将在 TreeView
中处于第一级。在每个 Group
class 中,我创建了 child ObservableCollection<Parameter>
属性。最后,在 Parameter
class 中,我创建了 ObservableCollection<ParameterValue>
来存储值。注意:每个 class 基于 INotifyPropertyChanged
接口。上代码吧。
Models.cs
:
//BaseModel implement INotifyPropertyChanged
public class ParameterValue: BaseModel
{
private DateTime dateTimeValue;
public DateTime DateTimeValue
{
get { return dateTimeValue; }
set
{
dateTimeValue = value;
NotifyPropertyChanged("DateTimeValue");
}
}
private double value;
public double Value
{
get { return value; }
set
{
this.value = value;
NotifyPropertyChanged("Value");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Parameter: BaseModel
{
public Parameter()
{
values = new ObservableCollection<ParameterValue>();
}
private ObservableCollection<ParameterValue> values;
public ObservableCollection<ParameterValue> Values
{
get { return values; }
set
{
values = value;
NotifyPropertyChanged("Values");
}
}
private int parameterId;
public int ParameterId
{
get { return parameterId; }
set
{
parameterId = value;
NotifyPropertyChanged("ParameterId");
}
}
private string parameterName;
public string ParameterName
{
get { return parameterName; }
set
{
parameterName = value;
NotifyPropertyChanged("ParameterName");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Group: BaseModel
{
public Group()
{
parameters = new ObservableCollection<Parameter>();
}
private ObservableCollection<Parameter> parameters;
public ObservableCollection<Parameter> Parameters
{
get { return parameters; }
set
{
parameters = value;
NotifyPropertyChanged("Parameters");
}
}
private int groupId;
public int GroupId
{
get { return groupId; }
set
{
groupId = value;
NotifyPropertyChanged("Id");
}
}
private string groupName;
public string GroupName
{
get { return groupName; }
set
{
groupName = value;
NotifyPropertyChanged("GroupName");
}
}
}
//Implementing INotifyPropertyChanged
public class BaseModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModels.cs
:
//BaseModel implement INotifyPropertyChanged
public class MainViewModel: BaseModel
{
public MainViewModel()
{
groups = new ObservableCollection<Group>();
//fill sample data instead of recieving from DB
for (int i = 1; i < 11; i++)
{
Group group = new Group { GroupId = i, GroupName = "Group " + i.ToString()};
groups.Add(group);
for (int j = 1; j < 11; j++)
{
Parameter param = new Parameter { ParameterId = j, ParameterName = "Parameter "+j.ToString()};
for (int k = 1; k < 51; k++)
{
ParameterValue val = new ParameterValue { DateTimeValue = DateTime.Now.AddSeconds(i*j-k), Value = (1000-k*5)/((i+j)+1)};
param.Values.Add(val);
}
group.Parameters.Add(param);
}
}
int l = 0;
}
private ObservableCollection<Group> groups;
public ObservableCollection<Group> Groups
{
get { return groups; }
set
{
groups = value;
NotifyPropertyChanged("Groups");
}
}
}
和MainWindow.xaml在查看角色中:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1" Background="Bisque" ItemsSource="{Binding Path=Groups.Parameters}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
在MainViewModel
中,我简化了从数据库接收数据的过程,用测试数据替换为嵌套的for循环。
- 我尝试以 MVVM 方式在
TreeView
Parameter
中显示 ListView
中的数据。
- 在
DataGroup
中需要创建 SelectedItem
属性 的 Parameter
class 以便从 DB 接收更准确的数据?当然是 MVVM 方式。
在您的 ListView ItemSource 中,您必须像这样绑定到值...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1"
Background="Bisque"
ItemsSource="{Binding SelectedItem.Values, ElementName=trv}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
观察我如何绑定到您的 TreeView 的 SelectedItem。 selected 项应该是具有 属性 值的参数。
如果您 select Group 则不会显示任何内容,因为 Group 没有 Values 集合。只有参数有那个。
我有 3 个级别的 subclasses,彼此具有 ObservableCollection<T>
属性。在 MainViewModel
中,我创建了 ObservableCollection<Group>
属性 Group
class 中的哪些元素将在 TreeView
中处于第一级。在每个 Group
class 中,我创建了 child ObservableCollection<Parameter>
属性。最后,在 Parameter
class 中,我创建了 ObservableCollection<ParameterValue>
来存储值。注意:每个 class 基于 INotifyPropertyChanged
接口。上代码吧。
Models.cs
:
//BaseModel implement INotifyPropertyChanged
public class ParameterValue: BaseModel
{
private DateTime dateTimeValue;
public DateTime DateTimeValue
{
get { return dateTimeValue; }
set
{
dateTimeValue = value;
NotifyPropertyChanged("DateTimeValue");
}
}
private double value;
public double Value
{
get { return value; }
set
{
this.value = value;
NotifyPropertyChanged("Value");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Parameter: BaseModel
{
public Parameter()
{
values = new ObservableCollection<ParameterValue>();
}
private ObservableCollection<ParameterValue> values;
public ObservableCollection<ParameterValue> Values
{
get { return values; }
set
{
values = value;
NotifyPropertyChanged("Values");
}
}
private int parameterId;
public int ParameterId
{
get { return parameterId; }
set
{
parameterId = value;
NotifyPropertyChanged("ParameterId");
}
}
private string parameterName;
public string ParameterName
{
get { return parameterName; }
set
{
parameterName = value;
NotifyPropertyChanged("ParameterName");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Group: BaseModel
{
public Group()
{
parameters = new ObservableCollection<Parameter>();
}
private ObservableCollection<Parameter> parameters;
public ObservableCollection<Parameter> Parameters
{
get { return parameters; }
set
{
parameters = value;
NotifyPropertyChanged("Parameters");
}
}
private int groupId;
public int GroupId
{
get { return groupId; }
set
{
groupId = value;
NotifyPropertyChanged("Id");
}
}
private string groupName;
public string GroupName
{
get { return groupName; }
set
{
groupName = value;
NotifyPropertyChanged("GroupName");
}
}
}
//Implementing INotifyPropertyChanged
public class BaseModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModels.cs
:
//BaseModel implement INotifyPropertyChanged
public class MainViewModel: BaseModel
{
public MainViewModel()
{
groups = new ObservableCollection<Group>();
//fill sample data instead of recieving from DB
for (int i = 1; i < 11; i++)
{
Group group = new Group { GroupId = i, GroupName = "Group " + i.ToString()};
groups.Add(group);
for (int j = 1; j < 11; j++)
{
Parameter param = new Parameter { ParameterId = j, ParameterName = "Parameter "+j.ToString()};
for (int k = 1; k < 51; k++)
{
ParameterValue val = new ParameterValue { DateTimeValue = DateTime.Now.AddSeconds(i*j-k), Value = (1000-k*5)/((i+j)+1)};
param.Values.Add(val);
}
group.Parameters.Add(param);
}
}
int l = 0;
}
private ObservableCollection<Group> groups;
public ObservableCollection<Group> Groups
{
get { return groups; }
set
{
groups = value;
NotifyPropertyChanged("Groups");
}
}
}
和MainWindow.xaml在查看角色中:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1" Background="Bisque" ItemsSource="{Binding Path=Groups.Parameters}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
在MainViewModel
中,我简化了从数据库接收数据的过程,用测试数据替换为嵌套的for循环。
- 我尝试以 MVVM 方式在
TreeView
Parameter
中显示ListView
中的数据。 - 在
DataGroup
中需要创建SelectedItem
属性 的Parameter
class 以便从 DB 接收更准确的数据?当然是 MVVM 方式。
在您的 ListView ItemSource 中,您必须像这样绑定到值...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1"
Background="Bisque"
ItemsSource="{Binding SelectedItem.Values, ElementName=trv}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
观察我如何绑定到您的 TreeView 的 SelectedItem。 selected 项应该是具有 属性 值的参数。
如果您 select Group 则不会显示任何内容,因为 Group 没有 Values 集合。只有参数有那个。