나는 다음과 같은 열거 형을 가지고있다 :
public enum MyLovelyEnum
{
FirstSelection,
TheOtherSelection,
YetAnotherOne
};
내 DataContext에 속성이 있습니다.
public MyLovelyEnum VeryLovelyEnum { get; set; }
WPF 클라이언트에 3 개의 RadioButton이 있습니다.
<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>
이제 적절한 양방향 바인딩을 위해 RadioButton을 속성에 어떻게 바인딩합니까?
답변
좀 더 일반적인 변환기를 사용할 수 있습니다
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>
답변
허용 된 답변을 더 단순화 할 수 있습니다. 열거 형을 xaml에 문자열로 입력하고 필요한 것보다 변환기에서 더 많은 작업을 수행하는 대신 문자열 표현 대신 열거 형 값을 명시 적으로 전달할 수 있으며 CrimsonX가 언급 한대로 런타임이 아닌 컴파일 타임에 오류가 발생합니다.
ConverterParameter = {x : 정적 로컬 : 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;
}
}
편집 (12 월 16 일 10 일) :
DependencyProperty.UnsetValue 대신 Binding.DoNothing을 반환하도록 제안한 anon에게 감사드립니다.
참고-동일한 컨테이너에있는 여러 개의 RadioButton 그룹 (Feb 17 ’11) :
xaml에서 단일 선택 단추가 동일한 상위 컨테이너를 공유하는 경우 하나를 선택하면 다른 특성에 바인드되어 있어도 해당 컨테이너 내의 다른 모든 컨테이너가 선택 해제됩니다. 따라서 공통 속성에 바인딩 된 RadioButton을 스택 패널과 같은 자체 컨테이너에 그룹화하십시오. 관련 RadioButton이 단일 상위 컨테이너를 공유 할 수없는 경우 각 RadioButton의 GroupName 속성을 공통 값으로 설정하여 논리적으로 그룹화하십시오.
편집 (Apr 5 ’11) :
삼항 연산자를 사용하기 위해 단순화 된 ConvertBack의 if-else입니다.
참고-클래스에 중첩 된 열거 형 유형 (Apr 28 ’11) :
열거 형 유형이 네임 스페이스에 직접 포함되지 않고 클래스에 중첩 된 경우 ‘+’구문을 사용하여 XAML의 열거 형에 액세스하여 질문에 대한 (표시되지 않음) 답변에 나와있는 것처럼 답변 을 찾을 수 없습니다 WPF에서 정적 참조를위한 열거 형 :
ConverterParameter = {x : 정적 로컬 : YourClass + YourNestedEnumType.Enum1}
그러나이 Microsoft Connect 문제 로 인해 VS2010의 디자이너는 더 이상 상태를로드 "Type 'local:YourClass+YourNestedEnumType' was not found."
하지 않지만 프로젝트는 성공적으로 컴파일 및 실행됩니다. 물론 열거 형을 네임 스페이스로 직접 이동할 수 있다면이 문제를 피할 수 있습니다.
편집 (Jan 27 ’12) :
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;
}
}
편집 (5 월 7 일 ’15 일) :
(하는 null 허용 열거의 경우 하지 질문에 물었지만, 예를 들어, ORM DB에서 널 (null)을 반환하거나 때마다 프로그램 로직에 값이 제공되지 않는 것을 적합 할 수 있습니다, 경우에 따라 필요할 수 있습니다), 추가 기억 Convert 메서드에서 초기 null을 확인하고 적절한 부울 값을 반환합니다. 일반적으로 아래와 같이 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 (10 월 10 일 ’18) :
NullReferenceException 발생 가능성을 제거하도록 예제를 업데이트했습니다. IsChecked
nullable 형식이므로 반환 Nullable<Boolean>
하는 것이 합리적인 해결책 인 것 같습니다.
답변
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 .donothing.aspx
답변
ListBox에서 RadioButton을 사용한 다음 SelectedValue에 바인딩합니다.
이것은이 주제에 관한 오래된 글이지만, 기본 아이디어는 동일해야합니다 .
답변
UWP의 경우 그렇게 간단하지 않습니다. 필드 값을 매개 변수로 전달하려면 추가 후프를 뛰어 넘어야합니다.
실시 예 1
WPF 및 UWP 모두에 유효합니다.
<MyControl>
<MyControl.MyProperty>
<Binding Converter="{StaticResource EnumToBooleanConverter}" Path="AnotherProperty">
<Binding.ConverterParameter>
<MyLibrary:MyEnum>Field</MyLibrary:MyEnum>
</Binding.ConverterParameter>
</MyControl>
</MyControl.MyProperty>
</MyControl>
실시 예 2
WPF 및 UWP 모두에 유효합니다.
...
<MyLibrary:MyEnum x:Key="MyEnumField">Field</MyLibrary:MyEnum>
...
<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={StaticResource MyEnumField}}"/>
실시 예 3
WPF에만 유효합니다!
<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static MyLibrary:MyEnum.Field}}"/>
UWP는 지원하지 않습니다 x:Static
그래서 예 3은 밖으로 질문입니다; 예제 1을 사용 한다고 가정하면 결과는 더 자세한 코드입니다. 예제 2 가 약간 더 좋지만 여전히 이상적이지는 않습니다.
해결책
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);
}
}
그런 다음 지원하려는 각 유형에 대해 열거 형 유형을 상자 화하는 변환기를 정의하십시오.
public class MyEnumToBooleanConverter : EnumToBooleanConverter<MyEnum>
{
//Nothing to do!
}
박스에 넣어야하는 이유는 ConvertBack
메서드 에서 형식을 참조 할 방법이 없기 때문입니다 . 권투는 그것을 처리합니다. 처음 두 예제 중 하나를 사용하는 경우 매개 변수 유형을 참조하면 상자 클래스에서 상속 할 필요가 없습니다. 가능한 한 한 줄로 모든 것을하고 싶다면, 후자의 솔루션이 이상적입니다.
사용법은 예 2 와 비슷 하지만 실제로는 덜 장황합니다.
<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>
단점은 지원하려는 각 유형에 대한 변환기를 정의해야한다는 것입니다.
답변
RadioButtons 및 CheckBoxes를 열거 형에 바인딩하는 것을 처리하는 새 클래스를 만들었습니다. 단일 선택 확인란 또는 단일 선택 단추에 대해 플래그가 지정된 열거 형 (복수의 확인란 선택)과 비 플래그 형 열거 형에 작동합니다. 또한 ValueConverters가 전혀 필요하지 않습니다.
처음에는 더 복잡해 보일 수 있지만 일단이 클래스를 프로젝트에 복사하면 완료됩니다. 일반적이므로 모든 열거 형에 쉽게 재사용 할 수 있습니다.
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));
}
}
그리고 그것을 사용하는 방법에 대해 수동 또는 자동으로 작업을 실행하기위한 열거 형이 있고 요일 동안 예약 할 수 있고 몇 가지 선택적 옵션이 있다고 가정 해 봅시다.
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
}
이제이 클래스를 사용하는 것이 얼마나 쉬운 지 다음과 같습니다.
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; }
}
이 클래스를 사용하여 확인란과 라디오 버튼을 쉽게 바인딩 할 수 있습니다.
<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>
- UI가로드되면 “Manual”라디오 버튼이 선택되고 “Manual”또는 “Automatic”중에서 선택을 변경할 수 있지만 둘 중 하나를 항상 선택해야합니다.
- 요일마다 선택이 해제되지만 그 수는 선택하거나 해제 할 수 있습니다.
- “옵션 A”와 “옵션 B”는 모두 처음에 체크 해제되어 있습니다. 둘 중 하나를 검사하고, 하나를 검사하면 다른 하나를 선택 취소 할 수 있지만 (RadioButtons와 유사) 이제 둘 다 선택 해제 할 수 있습니다 (WPF의 RadioButton으로 수행 할 수 없으므로 CheckBox가 사용되는 이유).
답변
이것은 Checkbox 에서도 작동합니다 .
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());
}
}
단일 열거 형을 여러 확인란에 바인딩