C # DataTable DataGrid специальный символ "/" (косая черта) в именах столбцов - PullRequest
0 голосов
/ 14 мая 2018

Я хотел бы отобразить таблицу строк в C # с использованием DataGrid.Имена столбцов генерируются динамически (т.е. не известны во время компиляции).

Вот пример:

Здесь числа были преобразованы в строки,

Я использую 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 для достижения вышеизложенного, то есть правильной структуры данных, которая должна бытьused?

Вот код для создания DataTable.

    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>

Как предлагается вкомментарии, я добавил обработчик AutoGeneratingColumn, который изменяет привязку для использования квадратных скобок:

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

        };
    }

Теперь он отлично работает для "климата с изменением", но не работает для столбца с именем "EDIP2003без LT, подкисление без LT, подкисление без 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] 

1 Ответ

0 голосов
/ 28 марта 2019

Изучив документацию по Синтаксис PropertyPath , мы увидим, почему строки не отображаются.

Первый, который вы уже указали и можете исправить, - это косая черта /:

Обход источника (связывание с иерархиями коллекций)

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

/ в этом синтаксисе используется для навигации внутри объекта источника иерархических данных, и поддерживаются несколько шагов в иерархии с последовательными символами /.

Это исправлено с помощью индексатора ([]).

Однако формат индексатора поддерживает несколько индексаторов, разделенных запятой:

Несколько индексаторов

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

или

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

Если данный объект поддерживает несколько индексаторов, эти индексаторы можно указывать в порядке, аналогичном синтаксису ссылки на массив. Рассматриваемый объект может быть либо текущим контекстом, либо значением свойства, содержащего объект с несколькими индексами.

Если мы посмотрим дальше, то увидим, что мы можем избежать запятой, используя следующий синтаксис:

Экранирование для строк пути свойства

Для некоторых бизнес-объектов вы можете столкнуться со случаем, когда строка пути свойства требует escape-последовательности для правильного анализа. Необходимость избегать должна быть редкой, поскольку многие из этих символов имеют схожие проблемы взаимодействия имен в языках, которые обычно используются для определения бизнес-объекта.

  • Внутри индексаторов ([]) символ вставки (^) экранирует следующий символ.

Используя все это, я придумал следующее решение, чтобы избежать всего, все еще используя автоматически сгенерированные столбцы. Это может быть излишним, но это гарантирует, что строка интерпретируется правильно.

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,
    };
}
...