Wpf DataGrid插入列,列的类型问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wpf DataGrid插入列,列的类型问题相关的知识,希望对你有一定的参考价值。

在C# winform窗口程序中 DataGird插入列允许有按钮 或者图片类型的列。
wpf程序中默认是没有的,请问wpf的DataGird可以插入 按钮列 和图片列吗?
如果可以,要怎么操作呢?

默认没提供。但是wpf提供了模板列,它允许你设置任何控件类型的列,具体操作如下。
按钮列:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="Button_Click" Tag="Binding Id"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
图片列:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="Binding ImageSource"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
我给这些列加了绑定的属性,也可以不加!~望对你有帮助^ ^
参考技术A 重DataGridTextBoxColumn类

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Data;
using System.Collections;

namespace ImageCellInDataGrid

/// <summary>
/// Summary description for DataGridImageCell.
/// </summary>
public class DataGridImageCell : DataGridTextBoxColumn

private ArrayList theImages1;
public DataGridImageCell()



public ArrayList theImages

getreturn theImages1;
settheImages1 = value;


protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush foreBrush, bool alignToRight)

object o = this.GetColumnValueAtRow(source, rowNum);
if(o != null)

int i = (int)o;
g.FillRectangle(backBrush, bounds);

Bitmap bmp = (Bitmap)theImages[i];

//GridImageCellDrawOption cellDrawOption = GridImageCellDrawOption.NoResize;
//GridImageCellDrawOption cellDrawOption = GridImageCellDrawOption.FitProportionally;
GridImageCellDrawOption cellDrawOption = GridImageCellDrawOption.FitToCell;

System.Drawing.GraphicsUnit gu = System.Drawing.GraphicsUnit.Point;

RectangleF srcRect = bmp.GetBounds(ref gu);
Rectangle destRect = Rectangle.Empty;

Region saveRegion = g.Clip;

switch(cellDrawOption)

case GridImageCellDrawOption.FitToCell:
destRect = bounds;
break;
case GridImageCellDrawOption.NoResize:
destRect = new Rectangle(bounds.X, bounds.Y, (int) srcRect.Width, (int) srcRect.Height);
g.Clip = new Region(bounds);
break;
case GridImageCellDrawOption.FitProportionally:

float srcRatio = srcRect.Width / srcRect.Height;
float tarRatio = (float) bounds.Width / bounds.Height;
destRect = bounds;
if( tarRatio < srcRatio )

destRect.Height = (int) (destRect.Width * srcRatio);

else

destRect.Width = (int) (destRect.Height * srcRatio);


break;

default:
break;


if(!destRect.IsEmpty)
g.DrawImage(bmp, destRect, srcRect, gu);

g.Clip = saveRegion;



protected override void Edit(System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)

//overridden to avoid editing


public enum GridImageCellDrawOption

FitToCell = 0,
NoResize = 1,
FitProportionally = 2,
;


测试代码

private System.Windows.Forms.DataGrid dataGrid1;

private void Form1_Load(object sender, System.EventArgs e)


//create a datatable
DataTable dt = new DataTable("MyTable");

dt.Columns.Add(new DataColumn("Col0"));
dt.Columns.Add(new DataColumn("Images",typeof(int)));

Random r = new Random();
for(int i = 0; i < nRows; ++i)

DataRow dr = dt.NewRow();
dr[0] = string.Format("row0", i);
dr[1] = r.Next(4);
dt.Rows.Add(dr);


//store bitmaps in an arraylist
bitMaps = new ArrayList();
System.IO.Stream strm = GetType().Assembly.GetManifestResourceStream("ImageCellInDataGrid.Blue hills.jpg");
bitMaps.Add(new Bitmap(strm));
strm = GetType().Assembly.GetManifestResourceStream("ImageCellInDataGrid.Sunset.jpg");
bitMaps.Add(new Bitmap(strm));
strm = GetType().Assembly.GetManifestResourceStream("ImageCellInDataGrid.Water lilies.jpg");
bitMaps.Add(new Bitmap(strm));
strm = GetType().Assembly.GetManifestResourceStream("ImageCellInDataGrid.Winter.jpg");
bitMaps.Add(new Bitmap(strm));

