我有一个如下所示的课程。
class RegionSale
{
DateTime DateSale;
string Region;
double DollarAmount;
}
在运行时,代码不知道需要多少个RegionSale对象,这很好,因为我可以创建RegionSale对象列表。
我遇到的问题是我现在要求通过wpf数据网格显示数据,但格式如下所示,
DateS UK US EUxUK JAP Brazil
2015-12-03 23634 22187 NULL NULL NULL
2015-12-04 56000 22187 NULL NULL NULL
2015-12-14 56000 10025 NULL NULL NULL
所以我可以创建一个像下面这样的新类(但感觉这是一个坏主意)
class RegionSaleNew
{
DateTime DateSale;
double UK;
double US;
double EUxUK;
double JAP;
double Brazil;
}
正如我前面提到的,我不会在运行时知道区域的数量,所以上面的类似乎是一个坏主意,但显然很容易绑定到datagrid。
问题是如何最好地构建我的类,同时考虑到datagrid&的格式。直到运行时才知道区域的数量?反思是个好主意吗?
答案 0 :(得分:0)
我会编写一个派生INotifyPropertyChanged
接口的类,并为每个区域创建一个属性,如示例所示。
然后我会使用ObservableCollection<myClass>
并绑定到属性。
class RegionSaleNew : INotifyPropertyChanged
{
DateTime DateSale;
double _uk;
.....
public double UK
{
get { return _monitor; }
set
{
if (value == _uk) return;
_uk = value;
OnPropertyChanged();
}
}
// Add all properties here
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
在XAML中,您可以像这样绑定
...
<DataGridTextColumn Width="Auto" Header="UK" Binding="{Binding UK, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True"/>
...
然后,您只需要设置DataGrid.ItemsSource = myObservableCollection
或XAML <DataGrid ItemsSource="{Binding myObservableCollection} ... </DataGrid>
答案 1 :(得分:0)
其实我对同一个主题感兴趣,所以它是我第一个SO问题Cross tabular data binding in WPF的目标。提供的答案一般涵盖了它,但不适用于DataGrid
特定绑定。所以我的结论是解决方案应该基于一些System.ComponentModel
概念:
(1)自定义PropertyDescriptor实施提供&#34;虚拟&#34;属性。
(2)项目类实现ICustomTypeDescriptor以暴露&#34;虚拟&#34;每件物品
(3)实现ITypedList的集合类,允许从&#34;虚拟&#34;创建自动数据网格列。属性。
拥有你的模特
class RegionSale
{
public DateTime DateSale;
public string Region;
public double DollarAmount;
}
和数据
IEnumerable<RegionSale> data = ...;
&#34;虚拟&#34;只需获取Region
字段的明确列表,即可在运行时确定属性:
var regions = data.Select(sale => sale.Region).Distinct().ToList();
对于每个区域,我们将创建一个区域为Name
的属性描述符,稍后将其用作项内部字典的键以检索值。
将通过DateSale
对数据进行分组来构建项目。
以下是整个实施:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
class RegionSalePivotViewItem : CustomTypeDescriptor
{
private RegionSalePivotView container;
private Dictionary<string, double> amountByRegion;
internal RegionSalePivotViewItem(RegionSalePivotView container, DateTime date, IEnumerable<RegionSale> sales)
{
this.container = container;
DateSale = date;
amountByRegion = sales.ToDictionary(sale => sale.Region, sale => sale.DollarAmount);
}
public DateTime DateSale { get; private set; }
public double? GetAmount(string region)
{
double value;
return amountByRegion.TryGetValue(region, out value) ? value : (double?)null;
}
public override PropertyDescriptorCollection GetProperties()
{
return container.GetItemProperties(null);
}
}
class RegionSalePivotView : ReadOnlyCollection<RegionSalePivotViewItem>, ITypedList
{
private PropertyDescriptorCollection properties;
public RegionSalePivotView(IEnumerable<RegionSale> source) : base(new List<RegionSalePivotViewItem>())
{
// Properties
var propertyList = new List<PropertyDescriptor>();
propertyList.Add(new Property<DateTime>("DateSale", (item, p) => item.DateSale));
foreach (var region in source.Select(sale => sale.Region).Distinct().OrderBy(region => region))
propertyList.Add(new Property<double?>(region, (item, p) => item.GetAmount(p.Name)));
properties = new PropertyDescriptorCollection(propertyList.ToArray());
// Items
((List<RegionSalePivotViewItem>)Items).AddRange(
source.GroupBy(sale => sale.DateSale,
(date, sales) => new RegionSalePivotViewItem(this, date, sales))
.OrderBy(item => item.DateSale)
);
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) { return properties; }
public string GetListName(PropertyDescriptor[] listAccessors) { return null; }
class Property<T> : PropertyDescriptor
{
Func<RegionSalePivotViewItem, Property<T>, T> getValue;
public Property(string name, Func<RegionSalePivotViewItem, Property<T>, T> getValue) : base(name, null) { this.getValue = getValue; }
public override Type ComponentType { get { return typeof(RegionSalePivotViewItem); } }
public override Type PropertyType { get { return typeof(T); } }
public override object GetValue(object component) { return getValue((RegionSalePivotViewItem)component, this); }
public override bool IsReadOnly { get { return true; } }
public override bool CanResetValue(object component) { return false; }
public override void ResetValue(object component) { throw new NotSupportedException(); }
public override void SetValue(object component, object value) { throw new NotSupportedException(); }
public override bool ShouldSerializeValue(object component) { return false; }
}
}
样本测试:
视图模型:
class ViewModel
{
public RegionSalePivotView PivotView { get; set; }
}
XAML :
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dataGrid" HorizontalAlignment="Left" Margin="28,33,0,0" VerticalAlignment="Top" Height="263" Width="463" ItemsSource="{Binding PivotView}"/>
</Grid>
</Window>
背后的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var data = new[]
{
new RegionSale { DateSale = new DateTime(2015, 12, 03), Region = "UK", DollarAmount = 23634 },
new RegionSale { DateSale = new DateTime(2015, 12, 03), Region = "US", DollarAmount = 22187 },
new RegionSale { DateSale = new DateTime(2015, 12, 04), Region = "UK", DollarAmount = 56000 },
new RegionSale { DateSale = new DateTime(2015, 12, 04), Region = "US", DollarAmount = 22187 },
new RegionSale { DateSale = new DateTime(2015, 12, 14), Region = "UK", DollarAmount = 56000 },
new RegionSale { DateSale = new DateTime(2015, 12, 14), Region = "US", DollarAmount = 10025 },
};
DataContext = new ViewModel { PivotView = new RegionSalePivotView(data) };
}
}
结果: