【问题标题】:How can I bind Wpf DataGridColumn to an object?如何将 Wpf DataGridColumn 绑定到对象?
【发布时间】:2010-10-27 09:48:15
【问题描述】:

我想将我的 WPF DataGrid 的列绑定到 Dictionary 中的一些对象,如下所示:

绑定路径=对象[i]

其中 Objects 是我的对象字典,因此每个单元格将代表一个 Object 元素。我该怎么做?

我想我需要为我的单元格创建一个模板,我已经这样做了,但是如何在我的模板中获取列绑定的结果?我知道默认情况下 DataGridCell 的内容是 TextBlock 并且它的 Text 属性是通过列绑定结果设置的,但是如果该结果是一个对象,我想我必须创建一个 ContentTemplate。我该怎么做,因为我尝试过的东西没有显示任何东西。

这是我尝试过的:

<Style x:Key="CellStyle" TargetType="{x:Type dg:DataGridCell}">
    <Setter Property="Template"> ---it should realy be ContentTemplate?
      <Setter.Value>
        <ControlTemplate>
          <controls:DataGridCellControl CurrentObject="{Binding }"/> -- I would expect to get the object like this for this column path : Path=Objects[i] but is not working
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

所以,为了让自己完全清楚,我想在我的 DataGridCellControl 的 CurrentObject 属性中获取当前对象,如果我在我的数据网格中设置列绑定,例如 Path=Objects[i]。

感谢您的任何建议,

约翰。

