我目前正在开展一个项目,为了简化说明,我们说TabControl中有两个标签...
在一个选项卡中,您将文件夹添加到ListBox。
在另一个标签中,有一个列表框,显示您添加的所有文件夹中的所有项目。
每个选项卡都是一个ViewModel(这是为了简化代码,因为在一个ViewModel中转储所有代码会使其难以阅读和理解)。
为了让这个程序工作,两个ViewModel都需要访问项目列表:一个是因为它必须显示它们,另一个因为它必须添加它们。
我无法弄清楚如何做到这一点。我最初认为共享数据很糟糕,这不应该首先发生,但后来我意识到我无法想到其他任何方式来做到这一点。
我是MVVM的新手(这是我使用MVVM的第一个真正的应用程序)并且最初开始使用它,因为我无法在类之间访问数据,并且认为MVVM会以某种方式排序这个问题,但在这里我又来了
如果有人能告诉我如何做到这一点,我会很感激,并可能通过示例代码解释它。我也愿意接受对我的方法的建议和建设性的批评。
答案 0 :(得分:3)
首先,您应该了解MVVM中的 View 是什么。把它看作一个小组。可以嵌入Window,TabControl甚至是ListBox项目的面板。一个也可以包含子面板的面板。基本上,如果您的应用程序不仅仅是一个简单的输入表单,那么它很可能会有多个 View 。不要试图将所有内容放在一个 View / ViewModel 中,因为这会使事情变得非常复杂。您希望拥有所谓的层次结构视图及其相应的 ViewModels 。会有很多 Views / ViewModels 但它们会相对简单且易于维护(这里是使用PRISM在视图之间切换的小例子,但你可以得到主要的想法https://youtu.be/ZfBy2nfykqY?t=45m34s)。
每个选项卡都是一个ViewModel(这是为了简化代码,因为在一个ViewModel中转储所有代码会使其难以阅读和理解)。
这是正确的方法。下面是一些伪代码,它描述了您的示例应用程序方案的外观:
// MODEL:
public class Model
{
ObservableCollection<Item> ListOfItems;
}
public class Item
{
}
// VIEWMODELS:
public class MainWindowViewModel
{
Model Model { get; set; }
Tab1ViewModel Tab1ViewModel { get; set; }
Tab2ViewModel Tab2ViewModel { get; set; }
public MainWindowViewModel()
{
Model = new Model();
Tab1ViewModel = new Tab1ViewModel(Model);
Tab2ViewModel = new Tab2ViewModel(Model);
}
}
public class Tab1ViewModel
{
ObservableCollection<ItemViewModel> ItemViewModels { get; set; } // Bind it to ListBox's ItemsSource
public Tab1ViewModel(Model m)
{
ItemViewModels = new ObservableCollection<ItemViewModel>();
// Populate ItemViewModels and keep it in sync with ListOfItems model by subscribing to its CollectionChanged event.
}
}
public class Tab2ViewModel
{
ObservableCollection<ItemViewModel> ItemViewModels { get; set; } // Bind it to ListBox's ItemsSource
public Tab2ViewModel(Model m)
{
ItemViewModels = new ObservableCollection<ItemViewModel>();
// Populate ItemViewModels and keep it in sync with ListOfItems model by subscribing to its CollectionChanged event.
}
}
public class ItemViewModel
{
Item Item { get; set; } // Model
public ItemViewModel(Item item)
{
Item = item;
}
}
现在,您可以在不同的 Views 中显示相同的数据,并对其执行不同的操作。每个 View 都会自动更新,因为它引用了相同的模型。
您也可以使用 EventAggregator 或类似内容在 ViewModels 之间进行通信。
尽量避免使用可从应用程序中的任何位置访问的数据的静态类/单例,因为这会破坏 Encapsulation 原则。
答案 1 :(得分:0)
您可以拥有单个对象并从任何地方获取/设置其属性。
看看这个例子;
public sealed class ApplicationState
{
private static readonly ApplicationState instance = new ApplicationState();
static ApplicationState()
{
}
private ApplicationState()
{
}
public static ApplicationState Instance
{
get
{
return instance;
}
}
public string SharedString {get;set;}
}
现在您可以从任何位置设置此SharedString属性;
ApplicationState.Instance.SharedString = "hello from VM1"
并从另一个视图模型中读取它;
Debug.WriteLine(ApplicationState.Instance.SharedString)
您可以查看this link以了解有关单身人士的更多信息
你甚至可以使你的ApplicationState单例成为ObservableObject并从你的视图绑定到它的属性,如;
Value="{Binding SharedString, Source={x:Static ApplicationState.Instance}}"
答案 2 :(得分:0)
因为在一个ViewModel中转储所有代码会使其难以阅读和理解。)
如果要在页面上使用一组主要数据,则该页面通常具有一个视图模型。除非每个选项卡都是可在其他地方使用的可重用单元,否则我不需要为每个标签页设置VM。
难以阅读和理解
我不同意,这就是用来提供使用逻辑的注释。
我的建议是将它带到一个虚拟机并解决这个问题。
两个ViewModel都需要访问项目列表:
您可以在程序的应用程序上放置静态属性,并将VM实例分配给这些静态。然后,每个VM都可以访问其他VM的数据。
在我需要访问虚拟机之前,我已经完成了类似操作,并且使用通用应用作为访问位置。
我是MVVM的新手
MVVM只是一个三层数据系统,用于将业务逻辑(VM)与实体(模型)从数据视图中分离出来。不要试图让MVVM成为教条。
答案 3 :(得分:0)
另一种方法是使用消息系统。例如,在PRISM中,您可以使用IEventAggregator
在应用程序中发送消息。我想IEventAggregator
可以作为独立的dll使用。
它非常强大且易于使用。您定义了一条消息,ViewModel可以添加项目,发送此消息的实例(以item作为参数)。带有列表的ViewModel可以捕获此消息并将该项添加到其列表中。
一个优点是两个ViewModel不必相互了解。
答案 4 :(得分:0)
使用单个父视图模型,该模型引用了您描述的两个子视图模型。我假设在用户正在选择的viewmodel中将视图绑定到ObservableCollection。
在您的父视图模型中,您可以在源视图模型中订阅ObservableCollection上的更改通知事件,然后在第二个视图模型上调用方法以填充更改。
使用ObservableCollection.CollectionChanged事件的示例:https://dotnetcodr.com/2015/05/29/getting-notified-when-collection-changes-with-observablecollection-in-c-net/
另一个选项,取决于您使用的MVVM框架是使用Messenging模式在断开连接的ViewModel之间传递消息 - Use MVVM Light's Messenger to Pass Values Between View Model
答案 5 :(得分:0)
只需使用mvvm库,如mvvm light,prism ...... 每个mvvm库都可以在视图模型之间进行构建,以便您可以使用它。 - 不要写新的。不要重新发明轮子。 - 不要在另一个viewmodel中使用参数viewmodel实例。如果你这样做会让你痛苦