ListBox 및 ComboBox에서 ItemSorce를 자동으로 생성하는 첨부 속성
18307 단어 UWP.NETWPF.NETFrameworkC#
개요
UWP나 WPF에서 열거형에서 하나의 값을 선택하기 위해 ComboBox나 ListBox를 사용하는 경우가 많습니다.
이 경우 ItemSource에 열거형 값 목록을 포함해야 합니다.
이전 기사에서는 열거형을 지정하는 것으로, 그 형태의 전치를 제공하는 MarkUpExtension를 XAML측에서 ItemSource에 사용하는 방법을 소개했습니다.
그러나 XAML 측에서 형식을 지정하기 때문에 그 내용을 동적으로 변경할 수 없습니다.
또, 많은 용도에 있어서, SelectedItem의 형태와 같기 때문에, 가능하면 SelectedItem에 자동으로 맞추어 주는 것이 좋다.
그래서 이번에는 첨부 속성을 사용하여 SelectedItem에 맞게 ItemSource를 자동 생성합니다.
실행 결과
두 개의 ListBox가 늘어서 있으며 한쪽을 선택하면 다른 한쪽에 전달됩니다.
또한 아래의 CheckBox를 클릭하면 ListBox의 후보 값이 전환됩니다.
보기
View는
(왼쪽) VM의 ItemSource
및 SelectedItem
에 같은 이름의 속성을 바인딩한 일반 ListBox
(오른쪽) 이번에 소개하는 첨부 프로퍼티를 VM의 SelectedItem
에만 바인드 한 ListBox
두 가지가 있습니다.
또한 그 아래의 CheckBox는 IsChecked
가 VM의 IsDayOfWeek
에 바인드되어 있습니다.
MainWindow.xaml<Window
x:Class="SelectorAttachedEnumProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectorAttachedEnumProperty"
Width="325" Height="250">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<UniformGrid Grid.Row="0" Rows="1">
<!-- 普通に書いたの -->
<ListBox ItemsSource="{Binding ItemSource}" SelectedItem="{Binding SelectedItem}" />
<!-- 添付プロパティで指定 -->
<ListBox local:AutoEnumSource.SelectedEnumItem="{Binding SelectedItem}" />
</UniformGrid>
<!-- Checkを変更するとItemSourceとSelectedItemが切り替わる -->
<CheckBox
Grid.Row="1"
Content="IsDayOfWeek"
IsChecked="{Binding IsDayOfWeek}" />
</Grid>
</Window>
ViewModel
ViewModel에서
· ItemSource
통상의 ListBox 로 사용하기 위한 열거치의 배열 프로퍼티
· SelectedItem
선택된 열거값 프로퍼티
· IsDayOfWeek
열거형의 전환 프로퍼티
변경 알림 속성으로 구현됩니다.
또 IsDayOfWeek
가 변경되었을 경우, ItemSource
와 SelectedItem
의 내용이 dayOfWeeks
⇔ dateTimeKinds
전치 배열간에 변경됩니다.
이 첨부 속성을 사용하면 ItemSource
와 원래의 두 배열( dayOfWeeks
, dateTimeKinds
)이 필요하지 않습니다.
그 경우의 전환 방법은 SelectedItem
에의 DayOfWeek 와 DateTimeKind 의 임의의 값의 입력입니다.
MainWindowViewModelpublic class MainWindowViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged実装
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private List<object> dayOfWeeks = typeof(DayOfWeek).GetEnumValues().Cast<object>().ToList();
private List<object> dateTimeKinds = typeof(DateTimeKind).GetEnumValues().Cast<object>().ToList();
//添付プロパティでItemSourceは不要になる
private List<object> _ItemSource;
public List<object> ItemSource
{
get => _ItemSource;
set
{
if (_ItemSource == value)
return;
_ItemSource = value;
NotifyPropertyChanged();
}
}
private object _SelectedItem;
public object SelectedItem
{
get => _SelectedItem;
set
{
if (_SelectedItem == value)
return;
_SelectedItem = value;
NotifyPropertyChanged();
}
}
private bool _IsDayOfWeek = false;
public bool IsDayOfWeek
{
get => _IsDayOfWeek;
set
{
if (_IsDayOfWeek == value)
return;
_IsDayOfWeek = value;
ItemSource = value ? dayOfWeeks : dateTimeKinds;
SelectedItem = value ? (object)DayOfWeek.Monday : DateTimeKind.Unspecified;
NotifyPropertyChanged();
}
}
public MainWindowViewModel()
{
IsDayOfWeek = true;
}
}
첨부 속성 구현
첨부 속성의 기본적인 설명 등은
WPF4.5 입문 그 45 「첨부 프로퍼티」 - 카즈키의 Blog@hatena
등을 참고하십시오.
이 첨부 속성의 작업은 값이 입력되면,
· ItemSource
에 그 값의 열거형의 전치 리스트를 설정한다
· SelectedItem
와 이 첨부 프로퍼티를 바인드 한다
의 2점입니다.
즉, UI의 변경은
View의 Selector의 SelectedItem → 첨부 속성의 SelectedEnumItem → VM의 SelectedItem
의 순서로 전해집니다.
반대로 VM의 변경은
VM의 SelectedItem → 첨부 속성 → View의 Selector의 SelectedItem
순서입니다.
추가로 변경된 값의 실행 유형이 다르면 첨부 속성을 변경할 때 View의 ItemSource가 변경됩니다.
AutoEnumSource.cspublic class AutoEnumSource
{
public static object GetSelectedEnumItem(Selector control) => (object)control.GetValue(SelectedEnumItemProperty);
public static void SetSelectedEnumItem(Selector control, object value) => control.SetValue(SelectedEnumItemProperty, value);
public static readonly DependencyProperty SelectedEnumItemProperty = DependencyProperty.RegisterAttached(
"SelectedEnumItem",
typeof(object), typeof(AutoEnumSource),
//デフォルトBindingモードをTwoWayにするために、FrameworkPropertyMetadataを使用
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnSelectedEnumItemChanged,
BindsTwoWayByDefault = true
});
private static void OnSelectedEnumItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//添付プロパティの変更値が有効でなかったら無効
Type newType = e.NewValue?.GetType();
if (newType == null || !newType.IsEnum)
{
return;
}
//添付されたコントロールがSelector以外では無効
var selector = d as Selector;
//変更値の型が変更前と同じなら何もしない
if (selector?.SelectedItem?.GetType() == newType)
{
return;
}
//添付されたSelectorのItemSourceに列挙型の全値を入力
selector.ItemsSource = Enum.GetValues(newType);
//SelectedItemに直接値を入力
selector.SelectedItem = e.NewValue;
//SelectorのSelctedItemにこの添付プロパティを双方向Bindingする
var binding = new Binding()
{
Path = new PropertyPath(AutoEnumSource.SelectedEnumItemProperty),
RelativeSource = RelativeSource.Self,
Mode = BindingMode.TwoWay
};
selector.SetBinding(Selector.SelectedItemProperty, binding);
}
}
환경
VisualStudio2017
.NET Framework 4.7
C#7.1
Reference
이 문제에 관하여(ListBox 및 ComboBox에서 ItemSorce를 자동으로 생성하는 첨부 속성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/soi/items/1b18e703d46a8ac85790
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
두 개의 ListBox가 늘어서 있으며 한쪽을 선택하면 다른 한쪽에 전달됩니다.
또한 아래의 CheckBox를 클릭하면 ListBox의 후보 값이 전환됩니다.
보기
View는
(왼쪽) VM의 ItemSource
및 SelectedItem
에 같은 이름의 속성을 바인딩한 일반 ListBox
(오른쪽) 이번에 소개하는 첨부 프로퍼티를 VM의 SelectedItem
에만 바인드 한 ListBox
두 가지가 있습니다.
또한 그 아래의 CheckBox는 IsChecked
가 VM의 IsDayOfWeek
에 바인드되어 있습니다.
MainWindow.xaml<Window
x:Class="SelectorAttachedEnumProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectorAttachedEnumProperty"
Width="325" Height="250">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<UniformGrid Grid.Row="0" Rows="1">
<!-- 普通に書いたの -->
<ListBox ItemsSource="{Binding ItemSource}" SelectedItem="{Binding SelectedItem}" />
<!-- 添付プロパティで指定 -->
<ListBox local:AutoEnumSource.SelectedEnumItem="{Binding SelectedItem}" />
</UniformGrid>
<!-- Checkを変更するとItemSourceとSelectedItemが切り替わる -->
<CheckBox
Grid.Row="1"
Content="IsDayOfWeek"
IsChecked="{Binding IsDayOfWeek}" />
</Grid>
</Window>
ViewModel
ViewModel에서
· ItemSource
통상의 ListBox 로 사용하기 위한 열거치의 배열 프로퍼티
· SelectedItem
선택된 열거값 프로퍼티
· IsDayOfWeek
열거형의 전환 프로퍼티
변경 알림 속성으로 구현됩니다.
또 IsDayOfWeek
가 변경되었을 경우, ItemSource
와 SelectedItem
의 내용이 dayOfWeeks
⇔ dateTimeKinds
전치 배열간에 변경됩니다.
이 첨부 속성을 사용하면 ItemSource
와 원래의 두 배열( dayOfWeeks
, dateTimeKinds
)이 필요하지 않습니다.
그 경우의 전환 방법은 SelectedItem
에의 DayOfWeek 와 DateTimeKind 의 임의의 값의 입력입니다.
MainWindowViewModelpublic class MainWindowViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged実装
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private List<object> dayOfWeeks = typeof(DayOfWeek).GetEnumValues().Cast<object>().ToList();
private List<object> dateTimeKinds = typeof(DateTimeKind).GetEnumValues().Cast<object>().ToList();
//添付プロパティでItemSourceは不要になる
private List<object> _ItemSource;
public List<object> ItemSource
{
get => _ItemSource;
set
{
if (_ItemSource == value)
return;
_ItemSource = value;
NotifyPropertyChanged();
}
}
private object _SelectedItem;
public object SelectedItem
{
get => _SelectedItem;
set
{
if (_SelectedItem == value)
return;
_SelectedItem = value;
NotifyPropertyChanged();
}
}
private bool _IsDayOfWeek = false;
public bool IsDayOfWeek
{
get => _IsDayOfWeek;
set
{
if (_IsDayOfWeek == value)
return;
_IsDayOfWeek = value;
ItemSource = value ? dayOfWeeks : dateTimeKinds;
SelectedItem = value ? (object)DayOfWeek.Monday : DateTimeKind.Unspecified;
NotifyPropertyChanged();
}
}
public MainWindowViewModel()
{
IsDayOfWeek = true;
}
}
첨부 속성 구현
첨부 속성의 기본적인 설명 등은
WPF4.5 입문 그 45 「첨부 프로퍼티」 - 카즈키의 Blog@hatena
등을 참고하십시오.
이 첨부 속성의 작업은 값이 입력되면,
· ItemSource
에 그 값의 열거형의 전치 리스트를 설정한다
· SelectedItem
와 이 첨부 프로퍼티를 바인드 한다
의 2점입니다.
즉, UI의 변경은
View의 Selector의 SelectedItem → 첨부 속성의 SelectedEnumItem → VM의 SelectedItem
의 순서로 전해집니다.
반대로 VM의 변경은
VM의 SelectedItem → 첨부 속성 → View의 Selector의 SelectedItem
순서입니다.
추가로 변경된 값의 실행 유형이 다르면 첨부 속성을 변경할 때 View의 ItemSource가 변경됩니다.
AutoEnumSource.cspublic class AutoEnumSource
{
public static object GetSelectedEnumItem(Selector control) => (object)control.GetValue(SelectedEnumItemProperty);
public static void SetSelectedEnumItem(Selector control, object value) => control.SetValue(SelectedEnumItemProperty, value);
public static readonly DependencyProperty SelectedEnumItemProperty = DependencyProperty.RegisterAttached(
"SelectedEnumItem",
typeof(object), typeof(AutoEnumSource),
//デフォルトBindingモードをTwoWayにするために、FrameworkPropertyMetadataを使用
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnSelectedEnumItemChanged,
BindsTwoWayByDefault = true
});
private static void OnSelectedEnumItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//添付プロパティの変更値が有効でなかったら無効
Type newType = e.NewValue?.GetType();
if (newType == null || !newType.IsEnum)
{
return;
}
//添付されたコントロールがSelector以外では無効
var selector = d as Selector;
//変更値の型が変更前と同じなら何もしない
if (selector?.SelectedItem?.GetType() == newType)
{
return;
}
//添付されたSelectorのItemSourceに列挙型の全値を入力
selector.ItemsSource = Enum.GetValues(newType);
//SelectedItemに直接値を入力
selector.SelectedItem = e.NewValue;
//SelectorのSelctedItemにこの添付プロパティを双方向Bindingする
var binding = new Binding()
{
Path = new PropertyPath(AutoEnumSource.SelectedEnumItemProperty),
RelativeSource = RelativeSource.Self,
Mode = BindingMode.TwoWay
};
selector.SetBinding(Selector.SelectedItemProperty, binding);
}
}
환경
VisualStudio2017
.NET Framework 4.7
C#7.1
Reference
이 문제에 관하여(ListBox 및 ComboBox에서 ItemSorce를 자동으로 생성하는 첨부 속성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/soi/items/1b18e703d46a8ac85790
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
<Window
x:Class="SelectorAttachedEnumProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectorAttachedEnumProperty"
Width="325" Height="250">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<UniformGrid Grid.Row="0" Rows="1">
<!-- 普通に書いたの -->
<ListBox ItemsSource="{Binding ItemSource}" SelectedItem="{Binding SelectedItem}" />
<!-- 添付プロパティで指定 -->
<ListBox local:AutoEnumSource.SelectedEnumItem="{Binding SelectedItem}" />
</UniformGrid>
<!-- Checkを変更するとItemSourceとSelectedItemが切り替わる -->
<CheckBox
Grid.Row="1"
Content="IsDayOfWeek"
IsChecked="{Binding IsDayOfWeek}" />
</Grid>
</Window>
ViewModel에서
·
ItemSource
통상의 ListBox 로 사용하기 위한 열거치의 배열 프로퍼티·
SelectedItem
선택된 열거값 프로퍼티·
IsDayOfWeek
열거형의 전환 프로퍼티변경 알림 속성으로 구현됩니다.
또
IsDayOfWeek
가 변경되었을 경우, ItemSource
와 SelectedItem
의 내용이 dayOfWeeks
⇔ dateTimeKinds
전치 배열간에 변경됩니다.이 첨부 속성을 사용하면
ItemSource
와 원래의 두 배열( dayOfWeeks
, dateTimeKinds
)이 필요하지 않습니다.그 경우의 전환 방법은
SelectedItem
에의 DayOfWeek 와 DateTimeKind 의 임의의 값의 입력입니다.MainWindowViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged実装
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private List<object> dayOfWeeks = typeof(DayOfWeek).GetEnumValues().Cast<object>().ToList();
private List<object> dateTimeKinds = typeof(DateTimeKind).GetEnumValues().Cast<object>().ToList();
//添付プロパティでItemSourceは不要になる
private List<object> _ItemSource;
public List<object> ItemSource
{
get => _ItemSource;
set
{
if (_ItemSource == value)
return;
_ItemSource = value;
NotifyPropertyChanged();
}
}
private object _SelectedItem;
public object SelectedItem
{
get => _SelectedItem;
set
{
if (_SelectedItem == value)
return;
_SelectedItem = value;
NotifyPropertyChanged();
}
}
private bool _IsDayOfWeek = false;
public bool IsDayOfWeek
{
get => _IsDayOfWeek;
set
{
if (_IsDayOfWeek == value)
return;
_IsDayOfWeek = value;
ItemSource = value ? dayOfWeeks : dateTimeKinds;
SelectedItem = value ? (object)DayOfWeek.Monday : DateTimeKind.Unspecified;
NotifyPropertyChanged();
}
}
public MainWindowViewModel()
{
IsDayOfWeek = true;
}
}
첨부 속성 구현
첨부 속성의 기본적인 설명 등은
WPF4.5 입문 그 45 「첨부 프로퍼티」 - 카즈키의 Blog@hatena
등을 참고하십시오.
이 첨부 속성의 작업은 값이 입력되면,
· ItemSource
에 그 값의 열거형의 전치 리스트를 설정한다
· SelectedItem
와 이 첨부 프로퍼티를 바인드 한다
의 2점입니다.
즉, UI의 변경은
View의 Selector의 SelectedItem → 첨부 속성의 SelectedEnumItem → VM의 SelectedItem
의 순서로 전해집니다.
반대로 VM의 변경은
VM의 SelectedItem → 첨부 속성 → View의 Selector의 SelectedItem
순서입니다.
추가로 변경된 값의 실행 유형이 다르면 첨부 속성을 변경할 때 View의 ItemSource가 변경됩니다.
AutoEnumSource.cspublic class AutoEnumSource
{
public static object GetSelectedEnumItem(Selector control) => (object)control.GetValue(SelectedEnumItemProperty);
public static void SetSelectedEnumItem(Selector control, object value) => control.SetValue(SelectedEnumItemProperty, value);
public static readonly DependencyProperty SelectedEnumItemProperty = DependencyProperty.RegisterAttached(
"SelectedEnumItem",
typeof(object), typeof(AutoEnumSource),
//デフォルトBindingモードをTwoWayにするために、FrameworkPropertyMetadataを使用
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnSelectedEnumItemChanged,
BindsTwoWayByDefault = true
});
private static void OnSelectedEnumItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//添付プロパティの変更値が有効でなかったら無効
Type newType = e.NewValue?.GetType();
if (newType == null || !newType.IsEnum)
{
return;
}
//添付されたコントロールがSelector以外では無効
var selector = d as Selector;
//変更値の型が変更前と同じなら何もしない
if (selector?.SelectedItem?.GetType() == newType)
{
return;
}
//添付されたSelectorのItemSourceに列挙型の全値を入力
selector.ItemsSource = Enum.GetValues(newType);
//SelectedItemに直接値を入力
selector.SelectedItem = e.NewValue;
//SelectorのSelctedItemにこの添付プロパティを双方向Bindingする
var binding = new Binding()
{
Path = new PropertyPath(AutoEnumSource.SelectedEnumItemProperty),
RelativeSource = RelativeSource.Self,
Mode = BindingMode.TwoWay
};
selector.SetBinding(Selector.SelectedItemProperty, binding);
}
}
환경
VisualStudio2017
.NET Framework 4.7
C#7.1
Reference
이 문제에 관하여(ListBox 및 ComboBox에서 ItemSorce를 자동으로 생성하는 첨부 속성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/soi/items/1b18e703d46a8ac85790
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
public class AutoEnumSource
{
public static object GetSelectedEnumItem(Selector control) => (object)control.GetValue(SelectedEnumItemProperty);
public static void SetSelectedEnumItem(Selector control, object value) => control.SetValue(SelectedEnumItemProperty, value);
public static readonly DependencyProperty SelectedEnumItemProperty = DependencyProperty.RegisterAttached(
"SelectedEnumItem",
typeof(object), typeof(AutoEnumSource),
//デフォルトBindingモードをTwoWayにするために、FrameworkPropertyMetadataを使用
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnSelectedEnumItemChanged,
BindsTwoWayByDefault = true
});
private static void OnSelectedEnumItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//添付プロパティの変更値が有効でなかったら無効
Type newType = e.NewValue?.GetType();
if (newType == null || !newType.IsEnum)
{
return;
}
//添付されたコントロールがSelector以外では無効
var selector = d as Selector;
//変更値の型が変更前と同じなら何もしない
if (selector?.SelectedItem?.GetType() == newType)
{
return;
}
//添付されたSelectorのItemSourceに列挙型の全値を入力
selector.ItemsSource = Enum.GetValues(newType);
//SelectedItemに直接値を入力
selector.SelectedItem = e.NewValue;
//SelectorのSelctedItemにこの添付プロパティを双方向Bindingする
var binding = new Binding()
{
Path = new PropertyPath(AutoEnumSource.SelectedEnumItemProperty),
RelativeSource = RelativeSource.Self,
Mode = BindingMode.TwoWay
};
selector.SetBinding(Selector.SelectedItemProperty, binding);
}
}
VisualStudio2017
.NET Framework 4.7
C#7.1
Reference
이 문제에 관하여(ListBox 및 ComboBox에서 ItemSorce를 자동으로 생성하는 첨부 속성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/soi/items/1b18e703d46a8ac85790텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)