2

私はこの列挙型(flag)を書きました:

using System;
namespace AndreyBushman.AutoCAD {
    // Specifies, how and when .NET application will load. 
    // It is a flag.
    [Flags]
    public enum LoadCtrls {
        // Load application upon detection of proxy object
        AtProxyFound = 1,
        // Load the application at startup
        AtAutoCADStart = 2,
        // Load the application at start of a command
        AtCommandStart = 4,
        // Load the application at the request of a user 
        // or another application
        AtUserOrApplicationRequirement = 8,
        // Do not load the application
        NotLoad = 16,
        // Load the application transparently
        TransparencyLoad = 32,
    }
}

今私はアイテムで作成StackPanelしました:CheckBox

<StackPanel x:Name="stackAllUsersLoadCtrls">
    <CheckBox Margin="2">At proxy found</CheckBox>
    <CheckBox Margin="2">At AutoCAD start</CheckBox>
    <CheckBox Margin="2">At command start</CheckBox>
    <CheckBox Margin="2">At user or application requirement</CheckBox>
    <CheckBox Margin="2">Not load</CheckBox>
    <CheckBox Margin="2">Transparency load</CheckBox>
</StackPanel>

結果画面:

ここに画像の説明を入力

LoadCtrlsのインスタンス(フラグ) をCheckBoxアイテムにバインドするにはどうすればよいですか?


UPD コードを書き直しました (ラッパーを追加し、コンバーターを書き直し、XAML を書き直しました):

ラッパー:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ab = AndreyBushman.AutoCAD;
using System.ComponentModel;

namespace AcadLoadManaged {

    public sealed class LoadCtrlsWrapper : INotifyPropertyChanged {
        ab.LoadCtrls loadCtrls;

        public ab.LoadCtrls GetloadCtrls() {
            return loadCtrls;
        }
        public LoadCtrlsWrapper() {
            loadCtrls = default(ab.LoadCtrls);
        }
        public LoadCtrlsWrapper(ab.LoadCtrls loadCtrls) {
            this.loadCtrls = loadCtrls;
        }

        public Boolean AtAutoCADStart {
            get {
                return (loadCtrls & ab.LoadCtrls.AtAutoCADStart) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.AtAutoCADStart;
                else
                    loadCtrls &= ~ab.LoadCtrls.AtAutoCADStart;
                OnPropertyChanged("AtAutoCADStart");
            }
        }

        public Boolean AtCommandStart {
            get {
                return (loadCtrls & ab.LoadCtrls.AtCommandStart) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.AtCommandStart;
                else
                    loadCtrls &= ~ab.LoadCtrls.AtCommandStart;
                OnPropertyChanged("AtCommandStart");
            }
        }

        public Boolean AtProxyFound {
            get {
                return (loadCtrls & ab.LoadCtrls.AtProxyFound) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.AtProxyFound;
                else
                    loadCtrls &= ~ab.LoadCtrls.AtProxyFound;
                OnPropertyChanged("AtProxyFound");
            }
        }

        public Boolean AtUserOrApplicationRequirement {
            get {
                return (loadCtrls & ab.LoadCtrls.AtUserOrApplicationRequirement) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.AtUserOrApplicationRequirement;
                else
                    loadCtrls &= ~ab.LoadCtrls.AtUserOrApplicationRequirement;
                OnPropertyChanged("AtUserOrApplicationRequirement");
            }
        }

        public Boolean NotLoad {
            get {
                return (loadCtrls & ab.LoadCtrls.NotLoad) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.NotLoad;
                else
                    loadCtrls &= ~ab.LoadCtrls.NotLoad;
                OnPropertyChanged("NotLoad");
            }
        }

        public Boolean TransparencyLoad {
            get {
                return (loadCtrls & ab.LoadCtrls.TransparencyLoad) != 0;
            }
            set {
                if (value)
                    loadCtrls |= ab.LoadCtrls.TransparencyLoad;
                else
                    loadCtrls &= ~ab.LoadCtrls.TransparencyLoad;
                OnPropertyChanged("TransparencyLoad");
            }
        }

