Bagaimana cara mengikat RadioButtons ke enum?

406

Saya mendapat enum seperti ini:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Saya mendapat properti di DataContext saya:

public MyLovelyEnum VeryLovelyEnum { get; set; }

Dan saya mendapat tiga RadioButtons di klien WPF saya.

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

Sekarang bagaimana saya mengikat RadioButtons ke properti untuk pengikatan dua arah yang tepat?

Sam
sumber
3
Jika Anda ingin melakukan ini tanpa menentukan masing-masing RadioButtons di XAML Anda, saya akan merekomendasikan ListBox terikat dengan nilai enum seperti ini atau ini , dan yang memiliki templat item ditimpa untuk menggunakan RadioButtons seperti ini .
Rachel

Jawaban:

389

Anda dapat menggunakan konverter yang lebih umum

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
}

Dan di XAML-Part yang Anda gunakan:

<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>
Lars
sumber
51
Bekerja seperti pesona bagi saya. Sebagai tambahan saya memodifikasi ConvertBack untuk juga mengembalikan UnsetValue pada "false", karena silverlight (dan mungkin WPF yang tepat) memanggil konverter dua kali - sekali ketika mengeset nilai tombol radio lama dan sekali lagi untuk mengatur yang baru. Saya menggantung barang-barang lain dari properti setter jadi saya hanya ingin itu dipanggil sekali. - if (parameterString == null || value.Equals (false)) mengembalikan DependencyProperty.UnsetValue;
MarcE
8
Dari apa yang saya tahu, ini harus dilakukan kecuali tombol radio berada di grup yang berbeda (dan tombol AFAIK tanpa set GroupName yang memiliki induk yang sama secara default di grup yang sama). Jika tidak, panggilan untuk mengatur properti "terpental" dan menghasilkan perilaku aneh.
nlawalker
2
ya tetapi jika Anda memanggil Unset di konverter ketika disetel ke false, maka itu bukan EnumToBooleanConverter yang sebenarnya tetapi lebih merupakan EnumToRadioButtonConverter. Jadi alih-alih saya memeriksa apakah nilainya berbeda di setter properti saya: if (_myEnumBackingField == value) kembali;
Stéphane
8
Pengikatan pada solusi ini hanya berfungsi dengan benar satu arah. Saya tidak bisa secara program matikan radiobutton dengan menetapkan properti yang diikat ke nilai yang berbeda. Jika Anda menginginkan solusi yang berfungsi DAN lebih baik, gunakan pendekatan scott.
l46kok
2
@ Mark, bukankah hal yang tepat untuk kembali dalam kasus 'Binding.DoNothing' dan bukan 'DependencyProperty.UnsetValue'?
Mark A. Donohoe
560

Anda selanjutnya dapat menyederhanakan jawaban yang diterima. Alih-alih mengetik enum sebagai string dalam xaml dan melakukan lebih banyak pekerjaan di konverter daripada yang dibutuhkan, Anda dapat secara eksplisit meneruskan nilai enum alih-alih representasi string, dan seperti dikomentari CrimsonX, kesalahan dapat terjadi pada waktu kompilasi alih-alih runtime:

ConverterParameter = {x: Statis lokal: 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>

Kemudian sederhanakan konverter:

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;
    }
}

