为了账号安全,请及时绑定邮箱和手机立即绑定

WPF 将数据绑定到 DataGrid 的 TabControl

WPF 将数据绑定到 DataGrid 的 TabControl

C#
倚天杖 2023-07-22 17:00:44
我正在尝试创建一个 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.cspublic 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 也会更新。是否可以这样做,或者我需要采取不同的方法?
查看完整描述

2 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

DataContext当前作用域中绑定的上下文。是TabControl一个ItemsControl,它有一个ItemsSource需要一个IEnumerableIEnumerable<Tab>在本例中)。您应该引入一个视图模型,它充当 the DataContext,在本例中公开the绑定到的UserControl源集合。视图模型通常将托管视图可以绑定到的所有数据。视图模型通常实现接口,以便 UI 控件在绑定源更改时自动更新。ObservableCollection<Tab>TabControlINotifyPropertyChanged

Tab.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>


查看完整回答
反对 回复 2023-07-22
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

根本问题是,这些为多个项目生成内容的控件应该使用 属性(而ItemsSource不是DataContext.

该行 TabControl.DataContext = clsTabs; 应分配给TabControl.ItemsSource

此时您将在输出窗格中看到

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“选项卡”(HashCode=55467050) 上找不到“上下文”属性。BindingExpression:路径=上下文;DataItem='Tab'(哈希码=55467050);目标元素是“DataGrid”(名称=“”);目标属性是“DataContext”(类型“Object”)

该行 <DataGrid  AutoGenerateColumns="True" DataContext="{Binding Context}" /> 存在先前的问题错误的属性名称。应该是 <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Content}" /> 这样,然后你就应该很好。


查看完整回答
反对 回复 2023-07-22
  • 2 回答
  • 0 关注
  • 202 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信