C# 将可观察到的集合组织到时间表中
我有一个需要在WPF应用程序中以时间表方式显示的C# 将可观察到的集合组织到时间表中,c#,wpf,mvvm,datagrid,C#,Wpf,Mvvm,Datagrid,我有一个需要在WPF应用程序中以时间表方式显示的ObservableCollection 演出除其他演出外,还包括一个开始时间和一个地点,其组织方式如下: Location | 14h - 15h | 15h - 16h | 16h - 17h | 17h - 18h ---------+-----------+-----------+-----------+---------- Loc #1 | Perf 1 | Perf 2 | Perf 3 | Perf 4 ----
ObservableCollection
演出除其他演出外,还包括一个开始时间和一个地点,其组织方式如下:
Location | 14h - 15h | 15h - 16h | 16h - 17h | 17h - 18h
---------+-----------+-----------+-----------+----------
Loc #1 | Perf 1 | Perf 2 | Perf 3 | Perf 4
---------+-----------+-----------+-----------+----------
Loc #2 | Perf 5 | ...
---------------------+
...
我的持久性层保证没有交叉点,即当有一个性能位于A中并从X点开始时,其他性能将不会这样做
我尝试过几种方法,主要是使用DataGrid
,因为这似乎是一个显而易见的选择,但我无法实现所需的目标。我很确定一定有某种解决方案不是完全“黑”的,但我没有弄明白
是否可以按原样使用数据,或者在任何情况下,可观察收集
是否需要重新构造?如何在StartTime
和Location
上绑定DataGrid
?还是应该替换DataGrid
任何帮助都将不胜感激 您正在尝试的是所谓的数据透视,不幸的是,如果您事先不知道确切的列,并且希望从数据中构建所有内容,那么要做到这一点就不那么容易了 一种解决方案是每次数据更改时将
observateCollection
转换为DataTable
,然后使用AutoGenerateColumns=“true”
将DataGrid
控件绑定到DataTable
DataTable
类在.NET的早期版本就已经存在,与现代C#一起使用并不特别优雅,但它允许您动态创建列,这是数据透视时的关键挑战
话虽如此,下面是一些代码,用于从一个可观察到的冲突
构造一个数据表
:
私有静态数据表GetPerformance(ObservableCollection性能)
{
var dataTable=GetTableSkeleton(性能);
var性能组=性能
.GroupBy(x=>x.Location)
.OrderBy(x=>x.Key);
foreach(性能组中的var性能组)
{
var dataRow=dataTable.NewRow();
数据行[“位置”]=“Loc{performanceGroup.Key}”;
foreach(性能组中的var性能)
{
var columnName=GetColumnName(performance.StartTime);
dataRow[columnName]=“性能{performance.Id}”;
}
dataTable.Rows.Add(dataRow);
}
返回数据表;
}
私有静态数据表GetTableSkeleton(IEnumerable性能)
{
var时间范围=性能
.选择(x=>x.StartTime)
.Distinct()
.OrderBy(x=>x)
.Select(x=>newdatacolumn(GetColumnName(x)))
.ToArray();
var dataTable=新的dataTable();
dataTable.Columns.Add(“位置”);
dataTable.Columns.AddRange(时间范围);
返回数据表;
}
私有静态字符串GetColumnName(int startTime)
{
返回$“{startTime}-{startTime+1}”;
}
这样做的目的是创建一个“骨架”DataTable
,首先从性能中提取列名(确保没有重复项并按StartTime排序),然后将这些列添加到一个新的DataTable
。(它还添加了位置列。)
然后,它通过循环遍历按位置分组和排序的数据,将所有数据添加到表中
通过挂接到CollectionChanged
事件,可以确保您的DataGrid
始终保持更新
这假设您的
性能
类具有以下三个整数属性:Id
、StartTime
、和Location
,您尝试的是所谓的数据透视,不幸的是,如果您事先不知道确切的列,并且希望从数据构建所有内容,那么做起来就不那么容易了
一种解决方案是每次数据更改时将observateCollection
转换为DataTable
,然后使用AutoGenerateColumns=“true”
将DataGrid
控件绑定到DataTable
DataTable
类在.NET的早期版本就已经存在,与现代C#一起使用并不特别优雅,但它允许您动态创建列,这是数据透视时的关键挑战
话虽如此,下面是一些代码,用于从一个可观察到的冲突
构造一个数据表
:
私有静态数据表GetPerformance(ObservableCollection性能)
{
var dataTable=GetTableSkeleton(性能);
var性能组=性能
.GroupBy(x=>x.Location)
.OrderBy(x=>x.Key);
foreach(性能组中的var性能组)
{
var dataRow=dataTable.NewRow();
数据行[“位置”]=“Loc{performanceGroup.Key}”;
foreach(性能组中的var性能)
{
var columnName=GetColumnName(performance.StartTime);
dataRow[columnName]=“性能{performance.Id}”;
}
dataTable.Rows.Add(dataRow);
}
返回数据表;
}
私有静态数据表GetTableSkeleton(IEnumerable性能)
{
var时间范围=性能
.选择(x=>x.StartTime)
.Distinct()
.OrderBy(x=>x)
.Select(x=>newdatacolumn(GetColumnName(x)))
.ToArray();
var dataTable=新的dataTable();
dataTable.Columns.Add(“位置”);
dataTable.Columns.AddRange(时间范围);
返回数据表;
}
私有静态字符串GetColumnName(int startTime)
{
返回$“{startTime}-{startTime+1}”;
}
这样做的目的是创建一个“骨架”DataTable
,首先从性能中提取列名(确保没有重复项并按开始时间排序),然后
private static DataTable GetPerformances(ObservableCollection<Performance> performances)
{
var dataTable = GetTableSkeleton(performances);
var performanceGroups = performances
.GroupBy(x => x.Location)
.OrderBy(x => x.Key);
foreach (var performanceGroup in performanceGroups)
{
var dataRow = dataTable.NewRow();
dataRow["Location"] = $"Loc {performanceGroup.Key}";
foreach (var performance in performanceGroup)
{
var columnName = GetColumnName(performance.StartTime);
dataRow[columnName] = $"Perf {performance.Id}";
}
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
private static DataTable GetTableSkeleton(IEnumerable<Performance> performances)
{
var timeRanges = performances
.Select(x => x.StartTime)
.Distinct()
.OrderBy(x => x)
.Select(x => new DataColumn(GetColumnName(x)))
.ToArray();
var dataTable = new DataTable();
dataTable.Columns.Add("Location");
dataTable.Columns.AddRange(timeRanges);
return dataTable;
}
private static string GetColumnName(int startTime)
{
return $"{startTime}-{startTime + 1}";
}