Проблема в том, что targetValue
- это поле.Если вы разделяете статический экземпляр преобразователя среди привязок к различным свойствам разных объектов, Convert()
и ConvertBack()
должны быть чистыми функциями .Твой нет.
Вместо этого у вас есть один targetValue
, общий для всех привязок в вашей DataGrid.Convert()
устанавливает targetValue
, затем следующий вызов ConvertBack()
использует это значение targetValue
- но теперь это другая строка.
Я переписал ваш конвертер как MarkupExtension
, так что вы можете легко создать новый его экземпляр для каждой ячейки в каждой строке.Не беспокойтесь о том, чтобы создать кучу этих вещей.По сравнению со стоимостью всего остального, что мы создаем для каждой ячейки, это не имеет значения.
Я также сделал маску флага параметром конструктора.Вы могли бы упростить использование этой вещи, сделав параметр конструктора типа AllowedOperations
, но вы написали конвертер, который работает с любым типом перечисления флага, и я подумал, что гибкость стоит того.
public class FlagConverter : MarkupExtension, IValueConverter
{
private int _mask;
private int _targetValue;
public FlagConverter(object enumValue)
{
_mask = (int)enumValue;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
_targetValue = (int)value;
return ((_mask & _targetValue) != 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
_targetValue ^= _mask;
return Enum.Parse(targetType, _targetValue.ToString());
}
}
И вот как вы будете использовать его сейчас.Он больше не создается в Window.Resources.
<DataGridTemplateColumn Width="100" Header="Read">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Read"
IsChecked="{Binding Operations, Converter={local:FlagConverter {x:Static local:AllowedOperations.Read}}, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="100" Header="Edit">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Edit"
IsChecked="{Binding Operations, Converter={local:FlagConverter {x:Static local:AllowedOperations.Edit}}, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Delete"
IsChecked="{Binding Operations, Converter={local:FlagConverter {x:Static local:AllowedOperations.Delete}}, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Мне не особенно нравится эта реализация, потому что в WPF существует общее предположение, что Convert()
и ConvertBack()
являются чистыми функциями, а это нарушает предположение .Не пренебрегайте тенденцией доверять этому предположению: вы попали сюда, случайно доверяя ему.
Однако для ConvertBack нужны два входа, и я не знаю другого способа получить второй.