DataGrid:动态 DataGridTemplateColumn 的动态 DataTemplate
我想在数据网格中显示数据,其中数据是
public class Thing
{
public string Foo { get; set; }
public string Bar { get; set; }
public List<Candidate> Candidates { get; set; }
}
public class Candidate
{
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
候选人列表中候选人数量在运行时变化的集合。
所需的网格布局如下所示
Foo | Bar | Candidate 1 | Candidate 2 | ... | Candidate N
我希望为每个候选人提供一个DataTemplate
,因为我计划在运行时更改它 - 用户可以选择以不同的方式显示有关候选人的信息列(候选人只是一个例子,我有不同的对象)。这意味着我还想在运行时更改列模板,尽管这可以通过一个大模板并折叠其各个部分来实现。
我知道如何实现我的目标有两种方法(两者都非常相似):
- 使用
AutoGenerateColumn
事件并创建 Candidates 列 - 手动添加列
在这两种情况下,我都需要加载 DataTemplate
来自带有 XamlReader
的字符串。在此之前,我必须编辑字符串以将绑定更改为想要的Candidate。
是否有更好的方法来创建具有未知数量的 DataGridTemplateColumn 的 DataGrid?
注意: 这个问题基于 带有 valueconverter 的动态数据模板
编辑: 由于我需要支持 WPF 和 Silverlight,因此我创建了自己的 DataGrid
组件,它具有用于绑定列集合的DependencyProperty
。当集合发生变化时,我会更新列。
I want to show data in a datagrid where the data is a collection of
public class Thing
{
public string Foo { get; set; }
public string Bar { get; set; }
public List<Candidate> Candidates { get; set; }
}
public class Candidate
{
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
where the number of candidates in Candidates list varies at runtime.
Desired grid layout looks like this
Foo | Bar | Candidate 1 | Candidate 2 | ... | Candidate N
I'd like to have a DataTemplate
for each Candidate as I plan changing it during runtime - user can choose what info about candidate is displayed in different columns (candidate is just an example, I have different object). That means I also want to change the column templates in runtime although this can be achieved by one big template and collapsing its parts.
I know about two ways how to achieve my goals (both quite similar):
- Use
AutoGeneratingColumn
event and create Candidates columns - Add Columns manually
In both cases I need to load the DataTemplate
from string with XamlReader
. Before that I have to edit the string to change the binding to wanted Candidate.
Is there a better way how to create a DataGrid with unknown number of DataGridTemplateColumn?
Note: This question is based on dynamic datatemplate with valueconverter
Edit: As I need to support both WPF and Silverlight, I've created my own DataGrid
component which has DependencyProperty
for bindig a collection of columns. When the collection changes, I update the columns.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
例如,我们创建 2 个 DataTemplate 和一个 ContentControl:
现在,如果您将 GridModel 属性(例如类型对象)设置为 VariantA 或 VariantB,它将切换 DataTemplate。
变体A& B 实施示例:
希望这会有所帮助。
For example we create 2 DataTemplates and a ContentControl:
Now if you set your GridModel Property (for example type object) to VariantA or VariantB, it will switch the DataTemplate.
VariantA & B example Implementation:
Hope this helps.
我不知道这是否是一种“更好”的方式,因为这仍然很丑陋,但我个人是这样做的:
例如:(抱歉,我没有调整我的代码来适合您的项目,但您应该能够从那里自己做)
这是我的数据模板:
这是我的转换器:
这保存了 MVVM 模型,我更喜欢这种方式因为我真的不喜欢使用 xaml 解析器来制作“动态”数据模板,但从我的角度来看,它仍然是一个丑陋的 Hack。
我希望 MS 的人能给我们一种方法来获取单元格而不是行作为 dataContexts,以便能够动态生成模板列...
希望这有助于
编辑:在您的情况下,转换器实际上应该简单得多(如果我没记错的话,你可以直接返回单元格的实例,并且不需要任何参数),但我仍然保留了更复杂的版本,以防其他人遇到类似的问题
I don't know if this is a "better" way, since this remains pretty ugly, but I personnaly did like this:
e.g.: (sorry, I did not adapt my code to suit your project, but you should be able to do it yourself from there)
here is my dataTemplate:
and here is my converter:
this saves the MVVM model, and I prefer this way of doing things because I really dislike using xaml parsers to make "dynamic" datatemplates, but it's still an ugly Hack from my point of view.
I wish the guys at MS would give us a way to get cells instead of rows as dataContexts to be able to generate templated columns on the fly...
hope this helps
EDIT: In your case, the converter ought to be a lot simpler actually (you can return the cell's instance directly if I'm not mistaken, and you don't need any parameter), but I left the more complex version nonetheless, just in case somebody else has a similar issue
我一直在研究类似的问题,但只发现了一些有用的模式。整个“动态列”问题在 silverlight 中是一个有趣的问题。
昨天,我在 Silverlight DataGrid with Dynamic Columns 上找到了此页面我搜索期间 Travis Pettijohn 的网站。
以前我一直在使用 Colin Eberhardt 效果非常好......只要您使用
DataGridTextColumn
。一切都可以在代码隐藏中完成,并且我在运行时应用样式没有遇到任何问题。然而,我现在的要求是应用一些“单元格级别”格式 - 更改单元格的背景等 - 这意味着需要DataGridTemplateColumn
。对于我来说,
DataGridTemplateColumn
的一个大问题是我无法在代码中设置绑定。我知道我们可以通过解析 xaml 来构建它,但就像其他人一样,这似乎是一个巨大的黑客攻击并且无法维护。Travis(上面的第一个链接)概述的模式完全不同。在“运行时”(即页面加载时),在网格中创建所需的列。这意味着迭代您的集合,并为每个项目添加一个具有适当标题等的列。然后为
RowLoaded
事件实现一个处理程序,并且在加载每一行时只需设置 DataContext 每个单元格到父级的适当属性/属性索引。这使我不再需要使用索引转换器。在设置
cell.DataContext
时,您可能可以使用Binding
,但对我来说,让模板直接绑定到底层对象会更容易。我现在计划拥有多个模板(其中每个模板都可以绑定到我的单元格对象上的相同属性)并在页面加载时在它们之间切换。非常整洁的解决方案。
I've been looking at a similar problem and have only found a handful of useful patterns. The whole 'dynamic column' problem is an interesting one in silverlight.
Yesterday I found this page Silverlight DataGrid with Dynamic Columns on Travis Pettijohn's site during my searches.
Previously I'd been using the 'index converter' pattern outlined by Colin Eberhardt which works fantastically well... as long as you use
DataGridTextColumn
. Everything can be done in code behind, and I had no trouble applying styles at run time. However my requirement is now to apply some 'cell level' formatting - change the background for the cell, etc - which means aDataGridTemplateColumn
is required.The big problem with a
DataGridTemplateColumn
for me was that I can't set the binding in code. I know we can build it by parsing xaml, but like everyone else that seems like a massive hack and unmaintainable to the nth.The pattern outlined by Travis (the first link above) is completely different. At 'run time' (i.e. page load time), create the columns you need in your grid. This means iterate through your collection, and add a column for each item with the appropriate header etc. Then implement a handler for the
RowLoaded
event, and when each row is loaded simply set the DataContext for each cell to the appropriate property / property index of the parent.This has removed the need for me to use the index converter. You can probably use a
Binding
when setting thecell.DataContext
but for me it's easier to have the template simply bind directly to the underlying object.I now plan on having multiple templates (where each can bind to the same properties on my cell object) and switching between them at page load. Very tidy solution.