        void OnPropertyChanged(String propertyName) {
            PropertyChangedEventHandler temp = PropertyChanged;
            if (null != temp)
                temp(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

コンバータ:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using ab = AndreyBushman.AutoCAD;

namespace AcadLoadManaged {

    public sealed class LoadCtrlsConverter : IValueConverter {

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture) {
            ab.LoadCtrls x = (ab.LoadCtrls)value;
            return new LoadCtrlsWrapper(x);
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture) {
            LoadCtrlsWrapper x = (LoadCtrlsWrapper)value;
            return x.GetloadCtrls();
        }
    }
}

XAML:

<GroupBox Grid.Row="4" Header="Load this plugin, when...:" Grid.Column="0" 
          Grid.ColumnSpan="2" Padding="3">
    <GroupBox.DataContext>
        <Binding ElementName="lstAllUsers" Path="SelectedItem.LoadCtrls" Mode="TwoWay">
            <Binding.Converter>
                <local:LoadCtrlsConverter/>
            </Binding.Converter>
        </Binding>
    </GroupBox.DataContext>
    <StackPanel>
        <CheckBox Margin="2" Content="At proxy found" IsChecked="{Binding Path=AtProxyFound}"/>
        <CheckBox Margin="2" Content="At AutoCAD start" IsChecked="{Binding Path=AtAutoCADStart}"/>
        <CheckBox Margin="2" Content="At command start" IsChecked="{Binding Path=AtCommandStart}"/>
        <CheckBox Margin="2" Content="At user or application requirement" 
                  IsChecked="{Binding Path=AtUserOrApplicationRequirement}"/>
        <CheckBox Margin="2" Content="Not load" IsChecked="{Binding Path=NotLoad}"/>
        <CheckBox Margin="2" Content="Transparency load" IsChecked="{Binding Path=TransparencyLoad}"/>
    </StackPanel>
</GroupBox>

しかし、私のバインディングは一方向にしか機能しません。値を変更するCheckBoxと、保存されません。メソッドでブレークポイントを試しましConvertBackたが、発生していません。なんで?

4

3 に答える 3

2

同様のニーズがあったので、TwoWay フラグ バインディングの私のアプローチを次に示します。ハードコードされた列挙型やあらゆる種類の値はありません。TargetType と Flags を設定するだけです。設定ウィンドウに最適です。

使用法:

<TextBox Text="{Binding ElementName=flagsCtrl, Path=Flags, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<local:FlagsControl x:Name="flagsCtrl" TargetType="{x:Type local:TestFlags}" SelectionMode="Multiple"/>

フラグ制御:

using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace FlagsControlDemoApplication
{
    public class FlagsControl : ItemsControl
    {
        public FlagsControl()
        {
            DataProvider = new ObservableCollection<Model>();

            Loaded += OnControlLoaded;
        }

        private void OnControlLoaded(object sender, RoutedEventArgs e)
        {
            Loaded -= OnControlLoaded;

            Binding isCheckedBinding = new Binding();
            isCheckedBinding.Path = new PropertyPath(Model.IsCheckedProperty);
            isCheckedBinding.Mode = BindingMode.TwoWay;
            isCheckedBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

            Binding nameBinding = new Binding();
            nameBinding.Path = new PropertyPath(Model.NameProperty);
            nameBinding.Mode = BindingMode.TwoWay;
            nameBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

            var checkBoxFactory = new FrameworkElementFactory(typeof(CheckBox));
            checkBoxFactory.SetValue(CheckBox.IsCheckedProperty, isCheckedBinding);
            checkBoxFactory.SetValue(CheckBox.ContentProperty, nameBinding);
            checkBoxFactory.AddHandler(CheckBox.CheckedEvent, new RoutedEventHandler(OnCheckBoxChecked));
            checkBoxFactory.AddHandler(CheckBox.UncheckedEvent, new RoutedEventHandler(OnCheckBoxUnchecked));

            ItemTemplate = new DataTemplate(typeof(CheckBox));
            ItemTemplate.VisualTree = checkBoxFactory;
            ItemsSource = DataProvider;
        }

        public FlagSelectionMode SelectionMode
        {
            get { return (FlagSelectionMode)GetValue(SelectionModeProperty); }
            set { SetValue(SelectionModeProperty, value); }
        }
        public static readonly DependencyProperty SelectionModeProperty =
            DependencyProperty.Register(nameof(SelectionMode), typeof(FlagSelectionMode), typeof(FlagsControl), new PropertyMetadata(FlagSelectionMode.Multiple));

        public ObservableCollection<Model> DataProvider
        {
            get { return (ObservableCollection<Model>)GetValue(DataProviderProperty); }
            set { SetValue(DataProviderProperty, value); }
        }
        public static readonly DependencyProperty DataProviderProperty =
            DependencyProperty.Register(nameof(DataProvider), typeof(ObservableCollection<Model>), typeof(FlagsControl), new PropertyMetadata(null));

        public uint Flags
        {
            get { return (uint)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Flags), typeof(uint), typeof(FlagsControl), new PropertyMetadata(OnValuePropertyChanged));

        private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            foreach (var model in ((FlagsControl)d).DataProvider)
            {
                var val = (uint)Convert.ChangeType(e.NewValue, typeof(uint));

                if (Exists(val, model.Value) != model.IsChecked)
                {
                    model.IsChecked = !model.IsChecked;
                }
            }
        }

        public Type TargetType
        {
            get { return (Type)GetValue(TargetTypeProperty); }
            set { SetValue(TargetTypeProperty, value); }
        }
        public static readonly DependencyProperty TargetTypeProperty =
            DependencyProperty.Register(nameof(TargetType), typeof(Type), typeof(FlagsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnTargetTypePropertyChanged)));

        private static void OnTargetTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var provider = ((FlagsControl)d).DataProvider;

            FieldInfo[] fields = ((Type)e.NewValue).GetFields(BindingFlags.Public | BindingFlags.Static);

            provider.Clear();

            foreach (var field in fields)
            {
                var fieldValue = (uint)Convert.ChangeType(field.GetValue(null), typeof(uint));

                provider.Add(new Model() { Name = field.Name, IsChecked = Exists(((FlagsControl)d).Flags, fieldValue), Value = fieldValue });
            }

            ((FlagsControl)d).DataProvider = provider;
        }

