带有 valueconverter 的动态数据模板

发布于 2024-07-15 02:28:38 字数 3087 浏览 6 评论 0原文

我想在 wpftoolkit 数据网格中显示数据,其中数据是

public class Thing
{
    public string Foo { get; set; }
    public string Bar { get; set; }
    public List<Candidate> Candidates { get; set; }
}

public class Candidate
{

    public string Name { get; set; }
    public CandidateType CandidateType { get; set; }
}

public enum CandidateType
{
    Type1,
    Type2,
    Type42
}

候选列表中候选数量可在运行时配置的集合。

所需的网格布局如下

所示 酒吧| 候选人 1 | 候选人2 | ... | Candidate N

因此,我似乎无法在 xaml 中为候选者创建 DataTemplate,因为绑定表达式将会改变。

我在 AutoGenerateColumns 事件中添加必要的列,如下所示:

private void DataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
    ViewModel vm = DataContext as ViewModel;

    for (int i = 0; i < vm.LotsOfThings.First().Candidates.Count; i++)
    {
        string assName = Assembly.GetExecutingAssembly().GetName().Name;
        ParserContext ctx = new ParserContext();
        ctx.XamlTypeMapper = new XamlTypeMapper(new string[] { assName });
        ctx.XamlTypeMapper.AddMappingProcessingInstruction("src", "WpfToolkitDataGridTester", assName);
        ctx.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
        ctx.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
        ctx.XmlnsDictionary.Add("src", "clr-namespace:WpfToolkitDataGridTester;assembly=" + assName);
        var template = XamlReader.Parse(@"<DataTemplate>
                                            <DataTemplate.Resources>
                                                <src:FooConverter x:Key='fooConverter' />
                                            </DataTemplate.Resources>
                                            <TextBlock  
                                                Foreground='{Binding Candidates[" + i + @"].CandidateType,Converter={StaticResource fooConverter}}'
                                                Text='{Binding Candidates[" + i + @"].Name}' />
                                        </DataTemplate>", ctx) as DataTemplate;
        dg.Columns.Add(new DataGridTemplateColumn
        {
            Header = "Candidate " + (i + 1),
            CellTemplate = template
        });
    }
}

但是,这会失败,但出现以下异常: XML 命名空间“clr-namespace:WpfToolkitDataGridTester; assembly=WpfToolkitDataGridTester”中不存在标记“FooConverter”。 第“3”行位置“54”。

将 StaticResource 更改为 DynamicResource 不会发生任何变化。

我缺少什么?

FWIW:硬编码的数据模板

<DataTemplate x:Key="candidateTemplate">
  <DataTemplate.Resources>
    <src:FooConverter x:Key="fooConverter" />
  </DataTemplate.Resources>
  <TextBlock 
    Foreground="{Binding Candidates[0].CandidateType,Converter={StaticResource fooConverter}}"
    Text="{Binding Candidates[0].Name}" />
</DataTemplate>

和模板列定义如下

<wpftk:DataGridTemplateColumn CellTemplate="{StaticResource candidateTemplate}" />

“有效”,但显然不会产生所需的结果,因为 Candidates[0] 是硬编码的。

I want to show data in a wpftoolkit 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 Name { get; set; }
    public CandidateType CandidateType { get; set; }
}

public enum CandidateType
{
    Type1,
    Type2,
    Type42
}

where the number of candidates in Candidates list is configurable at runtime.

Desired grid layout looks like this

Foo | Bar | Candidate 1 | Candidate 2 | ... | Candidate N

Thus it seems I cannot create a DataTemplate for the candidates in xaml as the binding expression will change.

I add necessary columns in AutoGeneratedColumns event like so:

private void DataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
    ViewModel vm = DataContext as ViewModel;

    for (int i = 0; i < vm.LotsOfThings.First().Candidates.Count; i++)
    {
        string assName = Assembly.GetExecutingAssembly().GetName().Name;
        ParserContext ctx = new ParserContext();
        ctx.XamlTypeMapper = new XamlTypeMapper(new string[] { assName });
        ctx.XamlTypeMapper.AddMappingProcessingInstruction("src", "WpfToolkitDataGridTester", assName);
        ctx.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
        ctx.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
        ctx.XmlnsDictionary.Add("src", "clr-namespace:WpfToolkitDataGridTester;assembly=" + assName);
        var template = XamlReader.Parse(@"<DataTemplate>
                                            <DataTemplate.Resources>
                                                <src:FooConverter x:Key='fooConverter' />
                                            </DataTemplate.Resources>
                                            <TextBlock  
                                                Foreground='{Binding Candidates[" + i + @"].CandidateType,Converter={StaticResource fooConverter}}'
                                                Text='{Binding Candidates[" + i + @"].Name}' />
                                        </DataTemplate>", ctx) as DataTemplate;
        dg.Columns.Add(new DataGridTemplateColumn
        {
            Header = "Candidate " + (i + 1),
            CellTemplate = template
        });
    }
}