Edit (Des 16 '10):

Terima kasih kepada anon untuk menyarankan pengembalian Binding.DoNothing daripada DependencyProperty.UnsetValue.


Catatan - Beberapa grup RadioButtons dalam wadah yang sama (17 Feb '11):

Dalam xaml, jika tombol radio berbagi wadah induk yang sama, maka memilih satu akan membatalkan pilihan semua yang lain di dalam wadah itu (bahkan jika mereka terikat pada properti yang berbeda). Jadi cobalah untuk menjaga RadioButton Anda yang terikat pada properti umum yang dikelompokkan bersama dalam wadah mereka sendiri seperti panel tumpukan. Dalam kasus di mana RadioButtons Anda yang terkait tidak dapat membagikan wadah induk tunggal, kemudian tetapkan properti GroupName dari setiap RadioButton ke nilai umum untuk mengelompokkannya secara logis.


Edit (5 Apr '11):

ConvertBack Sederhana jika-lain menggunakan Operator Ternary.


Catatan - Jenis Enum bersarang di kelas (28 Apr '11):

Jika tipe enum Anda bersarang di kelas (bukan langsung di namespace), Anda mungkin dapat menggunakan sintaks '+' untuk mengakses enum di XAML seperti yang dinyatakan dalam jawaban (tidak ditandai) untuk pertanyaan yang tidak dapat menemukan tipe enum untuk referensi statis di WPF :

ConverterParameter = {x: Statis lokal: YourClass + YourNestedEnumType.Enum1}

Karena Masalah Microsoft Connect ini , bagaimanapun, perancang di VS2010 tidak akan lagi memuat pernyataan "Type 'local:YourClass+YourNestedEnumType' was not found.", tetapi proyek tersebut mengkompilasi dan berjalan dengan sukses. Tentu saja, Anda dapat menghindari masalah ini jika Anda dapat memindahkan tipe enum Anda ke namespace secara langsung.


Edit (27 Jan '12):

Jika menggunakan bendera Enum, konverternya adalah sebagai berikut:

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;
    }
}

Edit (7 Mei '15):

Dalam kasus Nullable Enum (yang tidak ditanyakan dalam pertanyaan, tetapi dapat diperlukan dalam beberapa kasus, misalnya ORM mengembalikan nol dari DB atau kapan pun mungkin masuk akal bahwa dalam logika program nilai tidak diberikan), ingatlah untuk menambahkan pemeriksaan awal nol dalam Metode Konversi dan kembalikan nilai bool yang sesuai, yang biasanya salah (jika Anda tidak ingin tombol radio dipilih), seperti di bawah ini:

    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);
    }

Catatan - NullReferenceException (10 Okt '18):

Diperbarui contoh untuk menghapus kemungkinan melempar NullReferenceException. IsCheckedadalah jenis yang dapat dibatalkan sehingga mengembalikan Nullable<Boolean>tampaknya merupakan solusi yang masuk akal.

Scott
sumber
26
Saya setuju, saya percaya ini adalah solusi yang lebih baik. Juga, menggunakan konversi ini akan menyebabkan proyek rusak pada waktu kompilasi, bukan waktu berjalan, jika nilai enumerasi diubah, yang merupakan keuntungan besar.
CrimsonX
4
Ini tentu saja merupakan solusi yang jauh lebih baik daripada yang diterima. +1
OrPaz
7
Solusi yang bagus. Saya akan menambahkan bahwa ini benar-benar hanya sebuah konverter perbandingan yang membandingkan 2 nilai. Itu bisa memiliki nama yang lebih umum daripada EnumToBooleanConverter seperti ComparisonConverter
MikeKulls
5
@ Scott, sangat bagus. Konverter ini bagus dalam hal apa pun, dengan atau tanpa atribut Flags. Tetapi akan konyol dalam banyak kasus untuk menggunakan filter ini secara langsung sebagai konverter dengan enum sebagai flag. Alasannya adalah Anda harus mencapai boolean calc (| = atau ^ =) dengan nilai sebelumnya untuk mendapatkan hasil yang tepat tetapi konverter tidak memiliki akses ke nilai sebelumnya. Anda kemudian harus menambahkan bool untuk setiap nilai enum dan melakukan sendiri boolean calc dalam model MVVM Anda. Tapi terima kasih untuk setiap info, sangat berguna.
Eric Ouellet
2
Di Windows Phone 8 (Mungkin untuk Aplikasi Win Store) kami tidak memiliki x: statis, jadi kami tidak dapat langsung menggunakan solusinya di sini. Namun IDE / Complier cukup pintar, dan mencari string terhadap semua string literal (tebakan saya). mis. ini berfungsi <RadioButton IsChecked = "{Binding TrackingMode, ConverterParameter = Berkendara, Konverter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Setiap kesalahan ketik dalam Mengemudi akan ditangkap selama desain / waktu kompilasi daripada waktu berjalan.
Adarsha
26

Untuk jawaban EnumToBooleanConverter: Alih-alih mengembalikan DependencyProperty.UnsetValue pertimbangkan untuk mengembalikan Binding. Tidak ada kasus di mana nilai IsChecked tombol radio menjadi false. Yang pertama menunjukkan masalah (dan mungkin menunjukkan pengguna persegi panjang merah atau indikator validasi serupa) sementara yang kedua hanya menunjukkan bahwa tidak ada yang harus dilakukan, yang merupakan apa yang diinginkan dalam kasus itu.

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

segera
sumber
Tidak ada Binding. Tidak ada di Silverlight. Ini hanya WPF. Gunakan null sebagai gantinya.
Alexander Vasilyev
1
Binding. Tidak ada yang juga hilang dari UWP.
BlackICE
5

Saya akan menggunakan RadioButtons di ListBox, dan kemudian ikat ke SelectedValue.

Ini adalah utas yang lebih lama tentang topik ini, tetapi ide dasarnya harus sama: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

Martin Moser
sumber
Saya mendapatkan pengikatan dua arah melakukan metode yang sama menggunakan ListBox dan DataTemplate jadi Anda harus.
Bryan Anderson
Bug ini: geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx menghancurkan sehari untuk saya.
Slampen
3
Sejauh ini ini adalah solusi terbaik, yang lainnya menyebabkan kode redundan. ( Contoh lain menggunakan ListBox)
HB
3

Untuk UWP, itu tidak begitu sederhana: Anda harus melompat melalui lingkaran ekstra untuk melewati nilai bidang sebagai parameter.

Contoh 1

Berlaku untuk WPF dan UWP.

<MyControl>
    <MyControl.MyProperty>
        <Binding Converter="{StaticResource EnumToBooleanConverter}" Path="AnotherProperty">
            <Binding.ConverterParameter>
                <MyLibrary:MyEnum>Field</MyLibrary:MyEnum>
            </Binding.ConverterParameter>
        </MyControl>
    </MyControl.MyProperty>
</MyControl>

Contoh 2

Berlaku untuk WPF dan UWP.

...
<MyLibrary:MyEnum x:Key="MyEnumField">Field</MyLibrary:MyEnum>
...

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={StaticResource MyEnumField}}"/>

Contoh 3

Hanya berlaku untuk WPF!

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static MyLibrary:MyEnum.Field}}"/>

UWP tidak mendukung x:Staticsehingga Contoh 3 keluar dari pertanyaan; dengan asumsi Anda pergi dengan Contoh 1 , hasilnya adalah kode yang lebih bertele-tele. Contoh 2 sedikit lebih baik, tetapi masih belum ideal.

Larutan

public abstract class EnumToBooleanConverter<TEnum> : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;

        if (Parameter == null)
            return DependencyProperty.UnsetValue;

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

        return Enum.Parse(typeof(TEnum), Parameter).Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;
        return Parameter == null ? DependencyProperty.UnsetValue : Enum.Parse(typeof(TEnum), Parameter);
    }
}

Kemudian, untuk setiap jenis yang ingin Anda dukung, tentukan konverter yang mengotak jenis enum.

public class MyEnumToBooleanConverter : EnumToBooleanConverter<MyEnum>
{
    //Nothing to do!
}

Alasannya harus kotak adalah karena sepertinya tidak ada cara untuk referensi jenis dalam ConvertBackmetode ini; tinju menangani itu. Jika Anda menggunakan salah satu dari dua contoh pertama, Anda bisa mereferensikan tipe parameter, menghilangkan keharusan untuk mewarisi dari kelas kotak; jika Anda ingin melakukan semuanya dalam satu baris dan dengan kemungkinan yang paling sedikit, solusi yang terakhir sangat ideal.

Penggunaannya menyerupai Contoh 2 , tetapi pada kenyataannya lebih sedikit bertele-tele.

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>

Kelemahannya adalah Anda harus menentukan konverter untuk setiap jenis yang ingin Anda dukung.

James M
sumber
1

Saya telah membuat kelas baru untuk menangani RadioButtons dan CheckBox yang mengikat ke enum. Ini berfungsi untuk enum yang ditandai (dengan beberapa pilihan kotak centang) dan enum yang tidak ditandai untuk kotak centang pilihan tunggal atau tombol radio. Ini juga tidak memerlukan ValueConverters sama sekali.

Ini mungkin terlihat lebih rumit pada awalnya, namun, setelah Anda menyalin kelas ini ke proyek Anda, selesai. Ini generik sehingga dapat dengan mudah digunakan kembali untuk enum apa pun.

public class EnumSelection<T> : INotifyPropertyChanged where T : struct, IComparable, IFormattable, IConvertible
{
  private T value; // stored value of the Enum
  private bool isFlagged; // Enum uses flags?
  private bool canDeselect; // Can be deselected? (Radio buttons cannot deselect, checkboxes can)
  private T blankValue; // what is considered the "blank" value if it can be deselected?

  public EnumSelection(T value) : this(value, false, default(T)) { }
  public EnumSelection(T value, bool canDeselect) : this(value, canDeselect, default(T)) { }
  public EnumSelection(T value, T blankValue) : this(value, true, blankValue) { }
  public EnumSelection(T value, bool canDeselect, T blankValue)
  {
    if (!typeof(T).IsEnum) throw new ArgumentException($"{nameof(T)} must be an enum type"); // I really wish there was a way to constrain generic types to enums...
    isFlagged = typeof(T).IsDefined(typeof(FlagsAttribute), false);

    this.value = value;
    this.canDeselect = canDeselect;
    this.blankValue = blankValue;
  }

