我在mvvm
中遇到了中介模式的问题我会描述几乎所有课程,以便更好地理解我的问题。
我得到了MainWindow和ViewModel,它非常简单,只是拿着我的一个UserControls,但是在ViewModel中有一个绑定到MainWindow中的ContentControl.Content的UserControl属性。
UserControls相同,每个只有一个按钮, 另外还有两个带有处理clikcs命令的ViewModel。
Class Mediator是一个单例,我试图将它用于我的ViewModel之间的迭代
所以我要做的是在UserControls之间切换,而不是在MainWindowViewModel中创建它们和ViewModel。切换必须在我点击按钮后进行。例如,如果我单击FirstUserControl上的按钮,那么MainWindow的ContentControl应该切换到SecondUserControl。
问题出现在UserControlsViewModels中,我应该将UserControls对象作为Mediator NotifyCollegue()函数中的参数传递,但我无法访问它们 (当然,这是MVVM的原则之一),这就是用户类型的问题,因为标准类型应该不是问题(例如传递int或string ...)。
我在这里找到了这个解决方案 http://www.codeproject.com/Articles/35277/MVVM-Mediator-Pattern为什么我不能在MainWindowViewModel中切换UserControls,因为我希望MainWindow能够清除除绑定到ContentControl的当前UserControl之外的所有内容。
这个问题的可能解决方案是什么,我应该创建另一个单一类并收集所有userControls引用并在UserControlsViewModels中使用它们,或者其他什么东西?
我希望我已经清楚地描述了我的问题,并且有某种解决方案。
我很乐意回答任何问题,非常感谢帮助!!!
哦,这不是真正的应用程序,我只想获得ViewModel之间的消息系统的想法(概念),而不是混合ViewModel而不是在其他ViewModel中创建Views和他们的ViewModel ...再次感谢!
的MainView
<Window x:Class="TESTPROJECT.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TESTPROJECT"
mc:Ignorable="d"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="500" Width="750">
<Grid>
<ContentControl Grid.Row="1" Content="{Binding PagesControl}"/>
</Grid>
MainView ViewModel
namespace TESTPROJECT
{
class MainWindowViewModel : ViewModelBase
{
private UserControl _pagesControl;
public UserControl PagesControl
{
//Property that switches UserControls
set
{
_pagesControl = value;
OnPropertyChanged();
}
get
{
return _pagesControl;
}
}
public MainWindowViewModel()
{
//Method that will be listening all the changes from UserControls ViewModels
Mediator.Instance.Register(
(object obj) =>
{
PagesControl = obj as UserControl;
}, ViewModelMessages.UserWroteSomething);
}
}
}
FirstUserControl
<UserControl x:Class="TESTPROJECT.FirstUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TESTPROJECT"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Command="{Binding GetCommand}">
hello, i'm first user control!
</Button>
</Grid>
FirstUserControl ViewModel
namespace TESTPROJECT
{
class FirstUserControlViewModel : ViewModelBase
{
//command that is binded to button
private DelegateCommand getCommand;
public ICommand GetCommand
{
get
{
if (getCommand == null)
getCommand = new DelegateCommand(param => this.func(param), null);
return getCommand;
}
}
//method that will handle button click, and in it i'm sending a message
//to MainWindowViewModel throug Mediator class
//and that is allso a problem place because in theory i should
//pass the opposite UserControl object , but from here i have no
//acces to it
private void func(object obj)
{
Mediator.Instance.NotifyColleagues(
ViewModelMessages.UserWroteSomething,
"PROBLEM PLACE");
}
}
}
SecondUserControl
<UserControl x:Class="TESTPROJECT.SecondUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TESTPROJECT"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Command="{Binding GetCommand}">
Hello, i'm second user control!
</Button>
</Grid>
SecondUserControl ViewModel
namespace TESTPROJECT
{
class SecondUserControlViewModel : ViewModelBase
{
//command that is binded to button
private DelegateCommand getCommand;
public ICommand GetCommand
{
get
{
if (getCommand == null)
getCommand = new DelegateCommand(param => this.func(param), null);
return getCommand;
}
}
//method that will handle button click, and in it i'm sending a message
//to MainWindowViewModel throug Mediator class
//and that is allso a problem place because in theory i should
//pass the opposite UserControl object , but from here i have no
//acces to it
private void func(object obj)
{
Mediator.Instance.NotifyColleagues(
ViewModelMessages.UserWroteSomething,
"PROBLEM PLACE");
}
}
}
班级调解员 和 枚举ViewModelMessages
namespace TESTPROJECT
{
//this enum holding some kind of event names fro example UserWroteSomething
// is a name of switching one UserControl to another
public enum ViewModelMessages { UserWroteSomething = 1 };
class Mediator
{
//Singletone part
private static Mediator instance;
public static Mediator Instance
{
get
{
if (instance == null)
instance = new Mediator();
return instance;
}
}
private Mediator() { }
//Singletone part
//collection listeners that holds event names and handler functions
List<KeyValuePair<ViewModelMessages, Action<Object>>> internalList =
new List<KeyValuePair<ViewModelMessages, Action<Object>>>();
//new listener registration
public void Register(Action<object> callBack, ViewModelMessages message)
{
internalList.Add(
new KeyValuePair<ViewModelMessages, Action<Object>>(message, callBack));
}
// notifying all the listener about some changes
// and those whose names fits will react
public void NotifyColleagues(ViewModelMessages message, object args)
{
foreach(KeyValuePair<ViewModelMessages, Action<Object>> KwP in internalList)
if(KwP.Key == message)
KwP.Value(args);
}
}
}
App起点
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
FirstUserControl first = new FirstUserControl() { DataContext = new FirstUserControlViewModel() };
SecondUserControl second = new SecondUserControl() { DataContext = new SecondUserControlViewModel() };
new MainWindow()
{
DataContext = new MainWindowViewModel() { PagesControl = first }
}.ShowDialog();
}
}
答案 0 :(得分:2)
如果我理解正确,您希望在当前活动视图模型上发生某个操作时(例如,您按一个按钮)导航到另一个视图(或分别是视图模型)。
如果你想使用你的中介,你可以像这样构建它:
public class Mediator
{
// These fields should be set via Constructor Injection
private readonly MainWindowViewModel mainWindowViewModel;
private readonly Dictionary<ViewModelId, IViewFactory> viewFactories;
public void NotifyColleagues(ViewModelId targetViewModelId, ViewModelArguments arguments)
{
var targetFactory = this.viewModelFactories[targetViewModelId];
var view = targetFactory.Create(viewModelArguments);
this.mainWindowViewModel.PagesControl = view;
}
// other members omitted to keep the example small
}
然后,您将为每个视图创建一个工厂 - 视图模型组合。使用ViewModelArguments
,您可以将信息传递到源自其他视图模型的新创建的视图模型中。 ViewModelId可以是一个简单的枚举,就像您的ViewModelMessage一样,您也可以使用视图模型的Type
(我建议您继续使用)。
此外,我建议您不要在Mediator
类上使用私有构造函数,因为否则您无法传入mainWindowViewModel和视图工厂的字典。您应该能够在Application-Startup方法中配置它。
此外,请注意,还有许多其他方法可以构建MVVM应用程序,例如:使用数据模板来实例化视图模型的视图 - 但我认为这对你的小例子来说有点过于紧张。