如何根据变为动态的静态 属性 重新绑定 SourceItems?

How to rebind SourceItems based on a static property that becomes dynamic?

在我的 XAML 代码中,我有一个绑定到静态 属性 的组合框,如下所示。

<ComboBox x:Name="DifferentKinds" 
          ItemsSource="{x:Static local:MainWindow.DifferentKinds}"/>

以及 属性 的代码及其来源。

public static Kind[] DifferentKinds 
  => (Kind[])Enum.GetValues(typeof(Kind));

public enum Kind { WeeHee, BuuHuu }

刚知道以后还会有更多种类。它们不会特别频繁地创建,但不确定随着时间的推移它们会变成多少。因此,我不会向 enum 添加新元素,而是从数据库中读取这些元素。

为了示例的简单性,假设我们每次访问 属性 时都读入这些值。该解决方案成为一个私有字段,在 开始执行 InitializeComponent() 之前从数据库中读取。然后,我仍然将这些值作为静态 属性 提供,就像这样。

public MainWindow()
{
  PopulateDifferentKinds();
  InitializeComponent();
}

private static IEnumerable<Kind> _allDifferentKinds;
public static IEnumerable<Kind> AllDifferentKinds 
  => _allDifferentKinds.Where(element => element.Active);

public class Kind
{
  public String Name { get; set; }
  public bool Active { get; set; }

  public override string ToString() { return Name; }
}
  1. 这种方法是否会造成我想念的大问题?
  2. 有没有更好的方法将炸弹框中的项目绑定到数据库中的值?

我在这里看到的主要问题是在视图的构造函数中调用 PopulateDifferentKinds 方法会产生性能问题。虽然此方法是 运行 并且正在查询数据库,但您的 UI 正在被阻止。

这可以通过使用 class 在后台线程上加载数据并使用 PropertyChanged 事件来表示数据已加载来改进:

public class Kind
{
    public string Name { get; set; }
    public bool Active { get; set; }
    public int Value { get; set; }
}

public class AppEnumValues : INotifyPropertyChanged
{
    private static readonly Lazy<AppEnumValues> current
        = new Lazy<AppEnumValues>(() => new AppEnumValues(), LazyThreadSafetyMode.ExecutionAndPublication);

    public static AppEnumValues Current
    {
        get { return current.Value; }
    }

    public Kind[] AllDifferentKinds { get; private set; }

    public bool IsLoaded { get; private set; }

    private AppEnumValues()
    {
        Task.Run(() => this.LoadEnumValuesFromDb())
            .ContinueWith(t => this.OnAllPropertiesChanged());
    }

    protected virtual void OnAllPropertiesChanged()
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(string.Empty));
        }
    }

    private void LoadEnumValuesFromDb()
    {
        // This simulates some latency
        Thread.Sleep(2000);

        // Call your data service here and load the values

        var kinds = new[]
                    {
                        new Kind {Active = true, Name = "WeeHee", Value = 1},
                        new Kind {Active = true, Name = "BuuHuu", Value = 2}
                    };

        this.AllDifferentKinds = kinds;

        this.IsLoaded = true;
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

您可以使用应用程序中需要的每个可扩展 "enum" 的属性来扩展它。实现单例模式,这将在第一次使用时在后台加载其数据。您可以像这样绑定组合框:

<ComboBox ItemsSource="{Binding Source={x:Static wpfApplication2:AppEnumValues.Current},Path=AllDifferentKinds}"
            IsEnabled="{Binding Source={x:Static wpfApplication2:AppEnumValues.Current},Path=IsLoaded}"
            DisplayMemberPath="Name" />

加载数据时,组合框将被禁用。

我建议研究 MVVM 和依赖注入。这将增强您的 WPF 应用程序体系结构并使事情变得简单:您不会提供静态 属性 或单例,它们的可测试性和可扩展性很差,但您可以使用构造函数注入将 AppEnumValues 提供程序提供给您的视图建模然后将您的视图绑定到它。