  public T Value
  {
    get { return value; }
    set 
    {
      if (this.value.Equals(value)) return;
      this.value = value;
      OnPropertyChanged();
      OnPropertyChanged("Item[]"); // Notify that the indexer property has changed
    }
  }

  [IndexerName("Item")]
  public bool this[T key]
  {
    get
    {
      int iKey = (int)(object)key;
      return isFlagged ? ((int)(object)value & iKey) == iKey : value.Equals(key);
    }
    set
    {
      if (isFlagged)
      {
        int iValue = (int)(object)this.value;
        int iKey = (int)(object)key;

        if (((iValue & iKey) == iKey) == value) return;

        if (value)
          Value = (T)(object)(iValue | iKey);
        else
          Value = (T)(object)(iValue & ~iKey);
      }
      else
      {
        if (this.value.Equals(key) == value) return;
        if (!value && !canDeselect) return;

        Value = value ? key : blankValue;
      }
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChanged([CallerMemberName] string propertyName = "")
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

Dan untuk cara menggunakannya, katakanlah Anda memiliki enum untuk menjalankan tugas secara manual atau otomatis, dan dapat dijadwalkan untuk hari apa pun dalam seminggu, dan beberapa opsi opsional ...

public enum StartTask
{
  Manual,
  Automatic
}

[Flags()]
public enum DayOfWeek
{
  Sunday = 1 << 0,
  Monday = 1 << 1,
  Tuesday = 1 << 2,
  Wednesday = 1 << 3,
  Thursday = 1 << 4,
  Friday = 1 << 5,
  Saturday = 1 << 6
}

public enum AdditionalOptions
{
  None = 0,
  OptionA,
  OptionB
}

Sekarang, inilah betapa mudahnya menggunakan kelas ini:

public class MyViewModel : ViewModelBase
{
  public MyViewModel()
  {
    StartUp = new EnumSelection<StartTask>(StartTask.Manual);
    Days = new EnumSelection<DayOfWeek>(default(DayOfWeek));
    Options = new EnumSelection<AdditionalOptions>(AdditionalOptions.None, true, AdditionalOptions.None);
  }

  public EnumSelection<StartTask> StartUp { get; private set; }
  public EnumSelection<DayOfWeek> Days { get; private set; }
  public EnumSelection<AdditionalOptions> Options { get; private set; }
}

Dan inilah betapa mudahnya untuk mengikat kotak centang dan tombol radio dengan kelas ini:

<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
    <!-- Using RadioButtons for exactly 1 selection behavior -->
    <RadioButton IsChecked="{Binding StartUp[Manual]}">Manual</RadioButton>
    <RadioButton IsChecked="{Binding StartUp[Automatic]}">Automatic</RadioButton>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or Many selection behavior -->
    <CheckBox IsChecked="{Binding Days[Sunday]}">Sunday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Monday]}">Monday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Tuesday]}">Tuesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Wednesday]}">Wednesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Thursday]}">Thursday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Friday]}">Friday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Saturday]}">Saturday</CheckBox>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or 1 selection behavior -->
    <CheckBox IsChecked="{Binding Options[OptionA]}">Option A</CheckBox>
    <CheckBox IsChecked="{Binding Options[OptionB]}">Option B</CheckBox>
  </StackPanel>
</StackPanel>
  1. Ketika UI dimuat, tombol radio "Manual" akan dipilih dan Anda dapat mengubah pilihan Anda antara "Manual" atau "Otomatis" tetapi salah satunya harus selalu dipilih.
  2. Setiap hari dalam seminggu akan tidak dicentang, tetapi sejumlah dari mereka dapat diperiksa atau dicentang.
  3. "Opsi A" dan "Opsi B" pada awalnya tidak akan dicentang. Anda dapat memeriksa satu atau yang lain, memeriksa satu akan menghapus centang yang lain (mirip dengan RadioButtons), tetapi sekarang Anda juga dapat menghapus centang keduanya (yang tidak dapat Anda lakukan dengan RadioButton WPF, itulah sebabnya CheckBox digunakan di sini)
