WPF 将数据绑定到 DataGrid 的 TabControl

我正在尝试创建一个 UI,其中有一个 TabControl,并且每个选项卡中都有一个 DataGrid。我想动态添加/删除选项卡以及 DataGrid 的行/列。这是代码示例:


Test.xaml


<StackPanel>

        <Button x:Name="Button" Content="Add tab" Click="Button_Click"/>


        <Controls:MetroAnimatedTabControl x:Name="TabControl"

                                          TabStripPlacement="Left" 

                                          DisplayMemberPath="TabName">

                <TabControl.ContentTemplate>

                    <DataTemplate>

                        <DataGrid  AutoGenerateColumns="True" DataContext="{Binding Context}" />

                    </DataTemplate>

                </TabControl.ContentTemplate>

        </Controls:MetroAnimatedTabControl>

</StackPanel>

以及隐藏的代码


Test.xaml.cs


public class Tab

{

    public string TabName { get; set; }

    public DataTable Content { get; set; }


    public Tab(string name, DataTable content)

    {

        TabName = name;

        Content = content;

    }


    public Tab(string name, List<string[]> content)

    {


        Content = new DataTable();

        foreach (var item in content){

            Content.Columns.Add(item[0], typeof(string));

        }

        DataRow row = Content.NewRow();

        foreach (var item in content)

        {

            row[item[0]] = item[1];

        }

        Content.Rows.Add(row);

        TabName = name;

    }

}

它可以编译,但是当您运行该应用程序时,窗口中没有显示任何内容。数据绑定很可能是错误的(尤其是 DataGrid,因为我不知道如何使用像我这样的类来做到这一点)。


如果代码中不清楚,在我的Tab类中,我有TabName选项卡名称的属性,并且ContentDataTable 应该是相应 DataGrid 中的数据源。我想以某种方式将它们绑定到 xaml,如果实例被修改,UI 也会更新。


是否可以这样做,或者我需要采取不同的方法?


倚天杖
浏览 386回答 2
2回答

温温酱

是DataContext当前作用域中绑定的上下文。是TabControl一个ItemsControl,它有一个ItemsSource需要一个IEnumerable(IEnumerable<Tab>在本例中)。您应该引入一个视图模型,它充当 the DataContext,在本例中公开the绑定到的UserControl源集合。视图模型通常将托管视图可以绑定到的所有数据。视图模型通常实现接口,以便 UI 控件在绑定源更改时自动更新。ObservableCollection<Tab>TabControlINotifyPropertyChangedTab.cs(选项卡控件将绑定到的数据模型):public class Tab{    public string TabName { get; set; }    public DataTable Content { get; set; }    public Tab(string name, DataTable content)    {        TabName = name;        Content = content;    }    public Tab(string name, List<string[]> content)    {        Content = new DataTable();        foreach (var item in content){            Content.Columns.Add(item[0], typeof(string));        }        DataRow row = Content.NewRow();        foreach (var item in content)        {            row[item[0]] = item[1];        }        Content.Rows.Add(row);        TabName = name;    }}ViewModel.cs(DataContext将集合UserControl公开Tab为绑定上下文的):class ViewModel : INotifyPropertyChanged{  public ViewModel()  {    this.ClsTabs = new ObservableCollection<Tab>();    ClsTabs.Add(new Tab("Animals", new List<string[]>() { new string[] { "Name", "Tiger" }, new string[] { "Tail", "Yes" } }));    ClsTabs.Add(new Tab("Vegetables", new List<string[]>() { new string[] { "Name", "Tomato" }, new string[] { "Color", "Red" }, new string[] { "Taste", "Good" } }));    ClsTabs.Add(new Tab("Cars", new List<string[]>() { new string[] { "Name", "Tesla" } }));  }  private ObservableCollection<Tab> clsTabs;  public ObservableCollection<Tab> ClsTabs  {    get => this.clsTabs;    set    {      if (Equals(value, this.clsTabs)) return;      this.clsTabs = value;      OnPropertyChanged();    }  }  public event PropertyChangedEventHandler PropertyChanged;  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)  {    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  }}测试.xaml.cs:public partial class Test: UserControl{    public Test()    {        InitializeComponent();    }    private void Button_Click(object sender, RoutedEventArgs e)    {        (this.DataContext as ViewModel)?.ClsTabs.Add(new Tab("New", new List<string[]>() { new string[] { "Name", "Something" }, new string[] { "Detail", "No" } }));    }}测试.xaml<UserControl x:Class="WpfTestRange.Main.Test">  <!-- Set the DataContext of the Test control to an instance of ViewModel -->  <UserControl.DataContext>    <local:ViewModel />  </UserControl.DataContext>  <Grid>    <StackPanel>      <Button x:Name="Button"              Content="Add tab"              Click="Button_Click" />      <MetroAnimatedTabControl x:Name="TabControl"                   ItemsSource="{Binding ClsTabs}"                  TabStripPlacement="Left"                  DisplayMemberPath="TabName">        <TabControl.ContentTemplate>          <DataTemplate DataType="local:Tab">            <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Content}" />          </DataTemplate>        </TabControl.ContentTemplate>      </TabControl>    </StackPanel>  </Grid></UserControl>

慕运维8079593

根本问题是,这些为多个项目生成内容的控件应该使用 属性(而ItemsSource不是DataContext.该行&nbsp;TabControl.DataContext = clsTabs;&nbsp;应分配给TabControl.ItemsSource此时您将在输出窗格中看到System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“选项卡”(HashCode=55467050) 上找不到“上下文”属性。BindingExpression:路径=上下文;DataItem='Tab'(哈希码=55467050);目标元素是“DataGrid”(名称=“”);目标属性是“DataContext”(类型“Object”)该行&nbsp;<DataGrid &nbsp;AutoGenerateColumns="True" DataContext="{Binding Context}" />&nbsp;存在先前的问题和错误的属性名称。应该是&nbsp;<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Content}" />&nbsp;这样,然后你就应该很好。
打开App,查看更多内容
随时随地看视频慕课网APP