c# - 将模型中的异步更改通知 ViewModel

标签 c# wpf mvvm

我对 MVVM 比较陌生,我想知道构建我的应用程序的最佳方式。这是我的模型示例:

  public class ModelSource : ModelBase
  {
    #region Fields

    private int _isLoading;

    private BackgroundWorker worker = new BackgroundWorker();

    private ObservableCollection<PCDatabase> _databases;

    #endregion //Fields

    #region Properties

    public ObservableCollection<PCDatabase>Databases
    {
        get
        {
            if (_databases == null)
            {

                _databases = new ObservableCollection<PCDatabase>();
            }
            return _databases;
        }
        set
        {
            _databases = value;
            this.OnPropertyChanged("Databases");
        }
    }

    public int IsLoading
    {
        get
        {
            return _isLoading;
        }

        set
        {
            _isLoading = value;
            OnPropertyChanged("IsLoading");
        }
    }


    #endregion

    #region Methods

    /// <summary>
    /// Gets all Databases from the Server
    /// </summary>
    public void getDatabasesAsync(ConfigDatabaseConnection _currentConfig)
    {
      //execute SQL Query...
    }

(ModelBase 实现了 INotifyPropertyChanged)。

这是我对应的 ViewModel:

namespace DbRestore.ViewModel
{
public class ViewModelSource : ViewModelBase
{
    private ObservableCollection<PCDatabase> _databases;

    private ModelSource _modelSource;

    private ICommand _populateDatabaseCommand;

    public ConfigDatabaseConnection _currentConfig;

    public ViewModelSource()
    {
        this.ModelSource = new ModelSource();
    }

    #region Commands

    /// <summary>
    /// Command that opens a Database Connection Dialog 
    /// </summary>
    public ICommand OpenDataBaseConnectionCommand
    {
        get
        {
            if (_populateDatabaseCommand == null)
            {
                _populateDatabaseCommand = new RelayCommand(
                    param => this.PopulateDatabases()
                    );
            }
            return _populateDatabaseCommand;
        }
    }

    public ObservableCollection<PCDatabase> Databases
    {
        get
        {
            return _databases;
        }

        set
        {
            _databases = value;
            OnPropertyChanged("Databases");
        }
    }

    #endregion //Commands

    public void PopulateDatabases()
    {
        ModelSource.getDatabasesAsync(_currentConfig);
    } 

调用 ModelSource.getDatabasesAsync(_currentConfig) 在我的模型中获取我的 SQL 数据。由于我的一些 SQL 查询非常复杂,我实现了一个异步运行这些查询的后台工作程序。

如何将数据导入到绑定(bind)到我的 View 的 ViewModel 中?还是我的设计方法整体上有问题?

我考虑过并尝试过的事情:

  • 直接绑定(bind)到模型:可行,但有人告诉我这是一个
    不好的做法,应用程序逻辑应该驻留在模型中。

  • 将 SQL 查询移动到 ViewModel 中:同样有效,但随后是我的模型 类似乎是多余的 - 它只不过是一种自定义数据类型。

  • 同步运行查询并直接分配 Observable 我模型中的集合到我的 ViewModel 中的 Observable 集合。还 可以,但是我的 BackgroundWorker 遇到了问题, 因为 ViewModel 不知道查询何时真正完成。

最佳答案

  1. 将所有数据库逻辑移至服务(也称为存储库)类中。
  2. 可以直接绑定(bind)到模型属性,而不是为每个模型创建一打 ViewModel 代理类,只要您不需要围绕特定模型的任何特殊 View 相关逻辑。因此公开 PCDatabase 的集合是可以的。

由于您使用的是 BackgroundWorker,因此我假设您使用的是 .NET Framework 3.5 并且没有 TPL。

public interface IPCDatabaseRepository
{
    void GetPCDatabasesAsync(Action<IList<PCDatabase>> resultHandler);
}

public class PCDatabaseRepository : IPCDatabaseRepository
{
    public void GetPCDatabasesAsync(Action<IList<PCDatabase>> resultHandler)
    {
        var worker = new BackgroundWorker();

        worker.DoWork += (sender, args) =>
        {
            args.Result = // Execute SQL query...
        };  

        worker.RunWorkerCompleted += (sender, args) =>
        {
            resultHandler(args.Result as IList<PCDatabase>);
            worker.Dispose();
        };

        worker.RunWorkerAsync();
    }
}

public class ViewModelSource : ViewModelBase
{
    private readonly IPCDatabaseRepository _databaseRepository;
    private ObservableCollection<PCDatabase> _databases;
    private bool _isBusy;

    public ViewModelSource(IPCDatabaseRepository databaseRepository /*Dependency injection goes here*/)
    {
        _databaseRepository = databaseRepository;
        LoadDatabasesCommand = new RelayCommand(LoadDatabases, () => !IsBusy);
    }

    public ICommand LoadDatabasesCommand { get; private set; }

    public ObservableCollection<PCDatabase> Databases
    {
        get { return _databases; }
        set { _databases = value; OnPropertyChanged("Databases"); }
    }

    public bool IsBusy 
    { 
        get { return _isBusy; }
        set { _isBusy = value; OnPropertyChanged("IsBusy"); CommandManager.InvalidateRequerySuggested(); }
    }

    public void LoadDatabases()
    {
        IsBusy = true;

        _databaseRepository.GetPCDatabasesAsync(results =>
        {
            Databases = new ObservableCollection(results);
            IsBusy = false;
        });
    }

关于c# - 将模型中的异步更改通知 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35316999/

相关文章:

c# - 以 MVVM 模式更新记录以获得最大效率的正确方法

c# - 获取不为空的属性名称

wpf - 如何以编程方式在 WPF 中绘制箭头?

wpf 树状 View mvvm

WPF 动画仅触发一次

c# - Wpf UserControl 宽度和高度不 Taknig

mvvm - 尝试编辑时 WPF DataGrid 上动态列的两种方式绑定(bind)异常

c# - 将文件从 MemoryStream 附加到 C# 中的 MailMessage

c# - 如何使 WHERE 子句中的项目可选?

c# - 派生接口(interface)中的新方法声明