【问题标题】:C# DataTable DataGrid special character "/" (slash) in column namesC# DataTable DataGrid 列名中的特殊字符“/”(斜杠)
【发布时间】:2018-10-23 23:05:28
【问题描述】:

我想使用 DataGrid 在 C# 中显示字符串表。列名是动态生成的(即在编译时未知)。

这是一个例子:

在这里,数字已转换为字符串。

我使用 DataTable 作为包含整个表(行和列标题)的 DataGrid 的源。但是,我遇到的问题是“气候变化”列中的值未显示在 DataGrid 中。相反,我在控制台上收到以下错误消息

"BindingExpression path error: 'climate  w' property not found on 'object' 
''DataRowView' (HashCode=22429696)'. BindingExpression:Path=climate  
w/change; DataItem='DataRowView' (HashCode=22429696); target element is 
'TextBlock' (Name=''); target property is 'Text' (type 'String')"

我知道这是由于列名中的斜杠(“/”)被解释为绑定表达式。

我的问题是

  1. 有没有办法关闭该行为,即列名被解释为绑定表达式?由于我提供了一个 DataTable,其中包含行和列的所有值和标题,因此不需要根据列名计算任何数据值。此外,尽管不存在名为 HumanToxicity 的属性,但“人类毒性”列也没有问题。
  2. 如果我不能使用 DataTable 作为 DataGrid 的源来实现上述目的,那么应该使用哪种数据结构正确?

这是生成数据表的代码。

    public DataTable PaValues { get; set; }

    private void CreateDataSet()
    {
        var dt = new DataTable("Perturbation Analysis");
        List<String> ics = _perturbationAnalysis.ImpactCatagories();
        dt.Columns.Add("Parameters");

        foreach (var ic in ics)
        {
            dt.Columns.Add(Sanatize(ic));
        }
        foreach (var parameter in _perturbationAnalysis.ParameterNames())
        {
            var dr = dt.NewRow();
            dr[0] = parameter;
            for (int i = 0; i < ics.Count; i++)
            {
                dr[i+1] = _perturbationAnalysis[parameter, ics[i]].ToString();
            }
            dt.Rows.Add(dr);
        }
        PaValues = dt;
    }

    private string Sanatize(string ic)
    {
        //return ic.Replace("/", "[/]").Replace("[", "").Replace("]", "").Replace(".", " ");
        //return "[" + ic + "]";
        return ic;

    }

这是 XAML 文件的摘录

            <DataGrid
                x:Name="PAGrid"
                CanUserAddRows="False" 
                CanUserDeleteRows="False"
                ClipboardCopyMode="IncludeHeader"
                FrozenColumnCount="1"
                ItemsSource="{Binding Path=PaValues,UpdateSourceTrigger=PropertyChanged}"
                Style="{StaticResource DataGridStyle}"
                IsReadOnly="True">
            </DataGrid>

按照 cmets 中的建议,我添加了一个 AutoGeneratingColumn 处理程序,它将绑定更改为使用方括号:

    private void PaViewAutoGeneratingColumnHandler(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        e.Column = new DataGridTextColumn
        {
            Binding = new Binding("[" + e.Column.Header + "]"), Header=e.Column.Header

        };
    }

它现在适用于“气候 w/change”,但它不适用于名为“EDIP2003 w/o LT, acidification w/o LT, acidification w/o LT”的列,这是一个真实的例子客户使用。报错信息和之前一样

BindingExpression path error: '[]' property not found on 'object' ''DataRowView' (HashCode=56876317)'. 
BindingExpression:Path=[EDIP2003 w/o LT, acidification w/o LT, acidification w/o LT] 

【问题讨论】:

  • 您可能希望使用 DataGrid 列的 Header 属性,而不是 DataTable 中的实际列名。使用这种方法,列名就不会成为问题。
  • 将斜线替换为下划线。
  • @Hubert 我一定不清楚。例如,我建议您将列命名为Col1-ColN,然后使用某种逻辑(映射、列表等)将ColXHeader 属性分配给有意义的值,即My/col/header@,保持Binding 工作。
  • @AlexSeleznyov 我没有从你的链接中得到它,但我现在尝试了它并且它有效。但它是uuuuugly。我必须使用假列名,然后在视图中修补它们,并从 xaml 文件后面的代码访问视图模型,以访问我必须在视图模型中创建公共属性的真实列名。我很惊讶这样一个简单的问题没有简单的解决方案,但需要破解代码。无论如何,非常感谢大家。我自己无法找到解决方案。

标签: c# wpf datatable binding datagrid


【解决方案1】:

查看PropertyPath syntax 上的文档,我们可以看到字符串无法映射的原因。

您已经指出并且可以修复的第一个是斜线/

源遍历(绑定到集合的层次结构)

<object Path="propertyName/propertyNameX" .../>

此语法中的 / 用于在分层数据源对象中导航,并且支持使用连续 / 字符进入分层结构的多个步骤。

这已通过使用索引器 ([]) 解决。

但是,索引器格式支持多个索引器,以逗号分隔:

多个索引器

<object Path="[index1,index2...]" .../>

<object Path="propertyName[index,index2...]" .../>

如果给定对象支持多个索引器,则可以按顺序指定这些索引器,类似于数组引用语法。有问题的对象可以是当前上下文,也可以是包含多索引对象的属性的值。

如果我们进一步观察,我们可以看到我们可以使用以下语法转义逗号:

属性路径字符串的转义

对于某些业务对象,您可能会遇到属性路径字符串需要转义序列才能正确解析的情况。很少需要转义,因为其中许多字符在通常用于定义业务对象的语言中存在类似的命名交互问题。

  • 在索引器 ([ ]) 内,插入字符 (^) 转义下一个字符。

使用所有这些,我想出了以下解决方案,以在仍然使用自动生成的列的同时转义所有内容。这可能是矫枉过正,但它保证字符串被正确解释。

private void PaViewAutoGeneratingColumnHandler(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    var columnName = (string)e.Column.Header;

    // We'll build a string with escaped characters.
    // The capacity is the length times 2 (for the carets),
    // plus 2 for the square brackets.
    // This is not optimized for multi-character glyphs, like emojis

    var bindingBuilder = new StringBuilder(columnName.Length * 2 + 2);

    bindingBuilder.Append('[');
    foreach (var c in columnName)
    {
        bindingBuilder.Append('^');
        bindingBuilder.Append(c);
    }
    bindingBuilder.Append(']');

    e.Column = new DataGridTextColumn
    {
        Binding = new Binding(bindingBuilder.ToString()),
        Header = e.Column.Header,
    };
}

【讨论】:

  • 有这个确切的问题。杰出的!谢谢你们!
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
相关资源
最近更新 更多