WPF使用嵌套属性

时间:2016-12-30 10:23:15

标签: c# wpf data-binding datagrid observablecollection

我想将DataGrid绑定到嵌套属性的集合。 我尝试了解决方案 WPF: Bound datagrid does not update items properties 但到目前为止没有运气。

我得到的是一个空的DataGrid和Console输出:

  

System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。 BindingExpression:路径= AGNR.Key;的DataItem = NULL;目标元素是' DataGridTextColumn' (的HashCode = 38805039);目标属性是'标题' (键入'对象')

也是从tcc_CollectionChanged(但不是PropertyChangedHandler)输出:

  

30.12.2016 11:11:22,收藏已更改

我使用Modern UI(firstfloor)框架。这是我的Window代码:

public partial class Home : UserControl
{

    private ObservableTable<TableClass> tcc;

    public Home()
    {
        InitializeComponent();
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        TableClass tc;
        List<TableClass> tcl = new List<TableClass>();

        tcc = new ObservableTable<TableClass>();

        tcc.CollectionChanged += tcc_CollectionChanged;
        tcc.ItemPropertyChanged += PropertyChangedHandler;

        for (int i = 0; i < 10; i++)
        {
            tc = new TableClass();

            tc.AGNR.Name = "AGNr";
            tc.AGNR.Value = i.ToString();

            tc.MNR.Name = "MNr";
            tc.MNR.Value = i.ToString() + " M";

            tc.MST.Name = "MSt";
            tc.MST.Value = i % 2 == 0 ? "production" : "stopped";

            tcc.Add(tc);
        }

    }

    static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine(DateTime.Now.ToString() + ", Property changed");
        return;
    }

    static void tcc_CollectionChanged(object sender, EventArgs e)
    {
        Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
        return;
    }
}

对应的XAML:

<UserControl x:Class="MuiWpfTestApp.Pages.Home"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         Loaded="UserControl_Loaded">
<Grid Style="{StaticResource ContentRoot}">
    <ScrollViewer>
        <DataGrid x:Name="tcgrid" ItemsSource="{Binding tcc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="250" Width="250">
            <DataGridTextColumn Binding="{Binding AGNR.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding AGNR.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Binding="{Binding MNR.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding MNR.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Binding="{Binding MST.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding MST.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
        </DataGrid>
    </ScrollViewer>
</Grid>

INotifyPropertyChanged在TableClass中实现:

 class TableClass : INotifyPropertyChanged
{
    private KeyValueClass _mnr;
    private KeyValueClass _agnr;
    private KeyValueClass _mst;

    public KeyValueClass MNR
    {
        get
        {
            return _mnr;
        }
        set
        {
            _mnr = value;
            NotifyPropertyChanged("MNR");
        }
    }
    public KeyValueClass AGNR
    {
        get
        {
            return _agnr;
        }
        set
        {
            _agnr = value;
            NotifyPropertyChanged("AGNR");
        }
    }
    public KeyValueClass MST
    {
        get
        {
            return _mst;
        }
        set
        {
            _mst = value;
            NotifyPropertyChanged("MST");
        }
    }

    public TableClass()
    {
        MNR = new KeyValueClass();
        AGNR = new KeyValueClass();
        MST = new KeyValueClass();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

KeyValueClass非常简单(我在这里需要什么?):

class KeyValueClass
{
    private string _name;
    private string _val;

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }
    public string Value
    {
        get
        {
            return _val;
        }
        set
        {
            _val = value;
        }
    }
}

我在Collection中需要这个嵌套的属性,因为我可以用不同的语言获取这些数据。所以我无法对网格的标题进行编码。

1 个答案:

答案 0 :(得分:0)

由于您只能绑定到公共属性,因此您必须定义&#34; tcc&#34;因此。您的TableClass和KeyValueClass类型也必须是公共的:

public partial class Home : UserControl
{
    public ObservableCollection<TableClass> tcc { get; set; }

    public Home()
    {
        InitializeComponent();
        tcc = new ObservableCollection<TableClass>();
        DataContext = this;
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        TableClass tc;
        List<TableClass> tcl = new List<TableClass>();

        tcc.CollectionChanged += tcc_CollectionChanged;

        for (int i = 0; i < 10; i++)
        {
            tc = new TableClass();

            tc.AGNR.Name = "AGNr";
            tc.AGNR.Value = i.ToString();

            tc.MNR.Name = "MNr";
            tc.MNR.Value = i.ToString() + " M";

            tc.MST.Name = "MSt";
            tc.MST.Value = i % 2 == 0 ? "production" : "stopped";

            tcc.Add(tc);
        }

    }

    static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine(DateTime.Now.ToString() + ", Property changed");
        return;
    }

    static void tcc_CollectionChanged(object sender, EventArgs e)
    {
        Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
        return;
    }
}

public class TableClass : INotifyPropertyChanged
{
    private KeyValueClass _mnr;
    private KeyValueClass _agnr;
    private KeyValueClass _mst;

    public KeyValueClass MNR
    {
        get
        {
            return _mnr;
        }
        set
        {
            _mnr = value;
            NotifyPropertyChanged("MNR");
        }
    }
    public KeyValueClass AGNR
    {
        get
        {
            return _agnr;
        }
        set
        {
            _agnr = value;
            NotifyPropertyChanged("AGNR");
        }
    }
    public KeyValueClass MST
    {
        get
        {
            return _mst;
        }
        set
        {
            _mst = value;
            NotifyPropertyChanged("MST");
        }
    }

    public TableClass()
    {
        MNR = new KeyValueClass();
        AGNR = new KeyValueClass();
        MST = new KeyValueClass();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

public class KeyValueClass
{
    private string _name;
    private string _val;

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }
    public string Value
    {
        get
        {
            return _val;
        }
        set
        {
            _val = value;
        }
    }
}

没有内置的ObservableTable类,所以我在上面的示例代码中将此更改为ObservableCollection。

您还应该将列添加到DataGrid的集合中:

<DataGrid x:Name="tcgrid" ItemsSource="{Binding tcc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding AGNR.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding AGNR.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
        <DataGridTextColumn Binding="{Binding MNR.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding MNR.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
        <DataGridTextColumn Binding="{Binding MST.Value, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" 
                                Header="{Binding MST.Key, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
    </DataGrid.Columns>
</DataGrid>

然后似乎有效: