在 Tab 和 Datagrid 上正确绑定 WPF(Collection inside Collection)

Correct Binding in WPF (Collection inside Collection) on Tab and Datagrid

我想在多个选项卡上使用不同的数据网格,但我在正确绑定方面遇到问题。

每个 TabEntry 都有一个 DataGridEntry 集合。 显示选项卡项(Tab1 和 Tab2)但 DataGridEntries 的绑定不正确。

TabEntry.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace TabControlTest
{
    public class TabEntry : INotifyPropertyChanged
    {
        public TabEntry()
        {
            DataGridEntries = new ObservableCollection<DataGridEntry>();
        }
        public string Description { get; set; }
        public ObservableCollection<DataGridEntry> DataGridEntries{get;set;}

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class DataGridEntry : INotifyPropertyChanged
    {
        public string Description { get; set; }
        public string Value { get; set; }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        ObservableCollection<TabEntry> Tabs = new ObservableCollection<TabEntry>();

        TabEntry tab1 = new TabEntry();
        tab1.Description = "Tab1";

        DataGridEntry data1 = new DataGridEntry();
        data1.Description = "Tab1 Description 1";
        data1.Value = "Tab1 Value 1";

        DataGridEntry data2 = new DataGridEntry();
        data2.Description = "Tab1 Description 2";
        data2.Value = "Tab1 Value 2";

        tab1.DataGridEntries.Add(data1);
        tab1.DataGridEntries.Add(data2);

        TabEntry tab2 = new TabEntry();
        tab2.Description = "Tab2";

        DataGridEntry data3 = new DataGridEntry();
        data1.Description = "Tab2 Description 1";
        data1.Value = "Tab1 Value 1";

        DataGridEntry data4 = new DataGridEntry();
        data2.Description = "Tab2 Description 2";
        data2.Value = "Tab1 Value 2";

        tab2.DataGridEntries.Add(data3);
        tab2.DataGridEntries.Add(data4);

        Tabs.Add(tab1);
        Tabs.Add(tab2);
        this.DataContext = Tabs;        
        InitializeComponent();
    }
}

Tabs 是一个包含 tabEntries 的集合(classTabEntry) 每个 TabEntry 都有一个带有 DataGridEntries(class DataGridEntry) 的集合 如何在 xaml 中正确绑定到这些集合?

<Window x:Class="TabControlTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TabControlTest"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <TabControl x:Name="tabControl1" ItemsSource="{Binding}" TabStripPlacement="Left" HorizontalAlignment="Left" Height="242" Margin="10,10,0,0" VerticalAlignment="Top" Width="358">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Description}"></TextBlock>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <DataGrid x:Name="dataGrid1" ItemsSource="{Binding DataGridEntries}">
                        <DataGrid.Columns>
                        <DataGridTextColumn Header="Description" Binding="{Binding Description}"></DataGridTextColumn>
                        <DataGridTextColumn Header="Value" Binding="{Binding Value}"></DataGridTextColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

我有以下输出:

内容未正确映射到 TabControl 和 DataGrid。

Tab2 上的 Datagrid 是空白的

您的成员 DataGridEntries 必须是 属性 才能用于绑定:

public class TabEntry : INotifyPropertyChanged
{
    public TabEntry()
    {
        DataGridEntries = new ObservableCollection<DataGridEntry>();
    }
    public string Description { get; set; }
    public ObservableCollection<DataGridEntry> DataGridEntries { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
}

旁注: 仅实现 INotifyPropertyChanged 是不够的 - 您还需要在 getter 方法中调用事件。实施 getters 或使用例如Fody...

这里是你正在尝试做的更清晰的实现 Xaml

<Window x:Class="WpfApplication34.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfApplication34="clr-namespace:WpfApplication34"
    Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>

    <Grid>
        <TabControl x:Name="tabControl1" ItemsSource="{Binding Tabs}" TabStripPlacement="Left" HorizontalAlignment="Left" Height="242" Margin="10,10,0,0" VerticalAlignment="Top" Width="358">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Description}" ></TextBlock>
                </DataTemplate>
            </TabControl.ItemTemplate>

            <TabControl.ContentTemplate>
                <DataTemplate>
                    <DataGrid x:Name="dataGrid1" ItemsSource="{Binding DataGridEntries}">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Description" Binding="{Binding Desription}"></DataGridTextColumn>
                            <DataGridTextColumn Header="Value" Binding="{Binding Value}"></DataGridTextColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Grid>

和代码隐藏:

 public partial class MainWindow : Window, INotifyPropertyChanged
{
    private ObservableCollection<TabEntry> _tabs ;

    public ObservableCollection<TabEntry> Tabs
    {
        get
        {
            return _tabs;
        }

        set
        {
            if (_tabs == value)
            {
                return;
            }

            _tabs = value;
            OnPropertyChanged();
        }
    }

    public MainWindow()
    {
        InitializeComponent();
         Tabs = new ObservableCollection<TabEntry>()
        {
            new TabEntry()
            {
                Description = "Tab1",
                DataGridEntries = new ObservableCollection<DataGridEntry>()
                {
                    new DataGridEntry()
                    {
                        Description = "Tab1 Description 1",
                        Value = "Tab1 Value 1"
                    },
                    new DataGridEntry()
                    {
                        Description = "Tab1 Description 2",
                        Value = "Tab1 Value 2"
                    }
                }
            },
             new TabEntry()
            {
                Description = "Tab2",
                DataGridEntries = new ObservableCollection<DataGridEntry>()
                {
                    new DataGridEntry()
                    {
                        Description = "Tab2 Description 1",
                        Value = "Tab2 Value 1"
                    },
                    new DataGridEntry()
                    {
                        Description = "Tab2 Description 2",
                        Value = "Tab2 Value 2"
                    }
                }
            }

        };




    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class TabEntry : INotifyPropertyChanged
{



    private String _description;
    public String Description
    {
        get
        {
            return _description;
        }

        set
        {
            if (_description == value)
            {
                return;
            }

            _description = value;
            OnPropertyChanged();
        }
    }
    public ObservableCollection<DataGridEntry> DataGridEntries { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class DataGridEntry : INotifyPropertyChanged
{


    private String _description;
    public String Description
    {
        get
        {
            return _description;
        }

        set
        {
            if (_description == value)
            {
                return;
            }

            _description = value;
            OnPropertyChanged();
        }
    }
    private String _value;
    public String Value
    {
        get
        {
            return _value;
        }

        set
        {
            if (_value == value)
            {
                return;
            }

            _value = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}