DataGridTableStyle tableStyle = new DataGridTableStyle();
tableStyle.MappingName = "MyTable";

DataGridTextBoxColumn tbc = new DataGridTextBoxColumn();
tbc.MappingName = "Col0";
tbc.HeaderText = "Column 1";
tbc.Width = 50;
tableStyle.GridColumnStyles.Add(tbc);

int width = this.dataGrid1.ClientSize.Width - tbc.Width - this.dataGrid1.RowHeaderWidth - 4;
DataGridImageCell tbc1 = new DataGridImageCell();
tbc1.MappingName = "Images";
tbc1.HeaderText = "Images";
tbc1.theImages = bitMaps;
tbc1.Width = width;
tableStyle.GridColumnStyles.Add(tbc1);

this.dataGrid1.TableStyles.Add(tableStyle);
this.dataGrid1.DataSource = dt;
dt.DefaultView.AllowNew = false;

Rectangle rect = this.dataGrid1.GetCellBounds(0,0);
topPos = rect.Top;
int height = (this.dataGrid1.ClientSize.Height - topPos - nRows) / nRows;
tableStyle.PreferredRowHeight = height;
this.dataGrid1.DataSource = null;
this.dataGrid1.DataSource = dt;

WPF 中的 Datagrid - 1 列默认排序

【中文标题】WPF 中的 Datagrid - 1 列默认排序【英文标题】:Datagrid in WPF - 1 column default sorted 【发布时间】:2012-02-16 06:55:15 【问题描述】:

在 WPF 中,我有一个包含几列的 DataGrid。

默认情况下,我想让它排序为 1,但我就是找不到如何做到这一点。

XAML 中的 DataGrid 如下所示:

<DataGrid x:Name="LibraryView" ItemsSource="Binding Path=Elements[Persons]" IsReadOnly="True" LoadingRow="dg_LoadingRow">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="Binding Path=Element[Name].Value" IsReadOnly="True" />
                <DataGridTextColumn Header="Score" Binding="Binding Path=Element[Score].Value" IsReadOnly="True" />
                <DataGridTextColumn Header="Date" Binding="Binding Path=Element[Date].Value" IsReadOnly="True" />
            </DataGrid.Columns>
        </DataGrid>

而它背后的唯一代码是:

public ScoreBoard()

    InitializeComponent();
    DataSet ds = dweMethods.DecryptAndDeserialize("ScoreData.xml");
    XElement TrackList = XElement.Parse(ds.GetXml());
    LibraryView.DataContext = TrackList;

我只是找不到如何使其默认按“分数”列排序。

谁能帮我指出正确的方向?

【问题讨论】:

看看 CollectionViewSource。 我已经尝试过这个:ICollectionView view = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource); view.SortDescriptions.Clear(); view.SortDescriptions.Add(new SortDescription("LastName", ListSortDirection.Ascending)); view.Refresh(); 但这似乎不适用于我上面的代码,我不知道也不明白我应该怎么做才能让它工作 您是否考虑过对您的 TrackList 子项进行排序? uuh,问题是,我现在只有 3 周深入 c#,呵呵,所以我还需要学习一些东西。所以也许我没有以正确的方式设置数据网格以便现在能够使用排序? Darjan 的解决方案成功了吗?对 XElement 进行排序非常简单——看看 XLINQ Sort。 【参考方案1】:

注意:使用 CollectionViewSource 在这些情况下将为您提供更多的权力和控制。 当您学习 WPF 时,我建议您了解如何使用 CollectionViewSource 与其他集合一起解决此问题 GroupingFiltering 等相关问题。

编辑:这可能是由于规范的变化。此答案基于使用 .NET 4.0,我尚未研究此解决方案是否适用于旧版本的框架。

