我有一个对象集合,每个对象都包含类型集合的一个属性。我的目标是根据集合内容动态生成datagrid列,并为其余属性(即基本类型)生成列。将bool显示为CheckBox
是很重要的。
我的问题是:动态生成的列的最终单元格内容将是一个对象(我的对象结构中的Trait
),并且我希望显示其中一个对象属性(Trait.Value
) 。当我更改单元格的内容时,后面的对象应该更新。
DataTable
,但是当我添加一行时,我需要列键和值。将值设置为自定义对象时,看不到显示和编辑该自定义对象的单个属性的可能性。我的对象结构:
public class Model
{
//ItemsSource
public ObservableCollection<Person> Persons { get; set; }
}
public class Person
{
public string Name { get; set; }
//Generate Treats.Count columns
public ObservableCollection<Treat> Treats { get; set; }
}
public class Treat
{
//column header name
public string Name { get; set; }
//value that should be displayed
public string Value { get; set; }
}
我的ViewModel.cs
中带有示例数据:
public class ViewModel
{
public Model Model { get; set; }
public ViewModel()
{
#region Sample Data
Model = new Model()
{
Persons = new ObservableCollection<Person>()
{
new Person()
{
Name = "Peter",
Treats = new ObservableCollection<Treat>()
{
new Treat()
{
Name = "Look1",
Value = "Nice"
},
new Treat()
{
Name = "Look2",
Value = "Super Nice"
}
}
},
new Person()
{
Name = "Manuel",
Treats = new ObservableCollection<Treat>()
{
new Treat()
{
Name = "Look1",
Value = "Bad"
},
new Treat()
{
Name = "Look2",
Value = "Super Bad"
}
}
}
}
};
#endregion
}
}
Model.cs
类的信息:
Persons
是绑定集合,应将其用作ItemsSource Person
生成数据网格的列。 Name
的一列,集合Treats
的n列。 答案 0 :(得分:1)
既然如此,您已经说过可以破坏MVVM模式,请尝试以下方法。
概述:
创建一个IvalueConverter,将您的商品来源转换为expandoobejcts列表
在DataGrid(已加载事件或SourceChanged事件)后面的代码中,添加代码以手动生成列
代码:
创建转换器:第1部分首先,我们需要获取可能弹出的所有可能列的列表(因为我们尚不知道这些集合)
ObservableCollection<Person> inputlist = (ObservableCollection<Person>)value;
List<string> PossibleColumnList = new List<string>();
PossibleColumnList.Add(nameof(Person.Name)); //since we need name header first.
List<string> TempColumnList = new List<string>();
foreach (Person P in inputlist)
{
foreach(Treat T in P.Treats)
{
if (TempColumnList.Contains(T.Name) == false) TempColumnList.Add(T.Name);
}
}
TempColumnList.Sort();
PossibleColumnList.AddRange(TempColumnList); //This way we get Name first and rest of the columns in sorted out manner
创建转换器:第2部分。现在创建一个具有所有可用列标题的IDictionary对象
IDictionary<string, object> ColumnHeaderDictionary = new Dictionary<string, object>();
foreach (string columnheader in PossibleColumnList)
{
if (ColumnHeaderDictionary.ContainsKey(columnheader) == false) ColumnHeaderDictionary.Add(columnheader, new object());
}
创建转换器:第3部分现在遍历所有人,并为每个人模型创建一个IDictionary。将字典转换为expando对象并存储在最终列表中
List<ExpandoObject> FinalList = new List<ExpandoObject>();
foreach (Person p in inputlist)
{
ExpandoObject tempExpando = new ExpandoObject();
IDictionary<string, object> TempDictionary = tempExpando as IDictionary<string, object>;
foreach (var kvp in ColumnHeaderDictionary)
{
TempDictionary.Add(kvp);
}
TempDictionary[nameof(Person.Name)] = p.Name;
foreach(Treat t in p.Treats)
{
TempDictionary[t.Name] = t.Value;
}
FinalList.Add(tempExpando);
}
return FinalList;
XAML代码:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid x:Name="grdMain" DataContext="{Binding}">
<DataGrid x:Name="dgMain" ItemsSource="{Binding ElementName=grdMain,Path=DataContext.Model.Persons,Converter={StaticResource NewConverter}}" Loaded="dgMain_Loaded" />
</Grid>
隐藏代码:手动创建列
private void dgMain_Loaded(object sender, RoutedEventArgs e)
{
DataGrid workinggrid = sender as DataGrid;
ExpandoObject SingleExpando = (workinggrid.ItemsSource as List<ExpandoObject>).FirstOrDefault();
if (workinggrid == null) workinggrid = new DataGrid();
List<string> ColumHeaders = (SingleExpando as IDictionary<string, object>).ToList().Select(p => p.Key).ToList();
foreach (string ColumnName in ColumHeaders)
{
var newcolumn = new DataGridTextColumn() { Header = ColumnName, Binding = new Binding(ColumnName) };
workinggrid.Columns.Add(newcolumn);
}
}