在WPF中动态更新数据网格

时间:2016-10-26 06:31:29

标签: c# wpf xaml mvvm

我正在构建WPF应用程序,该应用程序从网站下载文章的链接并将其显示在网格中。

问题摘要:

我遇到的问题是我在模型中下载了逻辑,该逻辑无法访问ObservableCollection文章(在我的ViewModel中定义并绑定到DataGrid)。

当我下载新文章时,我应该如何访问此集合来更新它(以便数据网格将继续逐个添加新文章)?

详细信息:

以下是我的应用程序实现MVVM模式的概述(我剪切了一些不重要的部分以便于阅读):

DisplayWindow.xaml 是否将PresenterViewModel.cs和ItemSource的绑定源设置为ObservableCollection的文章(见下文)

<Grid DataContext="{Binding Source={StaticResource presenterViewModel}}">
        <DataGrid ItemsSource="{Binding Articles}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
...
            </DataGrid.Columns>
        </DataGrid>
</Grid>

它还有一个按钮,通过

触发文章链接的下载
        <Button Content="Download" Command="{Binding DownloadArticles, Mode=OneWay}"/>

DownloadArticles方法是PresenterViewModel的一部分,并返回实现接口ICommand的DownloadCommand实例。

PresenterViewModel.cs

contains ObservableCollection<Article> Articles

private ObservableCollection<Article> articles;

        public ObservableCollection<Article> Articles
        {
            get { return articles; }

            set
            {
                articles = value;
                RaisePropertyChangedEvent("Articles");
            }
        }
        public ICommand DownloadArticles
        {
            get
            {
                return downloadCommand;
            }
        }

DownloadCommand包含对PresenterViewModel的引用,在Execute方法中调用它的方法DownloadArticles,它在Article模型本身中调用DownloadArticles。

在DownloadCommand.cs中

        public void Execute(object parameter)
        {
            presenterViewModel.DownloadArticles();
        }

我正在考虑的解决方案:

现在,问题是我在Article.cs模型中的DownloadArticles方法,需要更新文章ObservableCollection,它是PresenterViewModel的一部分...... 我怎么做? DownloadArticles方法在单独的线程中运行下载逻辑。

我应该将对PresenterViewModel的引用传递给模型的DownloadArticles方法吗?

这似乎是一种简单的方法,但它感觉不对 - 我不认为模型应该耦合到ViewModel,在这种情况下,其中一个方法会接受PresenterViewModel对象。

另一种选择是直接在PresenterViewModel中下载逻辑,但这感觉不正确,因为我更喜欢我的ViewModel是轻量级的而且不包含任何逻辑。

在这种情况下,最佳解决方案是什么?如果您认为我的架构存在根本错误,请告诉我在这种情况下构建它的最佳方法。

我非常感谢您对此的建议!

1 个答案:

答案 0 :(得分:2)

  

现在,问题是我在Article.cs模型中的DownloadArticles方法   并且需要更新作为其一部分的文章ObservableCollection   PresenterViewModel ...我该怎么做?

您需要做的是将数据访问逻辑分离到另一个层,并将其作为依赖项注入ViewModel。通过这样做,您不会将任何数据访问逻辑耦合到ViewModel,因为它的任务应该只是将Model公开给View并响应用户输入。

假设您的模型看起来像这样:

public class Article : INotifyPropertyChanged
{
    private string _url;
    public string Url
    {
        get
        {
            return _url;
        }
        set
        {
            _url = value;
            PropertyChanged("Url");
        }
    }
}

所有数据访问逻辑都转到一个单独的层,我称之为DataService。它的工作是访问外部资源并下载文章:

public interface IDataService
{
    IList<Article> DownloadArticles();
}

public class DataService : IDataService
{
    public IList<Article> DownloadArticles()
    {
        var articles = new List<Article>();
        // you actually download articles here
        return articles;
    }
}

然后将数据访问层注入ViewModel

public class PresenterViewModel : BaseViewModel
{
    private readonly IDataService _dataService;

    public PresenterViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }
}

最后,当用户通过触发DownloadCommand请求下载文章时,您将此作业委托给您的服务并等待结果,然后该结果将显示在ViewModel的ObservableCollection<Article> Articles属性的View中:

// your DownlodArticles command's execute method
public void Execute(object parameter)
{
    var articles = _dataService.DownloadArticles();
    Articles = new ObservableCollection(articles);
}

如果由于某种原因您不想使用依赖注入,您可以将DataService实现为单例并从ViewModel中调用它:

public class DataService
{
    private static DataService _instance;
    public static DataService Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new DataService();
            }

            return _instance;
        }
    }

    public IList<Articles> DownloadArticles()
    {
        // ...
    }
}

public void Execute(object parameter)
{
    var articles = _DataService.Instance.DownloadArticles();
    Articles = new ObservableCollection(articles);
}

<强>更新

您的数据服务GetArticles方法:

public Task DownloadArticles(ICollection<Article> articles)
{
    // clear the collection if neccessary
    articles.Clear();

    return Task.Run(() =>
    {
        // load articles one by one and add them to the collection
    }
}

您的ViewModel命令执行方法:

private async void Execute(object parameter)
{
    await _dataService.LoadArticles(Articles);
}