鉴于此 XAML

<DataGrid x:Name="LibraryView" ItemsSource="Binding Path=Elements[Persons]" IsReadOnly="True" LoadingRow="dg_LoadingRow">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="Binding Path=Element[Name].Value" IsReadOnly="True" />
            <DataGridTextColumn Header="Score" Binding="Binding Path=Element[Score].Value" IsReadOnly="True" />
            <DataGridTextColumn Header="Date" Binding="Binding Path=Element[Date].Value" IsReadOnly="True" />
        </DataGrid.Columns>
    </DataGrid>

您需要做的就是选择一列并为该列指定排序方向。

<DataGrid x:Name="LibraryView" ItemsSource="Binding Path=Elements[Persons]" IsReadOnly="True" LoadingRow="dg_LoadingRow">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="Binding Path=Element[Name].Value" IsReadOnly="True" />
                <DataGridTextColumn Header="Score" Binding="Binding Path=Element[Score].Value" IsReadOnly="True" SortDirection="Ascending" />
                <DataGridTextColumn Header="Date" Binding="Binding Path=Element[Date].Value" IsReadOnly="True" />
            </DataGrid.Columns>
        </DataGrid>

这将默认按升序排列到第二列。

【讨论】:

DataGridTextColumn 使用MultiBinding 时,这似乎不起作用,即使设置了SortMemberPath。单击列标题将对其进行排序,但SortDirection 不会。 @Matt 这可能是使用 CollectionViewSource 会产生更好结果的情况 AFAICT SortDirection 只是在标题中设置箭头。 @fadden 出现这种情况的原因有很多。您需要展示一个具体示例来确定排序失败的原因。 这似乎设置了标题排序箭头,但实际上并未对底层集合进行排序。相反,在 CVS 上设置 SortDescriptions 会对集合进行排序,但对标题箭头没有影响。为什么我想要这个的可能用例是什么?为什么 WPF 一定要这么牛逼?【参考方案2】:

我在这里描述了如何按第一列对代码进行排序:Initial DataGrid Sorting

您可以调整代码以按您想要的特定列进行排序,尽管整个方法看起来很混乱。

如果您想在 XAML 中执行此操作...设置 CollectionViewSource.SortDescriptions 可能有效:

<CollectionViewSource x:Key="cvs" Source="StaticResource myItemsSource">
    <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="MyPropertyName" Direction="Ascending"/>
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

但我从未尝试过后者。

【讨论】:

您提供的这个链接 (***.com/questions/8944822/initial-datagrid-sorting/…) 似乎确实有效,但目前只有 1 个缺点。它对第一列进行排序(在方法中说明),但我怎样才能使它对第二列(或另一个)进行排序? 现在通过更改 Columns.First();到列[1]; (谢谢!) 您应该提及所需的命名空间xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"【参考方案3】:

您可以在后面的代码中使用ICollectionView。 假设您已定义 ObservableCollection&lt;yourPersonClass&gt; PersonsNames 是 yourPersonClass 的属性

public ICollectionView View; 
View = CollectionViewSource.GetDefaultView(Persons);
View.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
View.Refresh();

【讨论】:

【参考方案4】:

如果您想以编程方式执行此操作,可以这样做:

 MyDataGrid.ItemsSource = DataContext.RowItems.OrderBy(p => p.Score).ToList();

【讨论】:

以上是关于Wpf DataGrid插入列,列的类型问题的主要内容,如果未能解决你的问题,请参考以下文章

禁用 WPF MVVM 中 DataGrid 中自动生成的列的排序

在 WPF 中为 DataGrid 缩小列的宽度

WPF DataGrid在同一列中的不同控件 - 不正确的绑定

WPF DataGrid 将单元格绑定到具有动态列的数据模型

WPF DataGrid动态生成列的单元格背景色绑定

在wpf中怎么获取datagrid某行某列的值