Làm cách nào để liên kết RadioButtons với enum?


406

Tôi đã có một enum như thế này:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Tôi có một tài sản trong DataContext của tôi:

public MyLovelyEnum VeryLovelyEnum { get; set; }

Và tôi đã nhận được ba RadioButtons trong ứng dụng khách WPF của mình.

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

Bây giờ làm cách nào để liên kết RadioButtons với thuộc tính để liên kết hai chiều thích hợp?


3
Nếu bạn đang tìm cách thực hiện việc này mà không chỉ định từng RadioButtons trong XAML của mình, tôi sẽ đề xuất một ListBox bị ràng buộc với các giá trị enum như thế này hoặc thế này và có mẫu vật phẩm được ghi đè để sử dụng RadioButtons như thế này .
Rachel

Câu trả lời:


389

Bạn có thể sử dụng một công cụ chuyển đổi chung chung hơn

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
}

Và trong XAML-Part bạn sử dụng:

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

51
Làm việc như một cơ duyên đối với tôi. Ngoài ra, tôi đã sửa đổi ConvertBack để trả lại UnsetValue thành "false", bởi vì silverlight (và có lẽ là WPF thích hợp) gọi bộ chuyển đổi hai lần - một lần khi bỏ đặt giá trị nút radio cũ và một lần nữa để đặt lại giá trị mới. Tôi đã treo những thứ khác ra khỏi setter tài sản vì vậy tôi chỉ muốn nó được gọi một lần. - if (tham sốString == null || value.Equals (false)) return DependencyProperty.UnsetValue;
MarcE

8
Từ những gì tôi có thể nói, điều này phải được thực hiện trừ khi các nút radio nằm trong các nhóm khác nhau (và các nút AFAIK không có nhóm GroupName có cùng cha mẹ theo mặc định trong cùng một nhóm). Mặt khác, các lệnh gọi để đặt thuộc tính "nảy" và dẫn đến hành vi kỳ quặc.
nlawalker

2
có nhưng nếu bạn gọi Unset trong trình chuyển đổi khi đặt thành false, thì đó không phải là EnumToBooleanConverter đúng mà là EnumToRadioButtonConverter. Vì vậy, thay vào đó tôi kiểm tra xem giá trị có khác trong trình thiết lập thuộc tính của mình không: if (_myEnumBackingField == value) return;
Stéphane

8
Các ràng buộc trên giải pháp này chỉ hoạt động chính xác một chiều. Tôi không thể lập trình chuyển đổi radiobutton bằng cách gán thuộc tính bị ràng buộc cho một giá trị khác. Nếu bạn muốn một giải pháp làm việc VÀ tốt hơn, hãy sử dụng phương pháp của scott.
l46kok

2
@Marc, không phải là điều thích hợp để trở lại trong trường hợp đó 'Binding.DoNoth' chứ không phải 'DependencyProperty.UnsetValue'?
Đánh dấu A. Donohoe

560

Bạn có thể đơn giản hóa hơn nữa câu trả lời được chấp nhận. Thay vì gõ enum dưới dạng chuỗi trong xaml và thực hiện nhiều công việc trong trình chuyển đổi của bạn hơn mức cần thiết, bạn có thể chuyển rõ ràng giá trị enum thay vì biểu diễn chuỗi và như CrimsonX nhận xét, lỗi được đưa ra trong thời gian biên dịch thay vì thời gian chạy:

ConverterParameter = {x: Tĩnh cục bộ: 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>

Sau đó đơn giản hóa trình chuyển đổi:

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

Chỉnh sửa (ngày 16 tháng 12 năm 10):

Cảm ơn anon đã đề xuất trả lại Binding.DoNoth thay vì DependencyProperty.UnsetValue.


Lưu ý - Nhiều nhóm RadioButtons trong cùng một thùng chứa (ngày 17 tháng 2 năm 11):

Trong xaml, nếu các nút radio chia sẻ cùng một vùng chứa cha, thì việc chọn một nút sẽ bỏ chọn tất cả các vùng khác trong vùng chứa đó (ngay cả khi chúng bị ràng buộc với một thuộc tính khác). Vì vậy, hãy cố gắng giữ cho RadioButton của bạn được liên kết với một thuộc tính chung được nhóm lại với nhau trong thùng chứa riêng của chúng như bảng ngăn xếp. Trong trường hợp RadioButtons liên quan của bạn không thể chia sẻ một thùng chứa cha mẹ duy nhất, sau đó đặt thuộc tính GroupName của mỗi RadioButton thành một giá trị chung để nhóm chúng một cách hợp lý.


Chỉnh sửa (ngày 5 tháng 4 năm 11):

Đơn giản hóa ConvertBack's if-other để sử dụng Toán tử Ternary.


Lưu ý - Loại Enum được lồng trong một lớp (28 tháng 4 '11):

Nếu loại enum của bạn được lồng trong một lớp (chứ không phải trực tiếp trong không gian tên), bạn có thể sử dụng cú pháp '+' để truy cập enum trong XAML như đã nêu trong câu trả lời (không được đánh dấu) cho câu hỏi Không thể tìm thấy loại enum cho tham chiếu tĩnh trong WPF :

ConverterParameter = {x: Tĩnh cục bộ: YourClass + YourNestedEnumType.Enum1}

Tuy nhiên, do sự cố Microsoft Connect này , nhà thiết kế trong VS2010 sẽ không tải thông báo nữa "Type 'local:YourClass+YourNestedEnumType' was not found.", nhưng dự án đã biên dịch và chạy thành công. Tất nhiên, bạn có thể tránh vấn đề này nếu bạn có thể di chuyển loại enum của mình sang không gian tên trực tiếp.


Chỉnh sửa (27 tháng 1 '12):

Nếu sử dụng cờ Enum, trình chuyển đổi sẽ như sau:

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

Chỉnh sửa (ngày 7 tháng 5 năm 15):

Trong trường hợp Enum Nullable ( không được hỏi trong câu hỏi, nhưng có thể cần thiết trong một số trường hợp, ví dụ ORM trả về null từ DB hoặc bất cứ khi nào có thể có nghĩa là trong logic chương trình, giá trị không được cung cấp), hãy nhớ thêm kiểm tra null ban đầu trong Phương thức chuyển đổi và trả về giá trị bool thích hợp, thường là sai (nếu bạn không muốn bất kỳ nút radio nào được chọn), như dưới đây:

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

Lưu ý - NullReferenceException (ngày 10 tháng 10 năm 18):

Đã cập nhật ví dụ để loại bỏ khả năng ném NullReferenceException. IsCheckedlà một loại nullable vì vậy trở lại Nullable<Boolean>có vẻ là một giải pháp hợp lý.


26
Tôi đồng ý, tôi tin rằng đây là một giải pháp tốt hơn. Ngoài ra, sử dụng chuyển đổi này sẽ khiến dự án bị phá vỡ tại thời gian biên dịch, không phải thời gian chạy, nếu các giá trị liệt kê được thay đổi, đó là một lợi thế lớn.
CrimsonX

4
Đây chắc chắn là một giải pháp tốt hơn nhiều so với giải pháp được chấp nhận. +1
OrPaz

7
Giải pháp tốt đẹp. Tôi sẽ thêm rằng đây thực sự chỉ là một công cụ chuyển đổi so sánh so sánh 2 giá trị. Nó có thể có một tên chung hơn EnumToBooleanConverter như so
sánhConverter

5
@ Scott, Rất đẹp. Bộ chuyển đổi này là tốt trong mọi trường hợp, có hoặc không có thuộc tính Flags. Nhưng trong hầu hết các trường hợp sẽ là ngớ ngẩn khi sử dụng bộ lọc này trực tiếp như bộ chuyển đổi với enum là cờ. Lý do là bạn nên đạt được boolean calc (| = hoặc ^ =) với giá trị trước đó để có kết quả phù hợp nhưng trình chuyển đổi không có quyền truy cập vào giá trị trước đó. Sau đó, bạn nên thêm một bool cho mỗi giá trị enum và tự thực hiện phép boolean calc thích hợp trong mô hình MVVM của bạn. Nhưng cảm ơn cho mọi thông tin, rất hữu ích.
Eric Ouellet

2
Trong Windows Phone 8 (Có thể trong trường hợp Ứng dụng Win Store), chúng tôi không có x: tĩnh, vì vậy chúng tôi không thể trực tiếp sử dụng giải pháp tại đây. Tuy nhiên, IDE / Comprang đủ thông minh và tìm kiếm chuỗi dựa trên tất cả các chuỗi ký tự (dù sao tôi cũng đoán vậy). ví dụ: công việc này <RadioButton IsChecked = "{Binding TrackMode, ConverterParameter = Driving, Converter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Bất kỳ lỗi chính tả nào trong Lái xe sẽ bị bắt trong thời gian thiết kế / biên dịch thay vì thời gian chạy.
Adarsha

26

Đối với câu trả lời EnumToBooleanConverter: Thay vì trả về DependencyProperty.UnsetValue xem xét trả lại Binding.DoNoth cho trường hợp nút radio Giá trị IsChecked trở thành sai. Cái trước chỉ ra một vấn đề (và có thể hiển thị cho người dùng một hình chữ nhật màu đỏ hoặc các chỉ số xác nhận tương tự) trong khi cái sau chỉ ra rằng không nên làm gì, đó là điều cần thiết trong trường hợp đó.

http://msdn.microsoft.com/en-us/l Library / system.windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/l Library / system.windows.data.binding .donoth.aspx


Không có Binding. Nhẹ nhàng trong Silverlight. Chỉ có WPF. Sử dụng null thay thế.
Alexander Vasilyev

1
Binding.Noth cũng đi từ UWP.
BlackICE

5

Tôi sẽ sử dụng RadioButtons trong ListBox và sau đó liên kết với ChọnValue.

Đây là một chủ đề cũ hơn về chủ đề này, nhưng ý tưởng cơ bản nên giống nhau: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/


Tôi nhận được một ràng buộc hai chiều thực hiện một phương thức tương tự bằng cách sử dụng ListBox và DataTemplate vì vậy bạn nên làm.
Bryan Anderson

Lỗi này: geekswithbloss.net/claraoscura/archive/2008/10/17/125901.aspx hủy hoại một ngày đối với tôi.
Slampen

3
Đây là giải pháp tốt nhất, mọi thứ khác đều gây ra mã thừa. ( Một ví dụ khác về việc sử dụng ListBox)
HB

3

Đối với UWP, nó không đơn giản như vậy: Bạn phải nhảy qua một vòng bổ sung để vượt qua một giá trị trường làm tham số.

ví dụ 1

Hợp lệ cho cả WPF và UWP.

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

Ví dụ 2

Hợp lệ cho cả WPF và UWP.

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

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

Ví dụ 3

Chỉ có giá trị cho WPF!

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

UWP không hỗ trợ x:Staticnên Ví dụ 3 không còn nữa; giả sử bạn đi với ví dụ 1 , kết quả là mã dài hơn. Ví dụ 2 tốt hơn một chút, nhưng vẫn không lý tưởng.

Giải pháp

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

Sau đó, đối với mỗi loại bạn muốn hỗ trợ, hãy xác định trình chuyển đổi chứa loại enum.

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

Lý do nó phải được đóng hộp là vì dường như không có cách nào để tham chiếu loại trong ConvertBackphương thức; quyền anh chăm sóc điều đó. Nếu bạn đi với một trong hai ví dụ đầu tiên, bạn chỉ có thể tham chiếu loại tham số, loại bỏ nhu cầu kế thừa từ một lớp được đóng hộp; nếu bạn muốn làm tất cả trong một dòng và với mức độ chi tiết thấp nhất có thể, thì giải pháp sau là lý tưởng.

Cách sử dụng giống như Ví dụ 2 , nhưng trên thực tế, ít dài dòng hơn.

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

Nhược điểm là bạn phải xác định một trình chuyển đổi cho từng loại bạn muốn hỗ trợ.


1

Tôi đã tạo một lớp mới để xử lý ràng buộc RadioButtons và CheckBoxes. Nó hoạt động cho các enum được gắn cờ (với nhiều lựa chọn hộp kiểm) và các enum không được gắn cờ cho các hộp kiểm chọn đơn hoặc các nút radio. Nó cũng không yêu cầu ValueConverters nào cả.

Điều này có thể trông phức tạp hơn lúc đầu, tuy nhiên, khi bạn sao chép lớp này vào dự án của mình, nó đã hoàn thành. Nó chung chung vì vậy nó có thể dễ dàng được sử dụng lại cho bất kỳ enum nào.

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

Và về cách sử dụng nó, giả sử bạn có một enum để chạy một tác vụ theo cách thủ công hoặc tự động, và có thể được lên lịch cho bất kỳ ngày nào trong tuần và một số tùy chọn tùy chọn ...

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
}

Bây giờ, đây là cách dễ dàng để sử dụng lớp này:

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

Và đây là cách dễ dàng để liên kết các hộp kiểm và nút radio với lớp này:

<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. Khi UI tải, nút radio "Thủ công" sẽ được chọn và bạn có thể thay đổi lựa chọn giữa "Thủ công" hoặc "Tự động" nhưng phải luôn chọn một trong số chúng.
  2. Mỗi ngày trong tuần sẽ được bỏ chọn, nhưng bất kỳ số nào trong số chúng có thể được kiểm tra hoặc bỏ chọn.
  3. "Tùy chọn A" và "Tùy chọn B" ban đầu sẽ không được chọn. Bạn có thể kiểm tra cái này hay cái kia, kiểm tra cái này sẽ bỏ chọn cái kia (tương tự RadioButtons), nhưng bây giờ bạn cũng có thể bỏ chọn cả hai (điều mà bạn không thể làm với RadioButton của WPF, đó là lý do CheckBox được sử dụng ở đây)

Giả sử bạn có 3 mục trong enum StartTask, chẳng hạn như {Không xác định, Thủ công, Tự động} Bạn muốn mặc định thành Không xác định vì cho đến khi người dùng đặt giá trị thì không xác định. Ngoài ra: Làm thế nào được chọnItem xử lý? ViewModel của bạn không có ChọnStartTask.
dùng1040323

Trong ViewModel của tôi, thuộc tính StartUp là một EnumSelection<StartTask>đối tượng. Nếu bạn nhìn vào định nghĩa của EnumSelection<T>bạn có thể thấy rằng nó có thuộc tính Giá trị. Vì vậy, mô hình khung nhìn không cần phải có "ChọnStartTask". Bạn sẽ sử dụng StartUp.Value. Và để có giá trị mặc định là Không xác định, hãy xem enum thứ 3, ExtraOptions, nó có Không thay vì Không xác định, nhưng bạn có thể thay đổi tên của nó thành bất cứ điều gì bạn muốn.
Nick

1

Điều này làm việc cho Checkbox quá.

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

Liên kết một enum với nhiều hộp kiểm.


1
Tôi nói một câu "CẢM ƠN" lớn cho bạn vì sự ưu ái mà bạn đã dành cho tôi. Nó làm việc như một cơ duyên đối với tôi.
Elham Azadfar

0

Dựa trên EnumToBooleanConverter từ Scott. Tôi nhận thấy rằng phương thức ConvertBack không hoạt động trên Enum với mã cờ.

Tôi đã thử đoạn mã sau:

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

Điều duy nhất mà tôi không thể có được để làm việc là để làm khuôn đúc ra khỏi intđến targetTypevì vậy tôi đã làm cho nó hardcoded NavigationProjectDates, enum mà tôi sử dụng. Và, targetType == NavigationProjectDates...


Chỉnh sửa cho trình chuyển đổi Flag Enum chung hơn:

    lớp công khai FlagsEnumToBooleanConverter: IValueConverter {
        int int _flags = 0;
        đối tượng công khai Chuyển đổi (giá trị đối tượng, Loại đích, tham số đối tượng, ngôn ngữ chuỗi) {
            if (value == null) trả về false;
            giá trị _flags = (int);
            Loại t = value.GetType ();
            đối tượng o = Enum.ToObject (t, tham số);
            giá trị trả về ((Enum)) .HasFlag ((Enum) o);
        }

        đối tượng công khai ConvertBack (giá trị đối tượng, Kiểu đích, tham số đối tượng, ngôn ngữ chuỗi)
        {
            if (value? .Equals (true) ?? false) {
                _flags = _flags | (int) tham số;
            }
            khác {
                Tham số _flags = _flags & ~ (int);
            }
            trả lại _flags;
        }
    }

Ai đó đã chỉnh sửa câu trả lời của tôi để thêm vào mã Flag, thật lòng mà nói, tôi chưa bao giờ thử / sử dụng nó và đã cân nhắc loại bỏ nó vì tôi nghĩ nó có ý nghĩa hơn như câu trả lời của chính nó. Nếu tôi có thể tìm thấy một thời gian sau, tôi có thể thử và kết hợp một cái gì đó để kiểm tra mã đó cũng như những gì bạn có và có thể giúp đưa ra giải pháp tốt hơn cho vấn đề của bạn.
Scott

0

Bạn có thể tạo các nút radio một cách linh hoạt, ListBoxcó thể giúp bạn làm điều đó, mà không cần bộ chuyển đổi, khá đơn giản.

Các bước đồng thời ở bên dưới: tạo ListBox và đặt ItemSource cho hộp danh sách làm enum MyLovelyEnumvà ràng buộc chọnItItem của ListBox vào thuộc VeryLovelyEnumtính. Sau đó, các nút Radio cho mỗi ListBoxItem sẽ được tạo.

  • Bước 1 : thêm enum vào tài nguyên tĩnh cho Window, UserControl hoặc Grid, v.v.
    <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>
  • Bước 2 : Sử dụng Hộp danh sách và Control Templateđể điền từng mục bên trong dưới dạng nút 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>

Các lợi thế là dưới đây: nếu một ngày nào đó bạn thay đổi lớp enum, bạn không cần phải cập nhật GUI (file XAML).

Tài liệu tham khảo: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.