在我的Viewmodel中,有类型为string的属性LoggedInAs和类型为bool的属性EditMode。我还有一个名为ReaderList的列表属性,我将其绑定到ItemsControl以用于显示,如下所示:
<ItemsControl Name="ReaderList" ItemTemplateSelector="{StaticResource drts}"/>我使用Caliburn.Micro,所以绑定是通过命名自动完成的。我想使用DataTemplateSelector,因为如果应用程序是在EditMode中,而登录的人是我想要的是一个完全不同的显示。所以这是我的资源声明,
<UserControl.Resources>
<DataTemplate x:Key="OtherPersonTemplate"> ... </DataTemplate>
<DataTemplate x:Key="CurrentUserIsPersonTemplate"> ... </DataTemplate>
<local:DisplayReaderTemplateSelector x:Key="drts"
IsLoggedInAs="{Binding LoggedInAs}"
IsEditMode="{Binding EditMode}"
CurrentUserTemplate="{StaticResource CurrentUserIsPersonTemplate}"
OtherUserTemplate="{StaticResource OtherPersonTemplate}"/>
</UserControl.Resources>下面是类的代码:
public class DisplayReaderTemplateSelector: DataTemplateSelector {
public DataTemplate CurrentUserTemplate { get; set; }
public DataTemplate OtherUserTemplate { get; set; }
public string IsLoggedInAs {get; set;}
public bool IsEditMode { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container){
var _r = item as Person;
if (IsEditMode && _r.Name == IsLoggedInAs) return CurrentUserTemplate;
else return OtherUserTemplate;
}
}由于某些原因,应用程序在实例化视图模型时崩溃。视图)。错误在哪里,和/或我如何替代地解决这个问题?
编辑:崩溃是由于DisplayReaderTemplateSelector构造中的绑定表达式造成的-因为IsLoggedIn和EditMode不是DependencyProperties。
所以现在的问题是:如果我不能绑定到值,我怎么能有一个依赖于ViewModel状态的DataTemplateSelector呢?
发布于 2013-03-13 19:08:00
虽然您可以使用DataTemplateSelector或类似的工具,但如果您发现Caliburn.Micro中以View.Context和ViewLocator的形式内置了此功能,您可能不会感到惊讶
在您的VM上,您可以创建一个提供上下文字符串的属性,CM将使用该字符串来解析视图-因为它使用命名约定,所以您只需要为子视图提供正确的命名空间/名称以及上下文字符串,以便找到替代视图
在您的VM中,您可以创建使用用户详细信息来确定其值的上下文属性:
即
public class SomeViewModel
{
public string Context
{
get
{
if (IsEditMode && _r.Name == IsLoggedInAs) return "Current";
else return "Other";
}
}
// ... snip other code
}我看到的唯一问题(可能有解决方法)是您想要从ViewModel内部确定视图-通常您确定更高级别的上下文并将其传递给ContentControl,CM在定位该VM的视图时使用它
例如:
您的主要虚拟机:
public class MainViewModel
{
public SomeSubViewModel { get; set; } // Obviously would be property changed notification and instantiation etc, I've just left it out for the example
}和关联的视图
<UserControl>
<!-- Show the default view for this view model -->
<ContentControl x:Name="SomeSubViewModel" />
<!-- Show an alternative view for this view model -->
<ContentControl x:Name="SomeSubViewModel" cal:View.Context="Alternative" />
</UserControl>则您的虚拟机命名结构将为:
- ViewModels
|
----- SomeSubViewModel.cs
|
- SomeSubView.xaml
|
- SomeSubView
|
----- Alternative.xaml并且CM应该知道在SomeSubView名称空间中查找基于原始VM名称和Context属性的名为Alternative的控件(SomeSubViewModel减去模型,再加上点,再加上Context,即SomeSubView.Alternative)
所以我必须有一个游戏,因为这是做它的标准方法。如果要这样做,您必须创建一个子视图模型并将ContentControl添加到视图中,并将View.Context属性绑定到VM上的Context属性,或者将Context属性添加到更高的位置(到父VM)。
我将研究一些替代方案--如果没有办法让当前的ViewModel根据使用标准CM的属性来决定其视图,您可以定制ViewLocator,或许还可以使用一个接口(IProvideContext或类似的接口),它可以立即为ViewLocator提供上下文-(我不认为您不能直接从VM挂接到视图解析过程中)。
我很快就会带着另一个答案或替代方案回来!
编辑:
好的,这似乎是最直接的方法。我刚刚创建了一个直接从VM提供Context的接口
public interface IProvideContext
{
string Context { get; }
}然后,我定制了ViewLocator实现(您可以在Bootstrapper.Configure()中执行此操作),以便在没有指定上下文的情况下使用以下代码:
ViewLocator.LocateForModel = (model, displayLocation, context) =>
{
var viewAware = model as IViewAware;
// Added these 3 lines - the rest is from CM source
// Try cast the model to IProvideContext
var provideContext = model as IProvideContext;
// Check if the cast succeeded, and if the context wasn't already set (by attached prop), if we're ok, set the context to the models context property
if (provideContext != null && context == null)
context = provideContext.Context;
if (viewAware != null)
{
var view = viewAware.GetView(context) as UIElement;
if (view != null)
{
#if !SILVERLIGHT && !WinRT
var windowCheck = view as Window;
if (windowCheck == null || (!windowCheck.IsLoaded && !(new WindowInteropHelper(windowCheck).Handle == IntPtr.Zero)))
{
LogManager.GetLog(typeof(ViewLocator)).Info("Using cached view for {0}.", model);
return view;
}
#else
LogManager.GetLog(typeof(ViewLocator)).Info("Using cached view for {0}.", model);
return view;
#endif
}
}
return ViewLocator.LocateForModelType(model.GetType(), displayLocation, context);
};这应该适用于您,并允许您直接在目标ViewModel上设置上下文-显然,这可能只适用于视图优先方法
因此,您所需要做的就是按照上面的说明构建视图(正确的名称空间等),然后根据IsLoggedInAs和EditMode的值在VM上设置Context属性
https://stackoverflow.com/questions/15365614
复制相似问题