如何基于变为动态的静态属性重新绑定源项

本文关键字:新绑定 绑定 属性 何基于 动态 静态 | 更新日期: 2023-09-27 18:35:52

在我的 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 }

我刚刚了解到,将来会有更多的种类。它们不会特别频繁地被创建,但不确定随着时间的推移它们会变成多少。因此,我将从数据库中读取这些元素,而不是向枚举添加新元素。

为了示例的简单性,假设每次访问属性时都会读取这些值。该解决方案成为在 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. 有没有更好的方法将炸弹框中的项目绑定到 DB 中的值?

如何基于变为动态的静态属性重新绑定源项

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

可以使用在后台线程上加载数据并使用 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
}

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

<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 提供程序提供给视图模型,然后将视图绑定到该模型。