我正在构建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是轻量级的而且不包含任何逻辑。
在这种情况下,最佳解决方案是什么?如果您认为我的架构存在根本错误,请告诉我在这种情况下构建它的最佳方法。
我非常感谢您对此的建议!
答案 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);
}