449

私はこのような列挙型を持っています:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

DataContextにプロパティを取得しました:

public MyLovelyEnum VeryLovelyEnum { get; set; }

そして、WPFクライアントに3つのラジオボタンがあります。

<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>

次に、適切な双方向バインディングのためにRadioButtonsをプロパティにバインドするにはどうすればよいですか?

4

11 に答える 11

606

受け入れられた回答をさらに単純化できます。列挙型を xaml の文字列として入力し、コンバーターで必要以上の作業を行う代わりに、文字列表現の代わりに列挙値を明示的に渡すことができます。CrimsonX がコメントしたように、実行時ではなくコンパイル時にエラーがスローされます。

ConverterParameter={x:Static local:YourEnumType.Enum1}

<StackPanel>
    <StackPanel.Resources>          
        <local:ComparisonConverter x:Key="ComparisonConverter" />          
    </StackPanel.Resources>
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" />
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" />
</StackPanel>

次に、コンバーターを単純化します。

public class ComparisonConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value?.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value?.Equals(true) == true ? parameter : Binding.DoNothing;
    }
}

編集(10年12月16日):

DependencyProperty.UnsetValue ではなく Binding.DoNothing を返すことを提案してくれた anon に感謝します。


注 - 同じコンテナー内の RadioButtons の複数のグループ (2011 年 2 月 17 日):

xaml では、ラジオ ボタンが同じ親コンテナーを共有している場合、1 つを選択すると、そのコンテナー内の他のすべての選択が解除されます (別のプロパティにバインドされている場合でも)。そのため、共通のプロパティにバインドされている RadioButton を、スタック パネルのような独自のコンテナーにまとめてグループ化するようにしてください。関連する RadioButton が 1 つの親コンテナーを共有できない場合は、各 RadioButton の GroupName プロパティを共通の値に設定して、それらを論理的にグループ化します。

編集(11年4月5日):

三項演算子を使用するために ConvertBack の if-else を簡素化しました。

注 - クラスにネストされた列挙型 (2011 年 4 月 28 日):

列挙型が (名前空間に直接ではなく) クラスにネストされている場合、質問に対する (マークされていない) 回答に記載されているように、「+」構文を使用して XAML の列挙型にアクセスできる場合があります。

ConverterParameter={x:Static local: YourClass+ YourNestedEnumType.Enum1}

ただし、このMicrosoft Connect の問題により、VS2010 のデザイナーは状態をロードしなくなります"Type 'local:YourClass+YourNestedEnumType' was not found."が、プロジェクトは正常にコンパイルおよび実行されます。もちろん、列挙型を名前空間に直接移動できる場合は、この問題を回避できます。


編集(12年1月27日):

Enum フラグを使用する場合、コンバーターは次のようになります。
public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((Enum)value).HasFlag((Enum)parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? parameter : Binding.DoNothing;
    }
}

編集(15年5月7日):

Nullable Enum の場合 (これは質問では **尋ねられませんが、場合によっては必要になる場合があります。たとえば、ORM が DB から null を返す場合や、プログラム ロジックで値が提供されていないことが理にかなっている場合など)。 Convert メソッドに最初の null チェックを追加し、適切な bool 値を返すことを忘れないでください。これは、通常は false です (ラジオ ボタンを選択したくない場合)。
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) {
            return false; // or return parameter.Equals(YourEnumType.SomeDefaultValue);
        }
        return value.Equals(parameter);
    }

注 - NullReferenceException (18 年 10 月 10 日):

NullReferenceException をスローする可能性を排除するために例を更新しました。`IsChecked` は null 許容型なので、 `Nullable` を返すことは合理的な解決策のようです。
于 2010-05-25T22:07:39.183 に答える
413

より一般的なコンバーターを使用できます

public class EnumBooleanConverter : IValueConverter
{
  #region IValueConverter Members
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
      return DependencyProperty.UnsetValue;

    if (Enum.IsDefined(value.GetType(), value) == false)
      return DependencyProperty.UnsetValue;

    object parameterValue = Enum.Parse(value.GetType(), parameterString);

    return parameterValue.Equals(value);
  }

  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
        return DependencyProperty.UnsetValue;

    return Enum.Parse(targetType, parameterString);
  }
  #endregion
}

XAML-Part では、次を使用します。

<Grid>
    <Grid.Resources>
      <l:EnumBooleanConverter x:Key="enumBooleanConverter" />
    </Grid.Resources>
    <StackPanel >
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FirstSelection}">first selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=TheOtherSelection}">the other selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=YetAnotherOne}">yet another one</RadioButton>
    </StackPanel>
</Grid>
于 2009-01-02T13:36:50.543 に答える
27

EnumToBooleanConverter の回答: DependencyProperty.UnsetValue を返す代わりに、ラジオ ボタンの IsChecked 値が false になる場合に備えて Binding.DoNothing を返すことを検討してください。前者は問題を示します (そして、ユーザーに赤い四角形または同様の検証インジケーターを表示する可能性があります) が、後者は単に何もする必要がないことを示します。これは、その場合に必要なことです。

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/library/system.windows.data.binding .donthing.aspx

于 2010-09-03T14:40:26.620 に答える
5

ListBoxでRadioButtonsを使用してから、SelectedValueにバインドします。

これはこのトピックに関する古いスレッドですが、基本的な考え方は同じである必要があります:http ://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

于 2008-12-29T11:51:53.187 に答える
1

ViewModelこれを処理する 1 つの方法は、クラスに個別の bool プロパティを用意することです。このような状況で私が対処した方法は次のとおりです。

ビューモデル:

public enum MyLovelyEnum { FirstSelection, TheOtherSelection, YetAnotherOne };
private MyLovelyEnum CurrentSelection;

public bool FirstSelectionProperty
{
    get
    {
        return CurrentSelection == MyLovelyEnum.FirstSelection;
    }
    set
    {
        if (value)
            CurrentSelection = MyLovelyEnum.FirstSelection;
    }
}

public bool TheOtherSelectionProperty
{
    get
    {
        return CurrentSelection == MyLovelyEnum.TheOtherSelection;
    }
    set
    {
        if (value)
            CurrentSelection = MyLovelyEnum.TheOtherSelection;
    }
}

public bool YetAnotherOneSelectionProperty
{
    get
    {
        return CurrentSelection == MyLovelyEnum.YetAnotherOne;
    }
    set
    {
        if (value)
            CurrentSelection = MyLovelyEnum.YetAnotherOne;
    }
}

XAML:

<RadioButton IsChecked="{Binding SimilaritySort, Mode=TwoWay}">Similarity</RadioButton>
<RadioButton IsChecked="{Binding DateInsertedSort, Mode=TwoWay}">Date Inserted</RadioButton>
<RadioButton IsChecked="{Binding DateOfQuestionSort, Mode=TwoWay}">Date of Question</RadioButton>
<RadioButton IsChecked="{Binding DateModifiedSort, Mode=TwoWay}">Date Modified</RadioButton>

他のソリューションほど堅牢でも動的でもありませんが、優れた点は、非常に自己完結型であり、カスタム コンバーターなどを作成する必要がないことです。

于 2021-09-17T21:47:39.137 に答える
0

Scott の EnumToBooleanConverter に基づいています。ConvertBack メソッドが Enum with flags コードで機能しないことに気付きました。

私は次のコードを試しました:

public class EnumHasFlagToBooleanConverter : IValueConverter
    {
        private object _obj;
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            _obj = value;
            return ((Enum)value).HasFlag((Enum)parameter);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value.Equals(true))
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    // Do nothing
                    return Binding.DoNothing;
                }
                else
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i+ii;
                    return (NavigationProjectDates)newInt;
                }
            }
            else
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i-ii;
                    return (NavigationProjectDates)newInt;

                }
                else
                {
                    // do nothing
                    return Binding.DoNothing;
                }
            }
        }
    }

私が仕事に就けない唯一のことは、からintへのキャストを行うことです。そのため、使用する列挙型targetTypeにハードコードしました。NavigationProjectDatesそして、targetType == NavigationProjectDates...


より一般的な Flags Enum コンバーター用に編集します。

    public class FlagsEnumToBooleanConverter : IValueConverter {
        プライベート int _flags=0;
        public object Convert(オブジェクト値、タイプ targetType、オブジェクト パラメータ、文字列言語) {
            (値 == null) の場合は false を返します。
            _flags = (整数) 値;
            タイプ t = value.GetType();
            オブジェクト o = Enum.ToObject(t、パラメーター);
            return ((Enum)value).HasFlag((Enum)o);
        }

        public object ConvertBack(オブジェクト値、タイプ targetType、オブジェクト パラメータ、文字列言語)
        {
            if (値?.Equals(true) ?? false) {
                _flags = _flags | (整数) パラメータ;
            }
            そうしないと {
                _flags = _flags & ~(int) パラメータ;
            }
            _flags を返します。
        }
    }
于 2013-06-11T10:06:56.957 に答える
0

Nullable を使用する UWP への TwoWay Binding ソリューション:

C# 部分:

public class EnumConverter : IValueConverter
{
    public Type EnumType { get; set; }
    public object Convert(object value, Type targetType, object parameter, string lang)
    {
        if (parameter is string enumString)
        {
            if (!Enum.IsDefined(EnumType, value)) throw new ArgumentException("value must be an Enum!");
            var enumValue = Enum.Parse(EnumType, enumString);
            return enumValue.Equals(value);
        }
        return value.Equals(Enum.ToObject(EnumType,parameter));
    }

    public object ConvertBack(object value, Type targetType, object parameter, string lang)
    {
        if (parameter is string enumString)
            return value?.Equals(true) == true ? Enum.Parse(EnumType, enumString) : null;
        return value?.Equals(true) == true ? Enum.ToObject(EnumType, parameter) : null;
    }
}

ここで、null値は Binding.DoNothing として機能します。

private YourEnum? _yourEnum = YourEnum.YourDefaultValue; //put a default value here
public YourEnum? YourProperty
{
    get => _yourEnum;
    set{
        if (value == null) return;
        _yourEnum = value;
    }
}

Xaml 部分:

...
<Page.Resources>
    <ResourceDictionary>
        <helper:EnumConverter x:Key="YourConverter" EnumType="yournamespace:YourEnum" />
    </ResourceDictionary>
</Page.Resources>
...
<RadioButton GroupName="YourGroupName" IsChecked="{Binding Converter={StaticResource YourConverter}, Mode=TwoWay, Path=YourProperty, ConverterParameter=YourEnumString}">
    First way (parameter of type string)
</RadioButton>
<RadioButton GroupName="LineWidth">
    <RadioButton.IsChecked>
        <Binding
            Converter="{StaticResource PenWidthConverter}"
            Mode="TwoWay"   Path="PenWidth">
            <Binding.ConverterParameter>
                <yournamespace:YourEnum>YourEnumString</yournamespace:YourEnum>
            </Binding.ConverterParameter>
        </Binding>
    </RadioButton.IsChecked>
    Second way (parameter of type YourEnum (actually it was converted to int when passed to converter))
</RadioButton>
于 2021-03-19T02:36:24.067 に答える