This however fails with the following exception:
The tag 'FooConverter' does not exist in XML namespace 'clr-namespace:WpfToolkitDataGridTester;assembly=WpfToolkitDataGridTester'. Line '3' Position '54'.

Changing the StaticResource to DynamicResource makes no change.

What am I missing?

FWIW: a hardcoded datatemplate

<DataTemplate x:Key="candidateTemplate">
  <DataTemplate.Resources>
    <src:FooConverter x:Key="fooConverter" />
  </DataTemplate.Resources>
  <TextBlock 
    Foreground="{Binding Candidates[0].CandidateType,Converter={StaticResource fooConverter}}"
    Text="{Binding Candidates[0].Name}" />
</DataTemplate>

and the template column defined like so

<wpftk:DataGridTemplateColumn CellTemplate="{StaticResource candidateTemplate}" />

'works' but obviously does not produce the desired result as Candidates[0] is hardcoded.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枕头说它不想醒 2024-07-22 02:28:39

无论出于何种原因,如果我这样做,它就会按预期工作......

    string assName = Assembly.GetExecutingAssembly().GetName().Name;
    StringBuilder sb = new StringBuilder();
    sb.Append("<DataTemplate ");
    sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
    sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
    sb.Append("xmlns:src='clr-namespace:WpfToolkitDataGridTester;assembly=" + assName + "' >");
    sb.Append("<DataTemplate.Resources>");
    sb.Append("<src:FooConverter x:Key='fooConverter' />");
    sb.Append("</DataTemplate.Resources>");
    sb.Append("<TextBlock ");
    sb.Append("Foreground='{Binding Candidates[" + i + "].CandidateType,Converter={StaticResource fooConverter}}' ");
    sb.Append("Text='{Binding Candidates[" + i + @"].Name}' />");
    sb.Append("</DataTemplate>");
    var template = (DataTemplate)XamlReader.Parse(sb.ToString());

For whatever reason, it works as expected if I do like this...

    string assName = Assembly.GetExecutingAssembly().GetName().Name;
    StringBuilder sb = new StringBuilder();
    sb.Append("<DataTemplate ");
    sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
    sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
    sb.Append("xmlns:src='clr-namespace:WpfToolkitDataGridTester;assembly=" + assName + "' >");
    sb.Append("<DataTemplate.Resources>");
    sb.Append("<src:FooConverter x:Key='fooConverter' />");
    sb.Append("</DataTemplate.Resources>");
    sb.Append("<TextBlock ");
    sb.Append("Foreground='{Binding Candidates[" + i + "].CandidateType,Converter={StaticResource fooConverter}}' ");
    sb.Append("Text='{Binding Candidates[" + i + @"].Name}' />");
    sb.Append("</DataTemplate>");
    var template = (DataTemplate)XamlReader.Parse(sb.ToString());
满栀 2024-07-22 02:28:39

当 XAML 文件编译为 BAML 时,它引用程序集而不是内存中的源。 由于 BAML 被编译到同一程序集中,因此实际类型尚不可用。

我发现一个短期解决方法是暂时注释掉样式,构建项目,然后恢复样式。

然而,更永久的解决方案是将转换器移至另一个组件。

When the XAML files are compiled to BAML it references the assembly not the in memory source. Since the BAML is compiled into the same assembly the actual type isn't available yet.

I've found that a short term workaround is to comment out the style temporarily, build the project, then restore the style.

The more permanent solution however is to move the converter to another assembly.

违心° 2024-07-22 02:28:39

在更高级别声明一次 FooConverter(可能作为 DataGrid 的资源)而不是在每个 DataTemplate 中声明一次是否有帮助?

Would it help to declare the FooConverter once at a higher level (maybe as a resource of the DataGrid) instead of in each DataTemplate?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文