我正在尝试将现有的Windows表单软件转换为MVVM/WPF。我是MVVM的新手,所以我会犯很多错误。
在那个应用程序中,这些是我简化的主要对象:
product类,该类保存了每个不同产品的信息。而且,可以有许多相同UPC的产品,但是每个物理项都有一个唯一的标识符,比如UPC-date-serial,所以这个唯一标识符保存在products中的一个列表中。
class Product
{
// This is the barcode of the product
public UPC
{ get; set; }
// This is a list which contains the unique ID of every product
public List<string> ProductSerialCodes
{ get; set; }
}这样,如果我们拥有相同UPC的10个产品,那么我们就有一个产品类的一个实例,其中包含ProductSerialCodes列表中的10个项。
然后,在容器类中,这个类是标识每一个填充了产品的物理盒。一个盒子可以包含不同的产品。
class Container
{
// The box Id
public string ContainerID
{ get; set; }
// The list of products in the box
public List<Product> ProductList
{ get; set; }
}这些类有更多的代码和自我验证的函数,所以我认为最好将它们设置为ViewModels。
ProductViewModel:
class ProductViewModel
{
List<string> _productSerialCodes = new List<string>();
public string UPC
{ get; set; }
public List<string> ProductSerialCodes
{ get { return _productSerialCodes; } }
public int ItemsCount
{ get { return _productSerialCodes.Count; } }
public AddItem(string itemID)
{
_productSerialCodes.Add(itemID);
OnPropertyChanged("ItemsCount");
}
}*注意: AddItem()方法是从后台线程调用的。
ContainerViewModel:
public class ContainerViewModel
{
private ObservableCollection<ProductViewModel> _productList;
public ObservableCollection<ProductViewModel> ProductList
{ get { return _productList; } }
public string ContainerID
{ get; set; }
public AddItem(string itemID)
{
// This comes from a background thread.
// I find the product related to the item,
// (If the product doesn't exist in the list I create it)
_productList.Find(product).AddItem(itemId);
}
}这就是我使用MVVM的方法,我的MainViewModel有一个ContainerViewModel,我想在屏幕上显示产品列表和数量,例如:
UPC Qty
000000000000 12由于数据来自后台线程,因此必须由INotifyPropertyChanged自动更新。
我注意到的另一件事是,我需要单击窗口中的某个地方,以便UI更新。在阅读了一些博客之后,我发现使用SynchronizationContext对象可以解决这个问题:
然后当OnPropertyChanged(propertyName)被调用时,我称之为
SynchronizationContext _syncContext;
_syncContext.Post(delegate { CommandManager.InvalidateRequerySuggested(); }, null);但是,只有当我在UI线程上进行测试时,这才能起作用。在我的新应用程序中,由于数据来自后台线程,所以SynchronizationContext为null,因此该解决方案无法工作。
我已经读过乔希·史密斯的“文章”和卡尔·希夫莱特的“材料”了。太棒了,顺便说一句。
因此,问题是:
-Is我的方法对吗?我愿意接受新的想法。
-How可以将ListBox或其他控件绑定到另一个ViewModel中的ViewModel中的属性吗?
-How我可以将OnPropertyChanged分配给UI线程,而无需单击窗口就可以应用更新吗?
--编辑
我的主要问题是显示数据。
如果我的MainViewModel看起来像这样:
public class MainViewModel
{
private ContainerViewModel _currentContainer = new ContainerViewModel();
public ContainerViewModel CurrentContainer
{ get { return _currentContainer; } }
// more code...
}然后,在视图中,要显示ProductList,我的xaml是:
<Window.DataContext>
<ViewModels:MainViewModel />
</Window.DataContext>
<ListBox Grid.Column="0" Margin="5"
ItemsSource="{Binding CurrentContainer.ProductList}">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="True">
<TextBlock Text="{Binding UPC}" />
<TextBlock Text="{Binding ItemsCount}" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>当我运行应用程序时,在后台,ViewModels将被填充。如果设置了断点,则可以在可观察的列表中看到项目。
但是屏幕上没有东西,ListBox仍然是空的。
耽误您时间,实在对不起。
致以问候。
发布于 2015-10-24 07:26:48
可以将ProductSerialCodes定义为ObservableCollection来绑定视图。
public ObservableCollection<string> ProductSerialCodes
{ get { return _productSerialCodes; } }另外,要更新ObservableCollection (因为它是在后台线程而不是主线程中更新的),您应该使用Dispatcher对象。
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
<<Your code>>
}));发布于 2015-10-24 13:47:02
-Is我的方法对吗?我愿意接受新的想法。
如果ProductList在运行时没有被修改,我认为最好将它声明为List,并将ProductSerialCodes声明为ObservableCollection。
-How可以将ListBox或其他控件绑定到另一个ViewModel中的ViewModel中的属性吗?
通常,父-子(子集合)类型的ViewModels与任何ItemsControl派生控件(如ListBox )都是完美的。您只需将ItemSource绑定到子项目,并为项目提供一个模板。子ViewModel将被限制在项的视图中。
-How我可以将OnPropertyChanged分配给UI线程,而无需单击窗口就可以应用更新吗?
我同意user1672994的意见,调度员可以做到。
https://stackoverflow.com/questions/33315555
复制相似问题