        private void OnCheckBoxChecked(object sender, RoutedEventArgs e)
        {
            if (SelectionMode == FlagSelectionMode.Multiple)
                Flags = Add(Flags, ((Model)((CheckBox)sender).DataContext).Value);
            else Flags = ((Model)((CheckBox)sender).DataContext).Value;
        }
        private void OnCheckBoxUnchecked(object sender, RoutedEventArgs e)
        {
            Flags = Remove(Flags, ((Model)((CheckBox)sender).DataContext).Value);
        }

        public static bool Exists(uint flags, uint flag) => (flags & flag) == flag;
        public static uint Add(uint flags, uint flag) => flags |= flag;
        public static uint Remove(uint flags, uint flag) => Exists(flags, flag) ? flags ^ flag : flags;
    }

    public enum FlagSelectionMode
    {
        Multiple, Single
    }

    public class Model : DependencyObject
    {
        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register(nameof(IsChecked), typeof(bool), typeof(Model));

        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register(nameof(Name), typeof(string), typeof(Model));

        public uint Value
        {
            get { return (uint)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Value), typeof(uint), typeof(Model));
    }
}

デモアプリとソースコード

于 2015-10-13T11:24:06.220 に答える
0

Model(LoadCtrls) をView(XAML)に適合させるには、 を使用しViewModelます。

