MVVM ViewModel inside ViewModel

本文关键字:ViewModel inside MVVM | 更新日期: 2023-09-27 18:18:59

我正试图将现有的Windows窗体软件转换为MVVM/WPF。我是MVVM的新手,所以我可能会犯很多错误。

在这个应用程序中,这些是我的主要对象的简化:

Product类,该类保存UPC中每个不同产品的信息。同样,可以有许多相同UPC的产品,但是每个物理项目都有一个唯一标识符,比如UPC-date-serial,所以这个唯一标识符保存在Product类中的列表中。

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个产品,我们就有一个Product类的实例,在productserialdes列表中有10个产品。

然后,Container类,这个类是用来标识每一个装满产品的物理盒子。一个盒子可以装不同的产品。

class Container
{
    // The box Id
    public string ContainerID
    { get; set; }
    // The list of products in the box
    public List<Product> ProductList
    { get; set; } 
}

这些类有更多的代码,和自我验证的函数,所以我认为最好让他们viewmodel。

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,因此,此解决方案不起作用。

我已经读了Josh Smith的文章和karl shifflett的Stuff。顺便说一句,这些都很棒。

那么,问题是:

-我的方法正确吗?我愿意接受新想法。

-我如何绑定一个ListBox,或其他控件在另一个ViewModel内的ViewModel属性?

-我怎么能马歇尔OnPropertyChanged到UI线程,更新应用而不需要点击窗口?

——编辑

我的主要问题是显示数据。

如果我的MainViewModel看起来像这样:

public class MainViewModel
{
    private ContainerViewModel _currentContainer = new ContainerViewModel();
    public ContainerViewModel CurrentContainer
    { get { return _currentContainer; } }
    // more code...
}

然后在View中,为了显示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仍然是空的

感谢您的宝贵时间。

问候。

MVVM ViewModel inside ViewModel

可以将ProductSerialCodes定义为ObservableCollection来绑定View。

public ObservableCollection<string> ProductSerialCodes
    { get { return _productSerialCodes; } }

同样,要更新ObservableCollection(因为它是在后台线程而不是主线程中更新的),你应该使用Dispatcher对象。

Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
            {
              <<Your code>>
            }));

-我的方法正确吗?我愿意接受新想法。

如果ProductList在运行时没有被修改,我认为如果你声明它为List并使productserialdes为ObservableCollection会更好。

-我如何绑定一个ListBox,或其他控件在另一个ViewModel内的ViewModel属性?

通常,viewmodel的父-子(子作为集合)类型对于任何ItemsControl派生控件(如ListBox)都是完美的。您只需要将ItemSource绑定到子项,并为这些项创建一个Template。子ViewModel将被绑定到Item的视图。

-我怎么能马歇尔OnPropertyChanged到UI线程,更新应用而不需要点击窗口?

我同意user1672994, Dispatcher可以做到