Как может Вы двухсторонний связывать флажок с отдельным битом перечисления флагов?

Первый пример изменяет интерфейс только для этого объекта. Второй пример изменяет интерфейс для всех объектов этого класса.

18
задан Steve Cadwallader 28 November 2008 в 22:24
поделиться

3 ответа

Вы могли использовать преобразователь значения. Здесь очень определенная реализация для целевого Перечисления, но не была бы тверда видеть, как сделать преобразователь более универсальным:

[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; я также отправил демонстрационное рабочее приложение здесь ( редактирование: примечание, что загрузка примера кода также включает универсальную версию преобразователя).

Лично я думаю, что это намного более просто, я надеюсь, что это помогает.

45
ответ дан 30 November 2019 в 06:26
поделиться

Спасибо за общую справку я наконец понял это.

я связываю с 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
2
ответ дан 30 November 2019 в 06:26
поделиться

Проверьте свой DataObject, который связывает с CheckBoxes, содержит свойство Department, имеет INotifyPropertyChnaged. PropertyChanged обратился к своему Методу set?

1
ответ дан 30 November 2019 в 06:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: