Привязка свойства объекта ячейки к DataGridCell в WPF DataGrid - PullRequest
2 голосов
/ 02 сентября 2010

Использование WPF DataGrid У меня есть необходимость изменить различные свойства отображения и связанные свойства DataGridCell, такие как Foreground, FontStyle, IsEnabled и т. Д., На основе соответствующего значения свойства объекта ячейки.

Теперь это легко сделать в коде, например (используя Observable Collection из ObservableDictionaries):

  var b = new Binding("IsLocked") { Source = row[column], Converter = new BoolToFontStyleConverter() };
  cell.SetBinding(Control.FontStyleProperty, b);

и работает нормально, однако я не могу понять, как это сделать в XAML, поскольку не могу найти способ установить Path для свойства объекта ячейки.

Одна попытка XAML:

<Setter Property="FontStyle">
    <Setter.Value>
        <MultiBinding Converter="{StaticResource IsLockedToFontStyleConverter}" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
              <Binding />
              <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
        </MultiBinding>
    </Setter.Value>
</Setter>

но нет привязки к IsLocked свойству

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    var row = (RowViewModel) values[0];
    var cell = (DataGridCell) values[1];
    if (cell != null && row != null)
    {
        var column = DataGridMethods.GetColumn(cell);
        return row[column].IsLocked ? "Italic" : "Normal";
    }

    return DependencyProperty.UnsetValue;
}

Обратите внимание, что предыдущая версия возвратила row [col] .IsLocked и установила FontStyle, используя DataTrigger, но возвращенный объект не привязан к данным.

Обратите внимание, конечно, что приложение не знает, что столбцы во время разработки.

Наконец, DataTable слишком неэффективны для моих требований, но мне было бы интересно посмотреть, как это сделать с DataTable в любом случае, если есть такое решение для них, это может быть полезно в другом месте (хотя я предпочитаю использовать коллекции).

Конечно, это общая проблема, и я являюсь новичком WPF, пытающимся использовать все MVVM в моем проекте, но эта проблема сдерживает меня в связи с использованием WPF DataGrid.

1 Ответ

4 голосов
/ 05 сентября 2010

Ну вот самое простое решение, которое я нашел. (На самом деле у меня это было до того, как я опубликовал этот и другой вопрос, но смутился из-за такого решения. Так как здесь ничего больше не слышал, и просто на случай, если кто-то еще столкнется с той же проблемой, я подумал, что поделюсь им)

Поместите ссылку на объект ячейки в свойстве Tag DataGridCell. Я делаю это с помощью комбинации XAML и привязки кода внутри конвертера следующим образом:

   <Setter Property="Tag">
       <Setter.Value>
           <MultiBinding Converter="{StaticResource CellViewModelToTagConverter}" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
              <Binding />
              <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
          </MultiBinding>
       </Setter.Value>
   </Setter>

и

 public class CellViewModelToTagConverter : IMultiValueConverter
 {
     public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
        var row = values[0] as RowViewModel;
        var cell = values[1] as DataGridCell;
        if (row != null && cell != null)
        {
            var column = DataGridMethods.GetColumn(cell);
            // hack within hack!!! (using tag way is itself a hack?)
            var b = new Binding("Self") {Source = row[column]};
            cell.SetBinding(FrameworkElement.TagProperty, b);
            //...
            //return row[column];
            return DependencyProperty.UnsetValue;
        }
        return DependencyProperty.UnsetValue;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Вы можете сказать, что я думаю об этом решении, по моим комментариям внутри конвертера (мне пришлось добавить свойство Self к объекту Cell и сделать Self = this в конструкторе).

Тем не менее, это позволяет моему кодированию Datagrid быть полностью MVVM - если вы согласитесь, что то, что я сделал внутри конвертера, согласуется с MVVM. В любом случае это работает!

Делая это таким образом, я могу видеть и управлять всем из XAML, например, управлять таким связыванием только для определенных столбцов, помещая XAML в соответствующие стили ячеек столбцов (это не делается через DataGrid.CellStyle).

В любом случае, пример использования:

<Style.Triggers>
      <DataTrigger Value="true" Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag.IsLocked}">
            <Setter Property="FontStyle" Value="Italic"/>
            <Setter Property="IsEnabled" Value="False"/>
       </DataTrigger>
 </Style.Triggers>

На уровне XAML это просто и ИМХО элегантно (особенно для различных всплывающих подсказок и всплывающих окон, для которых я интенсивно использую свойства объекта ячейки). Однако я уверен, что есть лучший способ сделать это, не так ли?

Надеюсь, все это исчезнет, ​​когда я смогу использовать Net 4.0 и динамические объекты, но для этого проекта я не смогу.

...