public class ApplicationSettingsViewModel :
    MyViewModelBaseImplementingINotifyPropertyChanged {

    public ApplicationSettingsViewModel(ApplicationSettings model)
    {
      m_model = model;
      m_model.PropertyChanged += OnModelPropertyChanged;
    }

    ... OnModelPropertyChanged(object sender, WhateverArgs e)
    {
      switch(e.PropertyName)
      {
        ...
        case "Load":
          RaisePropertyChanged("IsAtProxyFoundSet");
          RaisePropertyChanged("IsAtAutoCADStartSet");
          ...
          break;
        ...
      }
    }

    ...
    public bool IsAtProxyFoundSet
    {
       get { return m_model.Load & LoadCtrls.AtProxyFound; }
       set { m_model.Load |= LoadCtrls.AtProxyFound; }
    }

    public bool IsAtAutoCADStartSet
    {
       get { return m_model.Load & LoadCtrls.AtAutoCADStart; }
       set { m_model.Load |= LoadCtrls.AtAutoCADStart; }
    }

    ...
}

アップデート

更新された例を次に示します。

public sealed class UserWrapper {

    private User m_user;

    public UserWrapper(User user) {
        m_user = user;
    }

    public Boolean AtAutoCADStart {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.AtAutoCADStart) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.AtAutoCADStart;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.AtAutoCADStart;
        }
    }

    public Boolean AtCommandStart {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.AtCommandStart) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.AtCommandStart;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.AtCommandStart;
        }
    }

    public Boolean AtProxyFound {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.AtProxyFound) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.AtProxyFound;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.AtProxyFound;
        }
    }

    public Boolean AtUserOrApplicationRequirement {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.AtUserOrApplicationRequirement) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.AtUserOrApplicationRequirement;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.AtUserOrApplicationRequirement;
        }
    }

    public Boolean NotLoad {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.NotLoad) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.NotLoad;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.NotLoad;
        }
    }

    public Boolean TransparencyLoad {
        get {
            return (m_user.loadCtrls & ab.LoadCtrls.TransparencyLoad) != 0;
        }
        set {
            if (value)
                m_user.loadCtrls |= ab.LoadCtrls.TransparencyLoad;
            else
                m_user.loadCtrls &= ~ab.LoadCtrls.TransparencyLoad;
        }
    }

}

コンバータ:

    public sealed class UserToUserWrapperConverter : IValueConverter {

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture) {
              return new UserWrapper((User)value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
            throw new Exception(); // never called
        }
    }
}

XAML:

<GroupBox Grid.Row="4" Header="Load this plugin, when...:" Grid.Column="0" 
          Grid.ColumnSpan="2" Padding="3">
    <GroupBox.DataContext>
        <Binding ElementName="lstAllUsers" Path="SelectedItem">
            <Binding.Converter>
                <local:UserToUserWrapperConverter/>
            </Binding.Converter>
        </Binding>
    </GroupBox.DataContext>
    <StackPanel>
        <CheckBox Margin="2" Content="At proxy found" IsChecked="{Binding Path=AtProxyFound}"/>
        <CheckBox Margin="2" Content="At AutoCAD start" IsChecked="{Binding Path=AtAutoCADStart}"/>
        <CheckBox Margin="2" Content="At command start" IsChecked="{Binding Path=AtCommandStart}"/>
        <CheckBox Margin="2" Content="At user or application requirement" 
                  IsChecked="{Binding Path=AtUserOrApplicationRequirement}"/>
        <CheckBox Margin="2" Content="Not load" IsChecked="{Binding Path=NotLoad}"/>
        <CheckBox Margin="2" Content="Transparency load" IsChecked="{Binding Path=TransparencyLoad}"/>
    </StackPanel>
</GroupBox>
于 2012-11-16T11:31:14.437 に答える
0

enum フラグとその enum 値の間に依存関係があるため、カスタム チェックボックスを使用して 2 つのプロパティにバインドします。

これは私のコードです (私は本番環境で使用して成功しています。使い方は非常に簡単です。クラスの上部にあるコメントを参照してください)。

あなたはそれが好きですか ?

using System;
using System.Windows;
using System.Windows.Controls;

