Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
这段代码相当简单;它只是打开一个新窗口并设置新窗口的DataContext。我遇到的问题是,如果我执行两次,第一个实例的内容将被覆盖并设置为第二个实例的内容,因为adventurerWindowVM
是两个窗口的DataContext,每次都被覆盖代码被调用。我正在寻找一种方法来防止这种情况;我希望能够使用此消息打开多个窗口并使每个窗口都是唯一的,但到目前为止我还没有想出办法。任何建议将不胜感激。我为这个模糊的标题道歉;我不确定这个问题的名称。 (另外,我知道这不是一种方法。这个代码块会被调用什么?)
更新:我正在使用MVVM Light,而我的代码是基于某个人在此答案中为我提供的示例:https://stackoverflow.com/a/16994523/1667020
以下是我的ViewModelLocator.cs
中的一些代码public ViewModelLocator()
{
_main = new MainViewModel();
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<GameViewModel>();
SimpleIoc.Default.Register<AdventurerViewModel>();
}
答案 0 :(得分:8)
得到了另一个答案后,我想我可以说这里使用的IoC容器只是来自MvvmLight的SimpleIoC
并且要在每个GetInstance(...)
上获得一个新的VM实例,只需要做的就是每次尝试解析VM的实例时都会传入唯一的密钥。
所以你可以切换
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
到
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(System.Guid.NewGuid().ToString());
然而正如MVVMLight Here的作者所提到的,这些VM将被缓存,我们需要在不再需要时删除它们。在您的情况下,可能在Window
关闭时。
因此,我的整个lambda就像:
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var uniqueKey = System.Guid.NewGuid().ToString();
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(uniqueKey);
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
adventurerWindow.Show();
});
注意:强>
虽然这比使用( new AdventurerViewModel())自己创建一个新VM要长3行但我仍然喜欢这个,因为如果你使用IoC容器来管理VM的LifeTime,然后让它完全管理它们。不需要时,不要真的喜欢mix-n-match。而是让IoC Container保持其意图。
如果您需要更多地控制VM注入和生命周期管理,请查看更复杂的Ioc控制器,例如Unity。 SimpleIoC
只是想让你的脚在IoC类容器中“湿润”,并且在这方面做得非常好。
答案 1 :(得分:2)
我认为您尝试使用多个视图的 ViewModel 的实例。所以视图显然会覆盖彼此的viewmodel内容。
如果你这样做会怎么样;
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = new AdventurerViewModel();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
答案 2 :(得分:1)
这是一个方法调用,使用lambda表达式传入一个匿名方法。
看起来你从某种IoC容器中获取了AdventurerViewModel
。如何配置IoC容器?特别是,它给你回来的对象的范围是什么?例如,如果将IoC配置为在单例范围内创建对象,则每次都会返回对同一对象的引用。您可能需要在IoC容器中配置对象的范围,以便每次都为您提供新的副本。
如何操作取决于您的IoC容器。在不知道您正在使用哪个IoC框架或查看其配置的情况下,无法进行任何进一步的评论。
答案 3 :(得分:0)
我的建议是为 SimpleIOC 创建一个扩展方法。像这样:
public static T CreateInstance<T>(this SimpleIoc simpleIoc)
{
// TODO implement
}
您已经知道获取相同实例的方法;使用创建新实例的方法扩展 SimpleIoc:
T instance = SimpleIoc.Default.GetInstance<T>();
T createdInstance = SimpleIoc.Defalt.CreateInstance<T>();
如果您不熟悉扩展方法,请参阅Extension Methods Demystified
实现:
SimpleIoc.GetInstance
中使用的方法相同的方法,带有一个属性。更详细的方法:尝试找出是否可以找到与构造函数之一匹配的注册元素。此处不作解释。.
public static T CreateInstance<T>(this SimpleIoc ioc)
{
return (T)ioc.CreateInstance(typeof(T));
}
public static object CreateInstance(this SimpleIoc ioc, Type type)
{
ConstructorInfo constructor = ioc.GetConstructor(type);
IEnumerable<object> constructorParameterValues = ioc.GetParameters(constructor);
constructor.Invoke(constructorParameterValues.ToArray());
}
决定使用哪个构造函数:
private static ConstructorInfo GetConstructor(this SimpleIoc ioc, Type type)
{
ConstructorInfo[] constructors = type.GetConstructors();
ConstructorInfo constructorToUse;
if (constructorInfo.Length > 1)
{
// Decide which constructor to use; not explained here
// use Attribute like SimpleIoc.GetInstance?
// other method: use SimpleIoc.IsRegistered to check which Parameters
// are registered: use ConstructorInfo.GetParameters()
constructorToUse =
}
else
constructorToUse = constructoInfo[0];
return constructorToUse;
}
要在构造函数中获取参数的值,我们需要决定是从 Ioc 中获取现有值,还是创建新值:
public static IEnumerable<object> GetParameterValues(this simpleIoc ioc,
ConstructorInfo constructor)
{
IEnumerable<Type> parameterTypes = contructor.GetParameters()
.Select(parameter => parameter.ParameterType);
return ioc.GetInstances(parameterTypes);
}
public static IEnumerable<object> GetInstances(this SimpleIoc ioc,
IEnumerable<Type> types)
{
// TODO: decide if we want an existing instance from ioc,
// or a new one
// use existing instance:
return types.Select(type => ioc.GetInstance(type));
// or create a new instance:
return types.Select(type => ioc.CreateInstance(type));
}
这看起来像很多代码,但大部分都是注释,大多数方法都是一行代码。