Первый пример изменяет интерфейс только для этого объекта. Второй пример изменяет интерфейс для всех объектов этого класса.
Вы могли использовать преобразователь значения. Здесь очень определенная реализация для целевого Перечисления, но не была бы тверда видеть, как сделать преобразователь более универсальным:
[Flags]
public enum Department
{
None = 0,
A = 1,
B = 2,
C = 4,
D = 8
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.DepartmentsPanel.DataContext = new DataObject
{
Department = Department.A | Department.C
};
}
}
public class DataObject
{
public DataObject()
{
}
public Department Department { get; set; }
}
public class DepartmentValueConverter : IValueConverter
{
private Department target;
public DepartmentValueConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Department mask = (Department)parameter;
this.target = (Department)value;
return ((mask & this.target) != 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
this.target ^= (Department)parameter;
return this.target;
}
}
И затем используют преобразователь в XAML:
<Window.Resources>
<l:DepartmentValueConverter x:Key="DeptConverter" />
</Window.Resources>
<StackPanel x:Name="DepartmentsPanel">
<CheckBox Content="A"
IsChecked="{Binding
Path=Department,
Converter={StaticResource DeptConverter},
ConverterParameter={x:Static l:Department.A}}"/>
<!-- more -->
</StackPanel>
РЕДАКТИРОВАНИЕ: у меня нет достаточного количества "представителя" (все же!) для комментария ниже, таким образом, я должен обновить свое собственное сообщение :(
В последнем комментарии, который demwiz.myopenid.com говорит, "но когда дело доходит до двухсторонней привязки ConvertBack, разваливается", хорошо я обновил свой пример кода выше для обработки сценария ConvertBack; я также отправил демонстрационное рабочее приложение здесь ( редактирование: примечание, что загрузка примера кода также включает универсальную версию преобразователя).
Лично я думаю, что это намного более просто, я надеюсь, что это помогает.
Спасибо за общую справку я наконец понял это.
я связываю с DataSet со строгим контролем типов, таким образом, перечисления хранятся как система типов. Байт и не Система. Перечисление. Я, оказалось, заметил тихое исключение кастинга привязки в своем окне вывода отладки, которое указало на меня на это различие. Решение совпадает с выше, но с ValueProperty, являющимся Байта типа вместо Перечисления.
Вот класс CheckBoxFlagsBehavior, повторенный в его заключительном пересмотре. Еще раз спасибо Ian Oakes для исходной реализации!
public class CheckBoxFlagsBehaviour
{
private static bool isValueChanging;
public static Enum GetMask(DependencyObject obj)
{
return (Enum)obj.GetValue(MaskProperty);
} // end GetMask
public static void SetMask(DependencyObject obj, Enum value)
{
obj.SetValue(MaskProperty, value);
} // end SetMask
public static readonly DependencyProperty MaskProperty =
DependencyProperty.RegisterAttached("Mask", typeof(Enum),
typeof(CheckBoxFlagsBehaviour), new UIPropertyMetadata(null));
public static byte GetValue(DependencyObject obj)
{
return (byte)obj.GetValue(ValueProperty);
} // end GetValue
public static void SetValue(DependencyObject obj, byte value)
{
obj.SetValue(ValueProperty, value);
} // end SetValue
public static readonly DependencyProperty ValueProperty =
DependencyProperty.RegisterAttached("Value", typeof(byte),
typeof(CheckBoxFlagsBehaviour), new UIPropertyMetadata(default(byte), ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
isValueChanging = true;
byte mask = Convert.ToByte(GetMask(d));
byte value = Convert.ToByte(e.NewValue);
BindingExpression exp = BindingOperations.GetBindingExpression(d, IsCheckedProperty);
object dataItem = GetUnderlyingDataItem(exp.DataItem);
PropertyInfo pi = dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);
pi.SetValue(dataItem, (value & mask) != 0, null);
((CheckBox)d).IsChecked = (value & mask) != 0;
isValueChanging = false;
} // end ValueChanged
public static bool? GetIsChecked(DependencyObject obj)
{
return (bool?)obj.GetValue(IsCheckedProperty);
} // end GetIsChecked
public static void SetIsChecked(DependencyObject obj, bool? value)
{
obj.SetValue(IsCheckedProperty, value);
} // end SetIsChecked
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked", typeof(bool?),
typeof(CheckBoxFlagsBehaviour), new UIPropertyMetadata(false, IsCheckedChanged));
private static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (isValueChanging) return;
bool? isChecked = (bool?)e.NewValue;
if (isChecked != null)
{
BindingExpression exp = BindingOperations.GetBindingExpression(d, ValueProperty);
object dataItem = GetUnderlyingDataItem(exp.DataItem);
PropertyInfo pi = dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);
byte mask = Convert.ToByte(GetMask(d));
byte value = Convert.ToByte(pi.GetValue(dataItem, null));
if (isChecked.Value)
{
if ((value & mask) == 0)
{
value = (byte)(value + mask);
}
}
else
{
if ((value & mask) != 0)
{
value = (byte)(value - mask);
}
}
pi.SetValue(dataItem, value, null);
}
} // end IsCheckedChanged
private static object GetUnderlyingDataItem(object o)
{
return o is DataRowView ? ((DataRowView)o).Row : o;
} // end GetUnderlyingDataItem
} // end class CheckBoxFlagsBehaviour
Проверьте свой DataObject, который связывает с CheckBoxes, содержит свойство Department, имеет INotifyPropertyChnaged. PropertyChanged обратился к своему Методу set?