首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何让这个DataTemplateSelector工作?

如何让这个DataTemplateSelector工作?
EN

Stack Overflow用户
提问于 2013-03-12 23:41:49
回答 1查看 1.2K关注 0票数 1

在我的Viewmodel中,有类型为string的属性LoggedInAs和类型为bool的属性EditMode。我还有一个名为ReaderList的列表属性,我将其绑定到ItemsControl以用于显示,如下所示:

代码语言:javascript
复制
<ItemsControl Name="ReaderList" ItemTemplateSelector="{StaticResource drts}"/>

我使用Caliburn.Micro,所以绑定是通过命名自动完成的。我想使用DataTemplateSelector,因为如果应用程序是在EditMode中,而登录的人是我想要的是一个完全不同的显示。所以这是我的资源声明,

代码语言:javascript
复制
<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>

下面是类的代码:

代码语言:javascript
复制
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构造中的绑定表达式造成的-因为IsLoggedInEditMode不是DependencyProperties。

所以现在的问题是:如果我不能绑定到值,我怎么能有一个依赖于ViewModel状态的DataTemplateSelector呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-13 19:08:00

虽然您可以使用DataTemplateSelector或类似的工具,但如果您发现Caliburn.Micro中以View.ContextViewLocator的形式内置了此功能,您可能不会感到惊讶

在您的VM上,您可以创建一个提供上下文字符串的属性,CM将使用该字符串来解析视图-因为它使用命名约定,所以您只需要为子视图提供正确的命名空间/名称以及上下文字符串,以便找到替代视图

在您的VM中,您可以创建使用用户详细信息来确定其值的上下文属性:

代码语言:javascript
复制
public class SomeViewModel
{
    public string Context 
    {
        get 
        { 
            if (IsEditMode && _r.Name == IsLoggedInAs) return "Current";
            else return "Other";
        }
    }  

    // ... snip other code
}

我看到的唯一问题(可能有解决方法)是您想要从ViewModel内部确定视图-通常您确定更高级别的上下文并将其传递给ContentControl,CM在定位该VM的视图时使用它

例如:

您的主要虚拟机:

代码语言:javascript
复制
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
}

和关联的视图

代码语言:javascript
复制
<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>

则您的虚拟机命名结构将为:

代码语言:javascript
复制
- 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的接口

代码语言:javascript
复制
public interface IProvideContext
{
    string Context { get; }
}

然后,我定制了ViewLocator实现(您可以在Bootstrapper.Configure()中执行此操作),以便在没有指定上下文的情况下使用以下代码:

代码语言:javascript
复制
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上设置上下文-显然,这可能只适用于视图优先方法

因此,您所需要做的就是按照上面的说明构建视图(正确的名称空间等),然后根据IsLoggedInAsEditMode的值在VM上设置Context属性

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15365614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档