Nick
sumber
Misalkan Anda memiliki 3 item dalam StartTask enum seperti {Undefined, Manual, Automatic} Anda ingin default ke Undefined karena sampai seorang pengguna menetapkan nilai, itu tidak terdefinisi. Juga: Bagaimana SelectedItem ditangani? ViewModel Anda tidak memiliki SelectedStartTask.
user1040323
Di ViewModel saya, properti StartUp adalah EnumSelection<StartTask>objek. Jika Anda melihat definisi EnumSelection<T>Anda dapat melihat bahwa ia memiliki properti Value. Jadi model tampilan tidak perlu memiliki "SelectedStartTask". Anda akan menggunakannya StartUp.Value. Dan untuk memiliki nilai default Undefined, lihat enum ke-3, AdditionalOptions, ia memiliki None, bukan Undefined, tetapi Anda dapat mengubah namanya menjadi apa pun yang Anda inginkan.
Nick
1

Ini juga berfungsi untuk Kotak Centang .

public class EnumToBoolConverter:IValueConverter
{
    private int val;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int intParam = (int)parameter;
        val = (int)value;

        return ((intParam & val) != 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        val ^= (int)parameter;
        return Enum.Parse(targetType, val.ToString());
    }
}

Mengikat satu enum ke beberapa kotak centang.

Ali Bayat
sumber
1
Saya mengucapkan "TERIMA KASIH" kepada Anda atas bantuan yang Anda lakukan untuk saya. Ini bekerja seperti pesona bagi saya.
Elham Azadfar
0

Berdasarkan EnumToBooleanConverter dari Scott. Saya perhatikan bahwa metode ConvertBack tidak berfungsi pada Enum dengan kode flags.

Saya sudah mencoba kode berikut:

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;
                }
            }
        }
    }

Satu-satunya hal yang saya tidak bisa mulai bekerja adalah membuat gips dari intke targetTypejadi saya membuatnya hardcode ke NavigationProjectDates, enum yang saya gunakan. Dan, targetType == NavigationProjectDates...


Edit untuk konverter Flags Enum yang lebih umum:

    Bendera kelas publikEnumToBooleanConverter: IValueConverter {
        private int _flags = 0;
        Konversi objek publik (nilai objek, Jenis targetType, parameter objek, bahasa string) {
            if (value == null) return false;
            _flags = (int) nilai;
            Ketik t = value.GetType ();
            objek o = Enum.ToObject (t, parameter);
            return ((Enum) value) .HasFlag ((Enum) o);
        }

        ConvertBack objek publik (nilai objek, Jenis targetType, parameter objek, bahasa string)
        {
            if (value? .Equals (true) ?? false) {
                _flags = _flags | (int) parameter;
            }
            lain {
                _flags = _flags & ~ (int) parameter;
            }
            kembalikan _flags;
        }
    }
KenGey
sumber
Seseorang telah mengedit jawaban saya untuk menambahkan dengan kode Bendera, jadi jujur, saya tidak pernah mencoba / menggunakannya sendiri dan telah mempertimbangkan untuk menghapusnya karena saya pikir itu lebih masuk akal sebagai jawabannya sendiri. Jika saya dapat menemukan beberapa waktu kemudian, saya dapat mencoba dan mengumpulkan sesuatu untuk menguji kode itu serta apa yang Anda miliki dan mungkin membantu mencapai solusi yang lebih baik untuk masalah Anda.
Scott
0

Anda dapat membuat tombol radio secara dinamis, ListBoxdapat membantu Anda melakukan itu, tanpa konverter, cukup sederhana.

Langkah-langkah concreate di bawah ini: membuat ListBox dan mengatur ItemsSource untuk listbox sebagai enum MyLovelyEnumdan mengikat SelectedItem dari ListBox ke VeryLovelyEnumproperti. Kemudian Tombol Radio untuk setiap ListBoxItem akan dibuat.

  • Langkah 1 : tambahkan enum ke sumber daya statis untuk Window, UserControl atau Grid Anda dll.
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type system:Enum}"
                            x:Key="MyLovelyEnum">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:MyLovelyEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
  • Langkah 2 : Gunakan Kotak Daftar dan isi Control Templatesetiap item di dalamnya sebagai tombol Radio
    <ListBox ItemsSource="{Binding Source={StaticResource MyLovelyEnum}}" SelectedItem="{Binding VeryLovelyEnum, Mode=TwoWay}" >
        <ListBox.Resources>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <RadioButton
                                Content="{TemplateBinding ContentPresenter.Content}"
                                IsChecked="{Binding Path=IsSelected,
                                RelativeSource={RelativeSource TemplatedParent},
                                Mode=TwoWay}" />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
    </ListBox>

The Keuntungan bawah: jika suatu hari nanti perubahan kelas enum Anda, Anda tidak perlu memperbarui GUI (file XAML).

Referensi: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

Bravo Yeung
sumber