namespace HQ.Wpf.Util.MyControl
{
    /// <summary>
    /// Usage: Bind on EnumFlag and Two way binding on EnumValue instead of IsChecked
    /// Example: <myControl:CheckBoxForEnumWithFlagAttribute 
    ///                 EnumValue="{Binding SimulationNatureTypeToCreateStatsCacheAtEndOfSimulation, Mode=TwoWay}" 
    ///                 EnumFlag="{x:Static Core:SimulationNatureType.LoadFlow }">Load Flow results</myControl:CheckBoxForEnumWithFlagAttribute>
    /// </summary>
    public class CheckBoxForEnumWithFlagAttribute : CheckBox
    {
        // ************************************************************************
        public static DependencyProperty EnumValueProperty =
            DependencyProperty.Register("EnumValue", typeof(object), typeof(CheckBoxForEnumWithFlagAttribute), new PropertyMetadata(EnumValueChangedCallback));

        public static DependencyProperty EnumFlagProperty =
            DependencyProperty.Register("EnumFlag", typeof(object), typeof(CheckBoxForEnumWithFlagAttribute), new PropertyMetadata(EnumFlagChangedCallback));

        // ************************************************************************
        public CheckBoxForEnumWithFlagAttribute()
        {
            base.Checked += CheckBoxForEnumWithFlag_Checked;
            base.Unchecked += CheckBoxForEnumWithFlag_Unchecked;
        }

        // ************************************************************************
        private static void EnumValueChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var checkBoxForEnumWithFlag = dependencyObject as CheckBoxForEnumWithFlagAttribute;
            if (checkBoxForEnumWithFlag != null)
            {
                checkBoxForEnumWithFlag.RefreshCheckBoxState();
            }
        }

        // ************************************************************************
        private static void EnumFlagChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var checkBoxForEnumWithFlag = dependencyObject as CheckBoxForEnumWithFlagAttribute;
            if (checkBoxForEnumWithFlag != null)
            {
                checkBoxForEnumWithFlag.RefreshCheckBoxState();
            }
        }

        // ************************************************************************
        public object EnumValue
        {
            get { return GetValue(EnumValueProperty); }
            set { SetValue(EnumValueProperty, value); }
        }

        // ************************************************************************
        public object EnumFlag
        {
            get { return GetValue(EnumFlagProperty); }
            set { SetValue(EnumFlagProperty, value); }
        }

        // ************************************************************************
        private void RefreshCheckBoxState()
        {
            if (EnumValue != null)
            {
                if (EnumValue is Enum)
                {
                    Type underlyingType = Enum.GetUnderlyingType(EnumValue.GetType());
                    dynamic valueAsInt = Convert.ChangeType(EnumValue, underlyingType);
                    dynamic flagAsInt = Convert.ChangeType(EnumFlag, underlyingType);

                    base.IsChecked = ((valueAsInt & flagAsInt) > 0);
                }
            }
        }

        // ************************************************************************
        private void CheckBoxForEnumWithFlag_Checked(object sender, RoutedEventArgs e)
        {
            RefreshEnumValue();
        }

        // ************************************************************************
        void CheckBoxForEnumWithFlag_Unchecked(object sender, RoutedEventArgs e)
        {
            RefreshEnumValue();
        }

        // ************************************************************************
        private void RefreshEnumValue()
        {
            if (EnumValue != null)
            {
                if (EnumValue is Enum)
                {
                    Type underlyingType = Enum.GetUnderlyingType(EnumValue.GetType());
                    dynamic valueAsInt = Convert.ChangeType(EnumValue, underlyingType);
                    dynamic flagAsInt = Convert.ChangeType(EnumFlag, underlyingType);

                    dynamic newValueAsInt = valueAsInt;
                    if (base.IsChecked == true)
                    {
                        newValueAsInt = valueAsInt | flagAsInt;
                    }
                    else
                    {
                        newValueAsInt = valueAsInt & ~flagAsInt;
                    }

                    if (newValueAsInt != valueAsInt)
                    {
                        object o = Enum.ToObject(EnumValue.GetType(), newValueAsInt);

                        EnumValue = o;
                    }
                }
            }
        }

        // ************************************************************************
    }
}
于 2014-02-26T19:11:03.107 に答える