我无辜地在我的应用程序(以及我的学习曲线)中找到了我需要通过ComboBox在GUI中设置实体属性的地方。具体来说,在Person
表单中,有一个Gender
字段,此字段应为ComboBox
,用户可在其中选择Male
,Female
和{ {1}}选项。
当然,这个ComboBox必须是TwoWay数据绑定到Unspecified
ViewModel的Gender
属性。
好吧,我首先想到“显然,我应该创建一个枚举,然后使用该枚举作为Person
属性和Gender
数据源的基石,如果我更改枚举本身,我甚至不需要更改ComboBox
类或XAML格式。
问题是:EVERY example实现我所描述的Person
应该简单的使用是非常扭曲的,使用辅助类,enum
s,{{1}等等。考虑到“应该是简单的”部分,这似乎很奇怪......
所以,问题是:
感谢阅读。
最终代码,在Sheridan的回答转换为字典而不是IEnumerable之后:
在ViewModel中,其中包含ValueConverter
属性,其中ObjectProvider
枚举位于可用的命名空间中:
SelectedPerson.Gender
在XAML中:
Gender
现在,这违反了我在问题中所说的内容,“如果枚举更改,则无需更改课程”,但如果您有显示名称和i18n,则无论如何都必须更改,因此您必须如果枚举改变,无论如何都要“更新东西”。但是枚举不应该经常改变。
当然,如果不需要显示名称,那么 // this won't be set, so only getter needed, I think
// Using dictionary as a placeholder for i18n implementation.
public Dictionary<Gender, String> Genders {
get { return new Dictionary<Gender,string> {
{Gender.Unspecified, "Não especificado"},
{Gender.Female, "Feminino"},
{Gender.Male, "Masculino"}
};
}
}
方式就可以了。
答案 0 :(得分:2)
将enum
实例用作WPF中任何集合控件中的项目是完全可以接受的。这是一个简单的例子来说明:
public enum Gender
{
Male, Female
}
private ObservableCollection<Gender> genders = new ObservableCollection<Gender>()
{ Gender.Male, Gender.Female };
public ObservableCollection<Gender> Genders
{
get { return genders; }
set { genders = value; NotifyPropertyChanged("Genders"); }
}
private Gender selectedGender = Gender.Female;
public Gender SelectedGender
{
get { return selectedGender; }
set { selectedGender = value; NotifyPropertyChanged("SelectedGender"); }
}
<ComboBox ItemsSource="{Binding Genders}" SelectedItem="{Binding SelectedGender}" />
此处,SelectedGender
属性可以在调用时替换为“实体”中的属性。这样,设置ComboBox
选项将更新您实体的该属性。
更新&gt;&gt;&gt;
对不起,我一定忽略了那个微小的细节......你可以使用Enum.GetValues
方法来迭代枚举值:
Array values = Enum.GetValues(typeof(Gender));
Genders = new ObservableCollection<Gender>(values.OfType<Gender>());
关于绑定到您的视图模型的SelectedItem
属性,我 说 SelectedGender
属性可以替换为您的'实体'中的属性。具体如何完成将取决于您如何设置数据类型和查看模型类,但我想象它会是这样的:
在您的视图模型中:
private ObservableCollection<Gender> genders = new ObservableCollection<Gender>();
public ObservableCollection<Gender> Genders
{
get { return genders; }
set { genders = value; NotifyPropertyChanged("Genders"); }
}
private YourDataObjectType yourDataObject = new YourDataObjectType();
public YourDataObjectType YourDataObject
{
get { return yourDataObject; }
set { yourDataObject = value; NotifyPropertyChanged("YourDataObject"); }
}
然后在XAML中:
<ComboBox ItemsSource="{Binding Genders}"
SelectedItem="{Binding YourDataObject.YourGenderProperty}" />
答案 1 :(得分:1)
大多数情况下,当我在wpf中使用组合框时,将字典作为itemssource,其中字典条目的值部分是我显示的用户友好文本(DisplayMember),键值绑定到我的viewmodel。
答案 2 :(得分:0)
[虽然它已经回答了,但我希望展示'XAML友好'的方式]
在数据上下文中使用集合会导致需要选择相同enum
值的每个视图模型的复制代码,即,如果您有多个视图模型,其中包含要编辑的Person
对象 - 每个视图模型都需要定义,初始化和填充集合。或者,或者,需要更改继承拓扑。
我们定义Gender
和Person
:
public enum Gender
{
Female,
Male,
Unspecified
}
public class Person : INotifyPropertyChanged
{
private Gender _gender = Gender.Unspecified;
public Gender Gender
{
get { return _gender; }
set
{
if (value == _gender) return;
_gender = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
我在MainWindow
中定义了person的属性以避免此示例的MVVM开销,但如果有一个持有Person
属性的视图模型,它将非常相似(仅限) DockPanel
不会在xaml文件中设置数据上下文)
public partial class MainWindow
{
#region ActivePerson
/// <summary>
/// Gets or sets an instance of <see cref="Person"/> object to use for testing.
/// </summary>
public Person ActivePerson
{
get { return (Person) GetValue(ActivePersonProperty); }
set { SetValue(ActivePersonProperty, value); }
}
/// <summary>
/// Identifies the <see cref="ActivePerson"/> property.
/// </summary>
public static readonly DependencyProperty ActivePersonProperty =
DependencyProperty.Register("ActivePerson", typeof (Person), typeof (MainWindow), new UIPropertyMetadata(null));
#endregion
public MainWindow()
{
ActivePerson = new Person();
InitializeComponent();
}
}
由于Enum
不是组合框所期望的IEnumerable
ItemsSource
,我们需要一些可以Enum
并枚举所有可用值的内容。这是通过声明为资源的ObjectDataProvider
完成的 - 在本例中是在App.xaml中,但可以是任何加载的资源字典的一部分,这样组合就可以到达其范围(当然,{{1} }或Window.Resources
是有效选项)
UserControl.Resorces
现在<Application x:Class="EnimObjectProvider.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:enumObjectProvider="clr-namespace:EnumObjectProvider"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ObjectDataProvider x:Key="Genders"
ObjectType="{x:Type system:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<system:Type>enumObjectProvider:Gender</system:Type>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Application.Resources>
</Application>
中的使用很简单:
MainWindow
这样我们只针对每个应用程序声明<Window x:Class="EnimObjectProvider.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525">
<DockPanel DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
Margin="20">
<ComboBox DockPanel.Dock="Top"
ItemsSource="{Binding Source={StaticResource Genders}}"
SelectedItem="{Binding ActivePerson.Gender}" />
<!--This text block is for testing of the Gender property of ActivePerson-->
<TextBlock Text="{Binding ActivePerson.Gender, StringFormat='Current gender is: {0}'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DockPanel>
</Window>
一次,并且我们想要使用组合,列表框或任何项目控件来列出此枚举的可用值,我们可以对{具有相同的绑定{1}}属性。