首页 > 解决方案 > WPF 绑定到三层 ObservableCollection财产

问题描述

我有 3 个具有ObservableCollection<T>彼此属性的级别子类。在MainViewModel我创建ObservableCollection<Group>的属性中,哪些Group类的元素将位于TreeView. 在每个Group班级中,我都创建了子ObservableCollection<Parameter>属性。最后在ParameterObservableCollection<ParameterValue>为存储值创建的课程中。注意:每个类都基于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");
        }
    }
}

以及 View 角色中的 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我简化了从 DB 接收的数据,用测试数据替换了嵌套的 for 循环。

  1. 我尝试以 MVVM 方式显示TreeView Parameter数据中的选定内容。ListView
  2. DataGroup必要创建类SelectedItem属性Parameter以更准确地从数据库接收数据吗?当然是 MVVM 方式。

标签: c#wpfmvvmbindingobservablecollection

解决方案


在您的 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。该选定项应为具有属性值的参数。

如果您选择 Group,则不会显示任何内容,因为 Group 没有 Values 集合。只有参数有。


推荐阅读