[英]WPF datagrid binding with custom columns
目前我正在開發 WPF 應用程序(使用 MVVM),我在DataGridView
顯示數據。
<DataGrid RowHeaderWidth="0" ItemsSource="{Binding PartsList,UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Item Name" IsReadOnly="True" Width="*" Binding="{Binding ProductName}"></DataGridTextColumn>
<DataGridTextColumn Header="Model Name" IsReadOnly="True" Width="*" Binding="{Binding CarModelName}"></DataGridTextColumn>
<DataGridTextColumn Header="Company Name" IsReadOnly="True" Width="*" Binding="{Binding CompanName}"></DataGridTextColumn>
<DataGridTextColumn Header="Price" IsReadOnly="True" Width="*" Binding="{Binding Rate}">
</DataGrid.Columns>
</DataGrid>
這里 PartsList 是實體 Part 的ObservableCollection
。
現在我想將自定義列添加到顯示折扣的DataGrid
和顯示凈額的另一列。 我怎樣才能做到這一點?
請給出一個好主意,因為我需要處理數千條記錄,因此性能對我來說非常重要。
先感謝您。
嘗試在DataGrid
的Loaded
事件上添加列:
private void DataGrid_Loaded_1(object sender, RoutedEventArgs e)
{
dataGrid.Columns.Add((DataGridTextColumn)this.Resources["DiscountColumn"]);
dataGrid.Columns.Add((DataGridTextColumn)this.Resources["NetAmountColumn"]);
//Alternatively you can create columns in .cs like
dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Dicount", Binding = new Binding("Discount") });
dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Net Amount", Binding = new Binding("NetAmount") });
}
<Window.Resources>
<DataGridTextColumn x:Key="DiscountColumn" Header="Discount" IsReadOnly="True" Width="*" Binding="{Binding Discount}"/>
<DataGridTextColumn x:Key="NetAmountColumn" Header="Net Amount" IsReadOnly="True" Width="*" Binding="{Binding NetAmount}"/>
</Window.Resources>
<DataGrid RowHeaderWidth="0" x:Name="dataGrid" Loaded="DataGrid_Loaded_1" />
這是一篇舊帖子,但我使用MVVM
和WPF
做了類似的事情,所以我想我會花兩分錢。
我無法給出任何關於它將如何執行的真實指示,但是我們沒有看到在ItemSource
顯示大約一千個對象的任何實際問題。
抱歉,這將是一段冗長的代碼顯示,但我會嘗試將其分解,以便於理解。
最終您需要做的是創建一個Attached Behavior 。
這是我的:
行為類
這完成了創建實際列的核心工作,並根據您綁定到它的ColumnsSource
將它們添加到您的DataGrid
。
public class DataGridColumnCollectionBehavior
{
private object columnsSource;
private DataGrid dataGrid;
public DataGridColumnCollectionBehavior(DataGrid dataGrid)
{
this.dataGrid = dataGrid;
}
public object ColumnsSource
{
get { return this.columnsSource; }
set
{
object oldValue = this.columnsSource;
this.columnsSource = value;
this.ColumnsSourceChanged(oldValue, this.columnsSource);
}
}
public string DisplayMemberFormatMember { get; set; }
public string DisplayMemberMember { get; set; }
public string FontWeightBindingMember { get; set; }
public string FontWeightMember { get; set; }
public string HeaderTextMember { get; set; }
public string IsEditableMember { get; set; }
public string SortMember { get; set; }
public string TextAlignmentMember { get; set; }
public string TextColourMember { get; set; }
public string WidthMember { get; set; }
private void AddHandlers(ICollectionView collectionView)
{
collectionView.CollectionChanged += this.ColumnsSource_CollectionChanged;
}
private void ColumnsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ICollectionView view = sender as ICollectionView;
if (this.dataGrid == null)
{
return;
}
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
for (int i = 0; i < e.NewItems.Count; i++)
{
DataGridColumn column = CreateColumn(e.NewItems[i]);
dataGrid.Columns.Insert(e.NewStartingIndex + i, column);
}
break;
case NotifyCollectionChangedAction.Move:
List<DataGridColumn> columns = new List<DataGridColumn>();
for (int i = 0; i < e.OldItems.Count; i++)
{
DataGridColumn column = dataGrid.Columns[e.OldStartingIndex + i];
columns.Add(column);
}
for (int i = 0; i < e.NewItems.Count; i++)
{
DataGridColumn column = columns[i];
dataGrid.Columns.Insert(e.NewStartingIndex + i, column);
}
break;
case NotifyCollectionChangedAction.Remove:
for (int i = 0; i < e.OldItems.Count; i++)
{
dataGrid.Columns.RemoveAt(e.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
for (int i = 0; i < e.NewItems.Count; i++)
{
DataGridColumn column = CreateColumn(e.NewItems[i]);
dataGrid.Columns[e.NewStartingIndex + i] = column;
}
break;
case NotifyCollectionChangedAction.Reset:
dataGrid.Columns.Clear();
CreateColumns(sender as ICollectionView);
break;
default:
break;
}
}
private void ColumnsSourceChanged(object oldValue, object newValue)
{
if (this.dataGrid != null)
{
dataGrid.Columns.Clear();
if (oldValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
if (view != null)
{
this.RemoveHandlers(view);
}
}
if (newValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
if (view != null)
{
this.AddHandlers(view);
this.CreateColumns(view);
}
}
}
}
private DataGridColumn CreateColumn(object columnSource)
{
DataGridColumn column = new DataGridTemplateColumn();
var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
((DataGridTemplateColumn)column).CellTemplate = new DataTemplate { VisualTree = textBlockFactory };
textBlockFactory.SetValue(TextBlock.MarginProperty, new Thickness(3));
if (!string.IsNullOrWhiteSpace(this.FontWeightBindingMember))
{
string propertyName = GetPropertyValue(columnSource, this.FontWeightBindingMember) as string;
textBlockFactory.SetBinding(TextBlock.FontWeightProperty, new Binding(propertyName));
}
else if (!string.IsNullOrWhiteSpace(this.FontWeightMember))
{
textBlockFactory.SetValue(TextBlock.FontWeightProperty, (FontWeight)GetPropertyValue(columnSource, this.FontWeightMember));
}
if (!string.IsNullOrWhiteSpace(this.SortMember))
{
column.SortMemberPath = GetPropertyValue(columnSource, this.SortMember) as string;
}
if (!string.IsNullOrEmpty(this.DisplayMemberMember))
{
string propertyName = GetPropertyValue(columnSource, this.DisplayMemberMember) as string;
string format = null;
if (!string.IsNullOrEmpty(this.DisplayMemberFormatMember))
{
format = GetPropertyValue(columnSource, this.DisplayMemberFormatMember) as string;
}
if (string.IsNullOrEmpty(format))
{
format = "{0}";
}
textBlockFactory.SetBinding(TextBlock.TextProperty, new Binding(propertyName) { StringFormat = format });
// If there is no sort member defined default to the display member.
if (string.IsNullOrWhiteSpace(column.SortMemberPath))
{
column.SortMemberPath = propertyName;
}
}
if (!string.IsNullOrWhiteSpace(this.TextAlignmentMember))
{
textBlockFactory.SetValue(TextBlock.TextAlignmentProperty, GetPropertyValue(columnSource, this.TextAlignmentMember));
}
if (!string.IsNullOrEmpty(this.HeaderTextMember))
{
column.Header = GetPropertyValue(columnSource, this.HeaderTextMember);
}
if (!string.IsNullOrWhiteSpace(this.TextColourMember))
{
string propertyName = GetPropertyValue(columnSource, this.TextColourMember) as string;
textBlockFactory.SetBinding(TextBlock.ForegroundProperty, new Binding(propertyName));
}
if (!string.IsNullOrEmpty(this.WidthMember))
{
double width = (double)GetPropertyValue(columnSource, this.WidthMember);
column.Width = width;
}
return column;
}
private void CreateColumns(ICollectionView collectionView)
{
foreach (object item in collectionView)
{
DataGridColumn column = this.CreateColumn(item);
this.dataGrid.Columns.Add(column);
}
}
private object GetPropertyValue(object obj, string propertyName)
{
object returnVal = null;
if (obj != null)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
if (prop != null)
{
returnVal = prop.GetValue(obj, null);
}
}
return returnVal;
}
private void RemoveHandlers(ICollectionView collectionView)
{
collectionView.CollectionChanged -= this.ColumnsSource_CollectionChanged;
}
}
存取器類
這是您在 XAML 文件中用於創建Binding
的類。
public static class DataGridColumnCollection
{
public static readonly DependencyProperty ColumnCollectionBehaviourProperty =
DependencyProperty.RegisterAttached("ColumnCollectionBehaviour", typeof(DataGridColumnCollectionBehaviour), typeof(DataGridColumnCollection), new UIPropertyMetadata(null));
public static readonly DependencyProperty ColumnsSourceProperty =
DependencyProperty.RegisterAttached("ColumnsSource", typeof(object), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.ColumnsSourcePropertyChanged));
public static readonly DependencyProperty DisplayMemberFormatMemberProperty =
DependencyProperty.RegisterAttached("DisplayMemberFormatMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.DisplayMemberFormatMemberChanged));
public static readonly DependencyProperty DisplayMemberMemberProperty =
DependencyProperty.RegisterAttached("DisplayMemberMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.DisplayMemberMemberChanged));
public static readonly DependencyProperty FontWeightBindingMemberProperty =
DependencyProperty.RegisterAttached("FontWeightBindingMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.FontWeightBindingMemberChanged));
public static readonly DependencyProperty FontWeightMemberProperty =
DependencyProperty.RegisterAttached("FontWeightMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.FontWeightMemberChanged));
public static readonly DependencyProperty IsEditableMemberProperty =
DependencyProperty.RegisterAttached("IsEditableMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.IsEditableMemberChanged));
public static readonly DependencyProperty HeaderTextMemberProperty =
DependencyProperty.RegisterAttached("HeaderTextMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.HeaderTextMemberChanged));
public static readonly DependencyProperty SortMemberProperty =
DependencyProperty.RegisterAttached("SortMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.SortMemberChanged));
public static readonly DependencyProperty TextAlignmentMemberProperty =
DependencyProperty.RegisterAttached("TextAlignmentMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.TextAlignmentMemberChanged));
public static readonly DependencyProperty TextColourMemberProperty =
DependencyProperty.RegisterAttached("TextColourMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.TextColourMemberChanged));
public static readonly DependencyProperty WidthMemberProperty =
DependencyProperty.RegisterAttached("WidthMember", typeof(string), typeof(DataGridColumnCollection), new UIPropertyMetadata(null, DataGridColumnCollection.WidthMemberChanged));
public static DataGridColumnCollectionBehaviour GetColumnCollectionBehaviour(DependencyObject obj)
{
return (DataGridColumnCollectionBehaviour)obj.GetValue(ColumnCollectionBehaviourProperty);
}
public static void SetColumnCollectionBehaviour(DependencyObject obj, DataGridColumnCollectionBehaviour value)
{
obj.SetValue(ColumnCollectionBehaviourProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(DataGrid))]
public static object GetColumnsSource(DependencyObject obj)
{
return (object)obj.GetValue(ColumnsSourceProperty);
}
[AttachedPropertyBrowsableForType(typeof(DataGrid))]
public static void SetColumnsSource(DependencyObject obj, ObservableCollection<DataGridColumn> value)
{
obj.SetValue(ColumnsSourceProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetDisplayMemberFormatMember(DependencyObject obj)
{
return (string)obj.GetValue(DisplayMemberFormatMemberProperty);
}
public static void SetDisplayMemberFormatMember(DependencyObject obj, string value)
{
obj.SetValue(DisplayMemberFormatMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetDisplayMemberMember(DependencyObject obj)
{
return (string)obj.GetValue(DisplayMemberMemberProperty);
}
public static void SetDisplayMemberMember(DependencyObject obj, string value)
{
obj.SetValue(DisplayMemberMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetFontWeightBindingMember(DependencyObject obj)
{
return (string)obj.GetValue(FontWeightBindingMemberProperty);
}
public static void SetFontWeightBindingMember(DependencyObject obj, string value)
{
obj.SetValue(FontWeightBindingMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetFontWeightMember(DependencyObject obj)
{
return (string)obj.GetValue(FontWeightMemberProperty);
}
public static void SetFontWeightMember(DependencyObject obj, string value)
{
obj.SetValue(FontWeightMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetTextAlignmentMember(DependencyObject obj)
{
return (string)obj.GetValue(TextAlignmentMemberProperty);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static void SetTextAlignmentMember(DependencyObject obj, string value)
{
obj.SetValue(TextAlignmentMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetTextColourMember(DependencyObject obj)
{
return (string)obj.GetValue(TextColourMemberProperty);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static void SetTextColourMember(DependencyObject obj, string value)
{
obj.SetValue(TextColourMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(DataGrid))]
public static string GetHeaderTextMember(DependencyObject obj)
{
return (string)obj.GetValue(HeaderTextMemberProperty);
}
[AttachedPropertyBrowsableForType(typeof(DataGrid))]
public static void SetHeaderTextMember(DependencyObject obj, string value)
{
obj.SetValue(HeaderTextMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetWidthMember(DependencyObject obj)
{
return (string)obj.GetValue(WidthMemberProperty);
}
public static void SetWidthMember(DependencyObject obj, string value)
{
obj.SetValue(WidthMemberProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridView))]
public static string GetSortMember(DependencyObject obj)
{
return (string)obj.GetValue(SortMemberProperty);
}
public static void SetSortMember(DependencyObject obj, string value)
{
obj.SetValue(SortMemberProperty, value);
}
private static void ColumnsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).ColumnsSource = e.NewValue;
}
private static void DisplayMemberFormatMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).DisplayMemberFormatMember = e.NewValue as string;
}
private static void DisplayMemberMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).DisplayMemberMember = e.NewValue as string;
}
private static void FontWeightBindingMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).FontWeightBindingMember = e.NewValue as string;
}
private static void FontWeightMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).FontWeightMember = e.NewValue as string;
}
private static void IsEditableMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).IsEditableMember = e.NewValue as string;
}
private static void HeaderTextMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).HeaderTextMember = e.NewValue as string;
}
private static void SortMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).SortMember = e.NewValue as string;
}
private static void TextAlignmentMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).TextAlignmentMember = e.NewValue as string;
}
private static void TextColourMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).TextColourMember = e.NewValue as string;
}
private static void WidthMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataGridColumnCollection.GetOrCreateBehaviour(sender).WidthMember = e.NewValue as string;
}
private static DataGridColumnCollectionBehaviour GetOrCreateBehaviour(DependencyObject source)
{
DataGridColumnCollectionBehaviour behaviour = DataGridColumnCollection.GetColumnCollectionBehaviour(source);
if (behaviour == null)
{
behaviour = new DataGridColumnCollectionBehaviour(source as DataGrid);
DataGridColumnCollection.SetColumnCollectionBehaviour(source, behaviour);
}
return behaviour;
}
}
XAML 用法示例
現在我們實際上開始使用它。
<DataGrid behaviors:DataGridColumnCollection.ColumnsSource="{Binding ColumnHeaders}"
behaviors:DataGridColumnCollection.DisplayMemberFormatMember="Format" behaviors:DataGridColumnCollection.DisplayMemberMember="DisplayMember"
behaviors:DataGridColumnCollection.FontWeightBindingMember="FontWeightMember"
behaviors:DataGridColumnCollection.HeaderTextMember="Header"
behaviors:DataGridColumnCollection.SortMember="SortMember"
behaviors:DataGridColumnCollection.TextAlignmentMember="TextAlignment"
behaviors:DataGridColumnCollection.TextColourMember="TextColourMember"
behaviors:DataGridColumnCollection.WidthMember="Width"
ItemsSource="{Binding Items}">
列標題類
這只是我描述列的“簡單”類。
public class ColumnHeaderDescriptor
{
public string DisplayMember { get; set; }
public string FontWeightMember { get; set; }
public string Format { get; set; }
public string Header { get; set; }
public string SortMember { get; set; }
public TextAlignment TextAlignment { get; set; }
public string TextColourMember { get; set; }
public double Width { get; set; }
}
實例化列
這就是我創建它們的方式。
this.ColumnHeaders.Add(new ColumnHeaderDescriptor { Header = Properties.Resources.Name, DisplayMember = "ItemName", Width = 250 });
this.ColumnHeaders.Add(new ColumnHeaderDescriptor { Header = Properties.Resources.ManufPartNumber, DisplayMember = "ManufPartNumber", Width = 150 });
this.ColumnHeaders.Add(new ColumnHeaderDescriptor { Header = Properties.Resources.LastUnitPrice, DisplayMember = "UnitPriceString", SortMember = "UnitPrice", Width = 90 });
this.ColumnHeaders.Add(new ColumnHeaderDescriptor { Header = Properties.Resources.AssetType, DisplayMember = "AssetType", Width = 100 });
this.ColumnHeaders.Add(new ColumnHeaderDescriptor { Header = Properties.Resources.Quantity, DisplayMember = "QuantityString", SortMember = "Quantity", Width = 80 });
結論
現在我意識到這可能不是完全的MVVM
但在一天結束時,我們必須做出犧牲才能完成工作。 這將允許您動態創建列並顯示視圖模型中的不同信息。
我的解決方案非常復雜,我不能完全相信。 我確信我從現有的 StackOverflow 答案中得到了起點,但是我不知道現在在哪里。 考慮到它的復雜性,允許消費者確定許多不同的東西,比如文本顏色等。這對於其他解決方案來說很可能是矯枉過正,如果你不需要它們,你可以刪除不必要的屬性。
假設您正在為模型使用實體框架; 使用基於基類計算的屬性 getter 創建模型的分部類。 確保您實現 INotifyPropertyChange,然后在新列中綁定 NetAmount 和 Discount 的新屬性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.