目录
介绍
我坐在那里试图回忆起我多年来遇到的与WPF相关的编程问题,并且想起了其中一个涉及创建可观察的枚举器值集合的问题。这很早以前就发生在我身上,我无法找到解决问题的代码,但是我确实记得它特定于所涉及的枚举器,实际上是“坏事”(TM)。本文提供了一种可调试的通用方法,并且应该适用于您认为重要的任何枚举器。我不会假装这是解决问题的唯一或最佳方法,但我可以保证它会起作用,并且肯定是可行的(至少在我看来)。话虽这么说,但有两种针对此问题的全XAML解决方案(通过简单的Google搜索即可找到这些方法),
诚然,本文将很短,并且没有屏幕截图或随附的可下载文件,因为所有源代码都将在单个<pre>块中显示,并且可以轻松地复制/粘贴到您自己的项目中。
问题与解决方案
在WPF中,集合应该是可观察的,以便与UI良好协作,但是枚举器不利于这种方式。我的解决方案是编写一个扩展方法和一个独立的静态方法,将给定的枚举数表示为ObservableCollection。事不宜迟(忙乱、工作或延迟,与c# ADO框架相反),下面是代码:
using System;
using System.Collections.ObjectModel;
namespace ObjectExtensions
{
public class EnumItem
{
public object Value { get; set; }
public string Name { get; set; }
public Type EnumType { get; set; }
public Type UnderlyingType { get; set; }
}
public static class ExtendEnum
{
/// <summary>
/// Get a list of all items in the enumerator assiated with the one we called <br/>
/// this method with. Example: DayOfWeek.Monday.AsObservableEnum will return <br />
/// all items in the DayOfWeek enumerator.
/// </summary>
/// <param name="enumObj">An enumerator value, like DayOfWeek.Monday</param>
/// <returns>ObservableCollection of items in the parent enumerator</returns>
public static ObservableCollection<EnumItem> AsObservableEnum(this Enum enumObj)
{
// get our enumerator type, and call the plain static method
Type enumType = enumObj.GetType();
return AsObservableEnum(enumType);
}
/// <summary>
/// Get a list of all items in the specified enumarator type.
/// </summary>
/// <param name="enumType">The enumerator type</param>
/// <returns>ObservableCollection of items in the specified enumerator, or <br/>
/// null is no enumerator was specified</returns>
public static ObservableCollection<EnumItem>AsObservableEnum(Type enumType)
{
// set a predictable value
ObservableCollection<EnumItem> list = null;
// if the specified type is not nukll AND it is actually an enum type,
// we can create the collection
if (enumType != null && enumType.IsEnum)
{
// discover the underlying type (int, long, byte, etc)
Type underlyingType = Enum.GetUnderlyingType(enumType);
// create the list
list = new ObservableCollection<EnumItem>();
// get each enum item and add it to the list
foreach (Enum item in enumType.GetEnumValues())
{
list.Add(new EnumItem()
{
// the name that will probably be displayed in the UI component
Name = item.ToString(),
// the actual enum value (DayofWeek.Monday)
Value = item,
// the enum type
EnumType = enumType,
// the underlying type (int, long, byte, etc)
UnderlyingType = underlyingType
});
}
}
return list;
}
}
}
使用代码
在标准WPF应用程序中,用法是典型的。由于枚举数不会超出其实际定义而更改其内容,因此以某种方式将生成的可观察枚举集合创建为静态对象(包含在全局静态类中或作为单例对象,甚至是两者的组合)将是一个好主意。一次将其创建为静态对象意味着您将不必花费大量时间来重新分配对象,这将防止堆碎片化并最终节省CPU周期。但是,对于简单的测试,您可以在窗口的代码隐藏区中执行以下操作:
public class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<EnumItem> enums;
public ObservableCollection<EnumItem> Enums
{
get { return this.enums; }
set { if (value != this.enums) { this.enums = value; this.NotifyPropertyChanged(); } }
}
public MainWindow()
{
this.InitializeComponent();
this.DataContext = this;
this.Enums = DayOfWeek.Monday.AsObservableEnum();
// or
//this.Enums = ExtendEnum.AsObservableEnum(typeof(DayOfWeek));
}
}
在XAML中,您可能希望使用ListBox来允许选择所显示的枚举数:
<ListBox ItemsSource="{Binding Path=Enums}" Height="120" Width="120" DisplayMemberPath="Name"/>
一旦在用户界面中选择了枚举值,就可以出于任何目的完全访问父枚举类型。
兴趣点
我维护一个仅包含扩展方法的程序集,并且此技术已添加到其中。每个数据类型都有自己的文件,例如,我有称为ExtendXMLToLinq,ExtendString,ExtendIEnumerable等的类/文件。我建议,如果您做了大量的c#编码,那么您应该开始自己的编码。相信我,如果您现在开始这样做,您的编程生活将会更容易。
https://www.codeproject.com/Articles/5295461/WPF-Creating-Observable-Enumerators