【问题讨论】:

    标签: wpf datagrid


    【解决方案1】:

    试试这个:

    <ListView x:Name="listViewUsers" SelectionMode="Single" 
                                  ItemsSource="{Binding ElementName=window1, Path=Users, Mode=TwoWay}" MouseDoubleClick="listViewUsers_MouseDoubleClick">
                            <ListView.View>
                                <GridView x:Name="gridViewUsers" AllowsColumnReorder="False">
                                    <GridViewColumn>
                                        <GridViewColumn.CellTemplate>
                                            <DataTemplate>
                                                <Image Source="{Binding Path=IsAdministrator, Converter={StaticResource boolToImage}, ConverterParameter='Images/admin18.gif|Images/user18.gif'}" />
                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>
                                    <GridViewColumn Header="User Name" DisplayMemberBinding="{Binding Path=UserName}" Width="140" />
                                    <GridViewColumn Header="Full Name" DisplayMemberBinding="{Binding Path=FullName}" Width="140" />
                                    <GridViewColumn Header="Phone Number" DisplayMemberBinding="{Binding Path=PhoneNumber}" Width="110" />
                                    <GridViewColumn Header="Access Type" DisplayMemberBinding="{Binding Path=AccessType}" Width="110">
                                    </GridViewColumn>
                                    <GridViewColumn>
                                        <GridViewColumn.CellTemplate>
                                            <DataTemplate>
                                                <Image Cursor="Hand" ToolTip="Delete User" Stretch="None" Source="Images/trash12.gif" MouseUp="DeleteUser" />
                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>
                                </GridView>
                            </ListView.View>
                        </ListView>
    

    ItemsSource="{Binding ElementName=window1, Path=Users, Mode=TwoWay}"

    • ElementName 是 XAML 中 Window 的名称(只需将 x:Name="window1" 与任何其他控件一样添加到 Window 标记。

    • Users 是一个 List,应该和 Dictionary 一样工作

    • Mode=TwoWay 表示如果网格被修改,列表也会被修改,反之亦然(双向绑定)

    编辑:

    试试这个:

    XAML:

    <ListView x:Name="listViewTest" ItemsSource="{Binding}">
    <ListView.View>
        <GridView x:Name="gridViewTest">
    
        </GridView>
    </ListView.View>
    </ListView>
    

    C#:

    public class TheClass
        {
            public int Col1, Col2, Col3; 
            public Dictionary<int, OtherColumns> otherColumns = new Dictionary<int,OtherColumns>();
        }
    
        public class OtherColumns
        {
            public string ColumnName;
            public int Value;
        }
    

    并在Window_Loaded下调用这个方法:

    private void PopulateListView()
            {
                TheClass c = new TheClass();
    
                c.Col1 = 10;
                c.Col2 = 20;
                c.Col3 = 30;
    
    
                c.otherColumns.Add(0, new OtherColumns() { ColumnName = "Col4", Value = 40 });
                c.otherColumns.Add(1, new OtherColumns() { ColumnName = "Col5", Value = 50 });
                c.otherColumns.Add(3, new OtherColumns() { ColumnName = "Col6", Value = 60 });
    
                DataTable table = new DataTable();
    
    // adding regular columns
                table.Columns.Add("Col1", typeof(int));
                table.Columns.Add("Col2", typeof(int));
                table.Columns.Add("Col3", typeof(int));
    
    // adding dynamic columns
                foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
                {
                    table.Columns.Add(pair.Value.ColumnName, typeof(int));
                }
    
                DataRow row = table.NewRow();
    
    // adding regular column values to the DataTable
                row["Col1"] = c.Col1;
                row["Col2"] = c.Col2;
                row["Col3"] = c.Col3;
    
    // adding dynamic column values to the DataTable
                foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
                {
                    row[pair.Value.ColumnName] = pair.Value.Value;
                }
    
                table.Rows.Add(row);
    
                // Start binding the table.
                gridViewTest.Columns.Clear();
    
                System.Windows.Controls.GridViewColumn gvc;
                Binding binding;
    
                foreach (DataColumn column in table.Columns)
                {
                    gvc = new System.Windows.Controls.GridViewColumn();
                    binding = new System.Windows.Data.Binding();
                    binding.Path = new PropertyPath(column.ColumnName);
                    binding.Mode = BindingMode.OneWay;
                    gvc.Header = column.Caption;
                    gvc.DisplayMemberBinding = binding;
                    gridViewTest.Columns.Add(gvc);
                }
    
                listViewTest.DataContext = table;
            }
    

    我并不是说这是最好的解决方案,但它会有所帮助。告诉我。

    【讨论】:

    • 感谢 Carlo 的重播,虽然 WPF DataGrid 有类似的方法吗?问候,约翰
    • 哦,还有别的,我动态创建列,所以我需要一个适用于所有单元格的全局 CellTemplate。关于如何实现这一目标的任何想法?
    • 也许您应该从字典中创建数据表并将数据网格绑定到该数据表,您认为这会对您有所帮助吗?
    • 我不知道该怎么做。我的场景如下:我的数据源是 ObservableColection。对象看起来像这样: class Object { int Col1,Col2,Col3;字典 otherColumns;现在 otherColumns 是动态设置的,可以随时更新。我认为您最初使用 ListView 提出的方法会奏效,我对 ListView 并不熟悉,但我认为可以像 DataGrid 一样设置和使用它。我找不到任何必须迁移到 ListView 的解决方案。可以在 ListView 上定义一个全局 CellTemplate 吗?
    • 我不认为有,我只在每个 GridViewColumn (GridViewColumn.CellTemplate) 下使用它,就像在我的示例中一样。试试我在编辑中添加的代码,我会对此进行更多调查。
    【解决方案2】:

    我创建了一些辅助类,以便可以将 DataGrid 用作一种 DataTable。换句话说,我想要 DataGrid 的格式化、排序和优美的外观,而不必事先预制一些类。我想要这个的主要原因是为了一个测试套件,我希望能够在运行时创建任意数量的列。这是我得到的

    public class DataRow
    {
        internal List<object> Items = new List<object>();
    
        public object this[string value]
        {
            get { return Items[Convert.ToInt32(value)]; }
        }
    
        public string GetString(int index)
        {
            return Items[index].ToString();
        }
    
        public object GetObject(int index)
        {
            return Items[index];
        }
    
        public DataRow(params object[] values)
        {
            if (values == null || values.Length < 1)
                throw new Exception("You must pass in some values");
    
            Items.AddRange(values);            
        }
    }  
    
    public class GridConstructor
    {
        public List<DataRow> Rows = new List<DataRow>();
        private DataRow headers;
    
        public GridConstructor(DataRow head)
        {
            headers = head;
        }
    
        public void BuildInto(DataGrid grid)
        {
            grid.AutoGenerateColumns = false;
            grid.Columns.Clear();
            int totalCols = 0;
    
            Type headType = headers.GetType();
    
            for (int i = 0; i < headers.Items.Count; i++)
            {
                grid.Columns.Add(GetCol(headers.GetString(i), String.Concat("[", i.ToString(),"]")));
                totalCols++;
            }                     
    
            int finalWidth = totalCols * (int)grid.ColumnWidth.Value + 15;
            grid.Width = finalWidth;
    
            grid.ItemsSource = Rows;
        }
    
        private DataGridTextColumn GetCol(string header, string binding)
        {
            DataGridTextColumn col = new DataGridTextColumn();
            col.IsReadOnly = true;            
            col.Header = header;
            col.Binding = new Binding(binding);
    
            return col;
        }
    
        public DataGrid Create(int colSize)
        {
            DataGrid grid = new DataGrid();
            grid.ColumnWidth = colSize;
            grid.CanUserAddRows = false;
            grid.AlternationCount = 2;
            BuildInto(grid);
            return grid;
        }
    }
    

    把这些放在一起,这是一个示例使用:

    void SimpleTest_Loaded(object sender, RoutedEventArgs e)
        {            
            DataRow headers = new DataRow("Level", "Weapon Type", "vs None", "vs Leather", "vs Studded", "vs Brigandine");            
            GridConstructor gridConstructor = new GridConstructor(headers);            
    
            var weaponType = "Slash";
            for (int level = 1; level < 10; level++)
            {
                int damage = DiceCup.RollMulti(8, level);
                int damCloth = damage - DiceCup.RollMulti(2, level);
                int damLeather = damage - DiceCup.RollMulti(3, level);
                int damStudded = damage - DiceCup.RollMulti(4, level);
                int damBrigandine = damage - DiceCup.RollMulti(5, level);
    
                DataRow row = new DataRow(level, weaponType, damage, damCloth, damLeather, damStudded, damBrigandine);
                gridConstructor.Rows.Add(row);                
            }
    
            //Create the grid.
            var grid = gridConstructor.Create(100);
    
    
            //Create a chart.
            Chart chart = new Chart();
            chart.Height = 200;
            chart.LegendTitle = "Legend";
            chart.Title = "Slash vs Armor Types";                       
            chart.DataContext = gridConstructor.Rows;            
    
    
            //Create our series, or lines.
            LineSeries slashVsNone = new LineSeries();
            slashVsNone.Title = "vs None";
            slashVsNone.DependentValueBinding = new Binding("[2]");
            slashVsNone.IndependentValueBinding = new Binding("[0]");
            slashVsNone.ItemsSource = gridConstructor.Rows;            
            chart.Series.Add(slashVsNone);
    
            //Presentation is a stackpanel on the page.            
            presentation.Children.Add(grid);
            presentation.Children.Add(chart);             
        }
    

    还有输出:

    alt text http://quiteabnormal.com/images/codeSample.jpg

    请注意,网格颜色来自页面上设置的通用样式。如果您使用 GridConstructor.BuildInto() 方法,您可以指定一个您在 Blend 或其他类似工具中预先格式化的网格。

    只有一件事,GridConstructor 对列的初始设置做了一些假设。如果您愿意,您可以更改类以使其更具可定制性,但这是我所需要的,所以我希望能够毫不费力地制作它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      • 1970-01-01
      • 2015-12-30
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多