我有一个使用Telerik RadGridView控件和Caliburn.Micro MVVM框架实现的应用程序。由于一些性能问题,我需要实现Telerik VirtualQueryableCollectionView来代替正在使用的直接控制到ObservableCollection绑定。原始代码将RadGridView的ItemsSouce属性绑定到视图模型的Prices属性。我不得不在代码隐藏中消除这种绑定:
public PricingView(PricingViewModel vm)
{
InitializeComponent();
var dataView = new VirtualQueryableCollectionView()
{ LoadSize=20, VirtualItemCount = vm.Prices.Count };
dataView.ItemsLoading += (sender, e) =>
{
var view = sender as VirtualQueryableCollectionView;
if (dataView != null)
{
view.Load(e.StartIndex, vm.Prices.Skip(e.StartIndex).Take(e.ItemCount));
}
};
this.PricesGridView.ItemsSource = dataView;
}
由于此代码仅处理特定于UI的功能,并且特定于视图实现,因此我觉得此代码属于代码隐藏而不是ViewModel,因为它将偏离MVVM模式在ViewModel中引用VirtualQueryableCollectionView。我不满意的部分是将ViewModel的引用传递给View的构造函数。是否有一种很好的方法可以在代码隐藏中获取引用而无需在构造函数中传递引用?
或者有更好的方法来完成所有这些吗?
答案 0 :(得分:3)
我的应用程序是用MVVM Light实现的,在我的例子中,我使用了ViewModel中的VirtualQueryableCollectionView
类而不是View。
我这样做是因为我认为这个类与ObservableCollection
非常相似,尽管它不是核心类的一部分。
实际上,VirtualQueryableCollectionView
并不仅限于Telerik控件,还有许多其他标准控件,例如ListView
。
我的情况是在模型中实现了提取。
void MainViewModel()
{
this.Traces = new VirtualQueryableCollectionView<MyEntityClass>()
{
// ViewModel also manages the LoadSize
LoadSize = this.PageSize,
VirtualItemCount = myModel.TotalCount
};
this.Traces.ItemsLoading += (s, args) =>
{
this.Traces.Load(args.StartIndex,
myModel.FetchRange(args.StartIndex, args.ItemCount));
};
}
答案 1 :(得分:0)
不确定“性能问题”是什么意思,但我会假设这意味着当你从UI线程填充集合时,它会阻止应用程序足够长时间,它似乎没有响应。
有两种常见的解决方案。首先是简单地从后台线程填充您的集合。
天真的实现是简单地将加载推送到ThreadPool线程,然后使用Dispatcher编组调用以将项目添加到UI线程上的ObservableCollection。
一种更好的方法(完全不涉及ViewModel的方法)是使用asynchronous bindings.您可以将回退配置为某个值,该值指示您正在加载的用户。有时(根据具体情况),您可以使用PriorityBinding逐步填充用户界面。
其他替代方法是在显示splash screen时预先加载和缓存数据。它们在WPF中有点不同,它不像旧的“在我工作时显示这种形式,然后显示主要形式”winforms模式。当然,总有经典的数据分页。它很难编码,但有效。实际上,我应该说在UI中很难。它现在很容易用代码(database.Skip(pageNumber * pageSize).Take(pageSize)
)。