【问题标题】:DataTemplate for MVVM: where does it go?MVVM 的 DataTemplate:它去哪儿了?
【发布时间】:2013-01-07 02:35:08
【问题描述】:

我正在开发一个“现代 UI”应用程序,所以语法对我来说有点新,我似乎无法让我的绑定正常工作。

我的愿望是首先设计一个 ViewModel,这样我就可以在我的应用页面上做一些事情,比如有一个 ListView 并添加一个 UserViewModel 作为一个孩子,并自动找到 DataTemplate 来创建一个 UserView并绑定到提供的 UserViewModel。

我为另一个为 Win 7 桌面编写的应用程序做了类似的事情,它只是工作,但对于我的生活,我无法弄清楚为什么它在这里不起作用。我只是将我的 ListView“UserViewModel”作为文本输入(没有创建 UserControl)。

这里唯一的另一个区别是这是我第一次使用异步函数,因为它几乎是强制你进行 Win 8 开发的,这就是我从 WCF 服务获得的方法,我正在提取我的数据来自。

这是我的视图模型的示例:

 public class UserViewModel
{
    private UserDTO _user { get; set; }

    public UserViewModel(UserDTO user)
    {
        _user = user;
    }

    public UserViewModel(int userId)
    {
        SetUser(userId);
    }

    private async void SetUser(int userId)
    {
        ServiceClient proxy = new ServiceClient();
        UserDTO referencedUser = await proxy.GetUserAsync(userId);
    }

    public string FirstName
    {
        get
        {
            return _user.FirstName;
        }
    }

    public string LastName
    {
        get
        {
            return _user.LastName;
        }
    }

    public string Email
    {
        get
        {
            return _user.email;
        }
    }
}

该视图应该是所有 XAML 并在应用程序资源中粘合在一起,如下所示:

<UserControl x:Class="TaskClient.Views.UserView" ...
    xmlns:root="using:TaskClient"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="30"
    d:DesignWidth="200">
    <StackPanel Orientation="Horizontal" Margin="5, 0, 0 ,0" DataContext="{Binding}">
        <TextBlock x:Name="FirstNameLabel" Text="{Binding FirstName}"/>
        <TextBlock x:Name="LastNameLabel" Text="{Binding LastName}"/>
        <TextBlock x:Name="EmailLabel" Text="{Binding Email}"/>
    </StackPanel>
</UserControl>

和:

<Application x:Class="TaskClient.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TaskClient"
xmlns:localData="using:TaskClient.Data" 
xmlns:vm="using:ViewModels"
xmlns:vw="using:TaskClient.Views">

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>

            <!-- 
                Styles that define common aspects of the platform look and feel
                Required by Visual Studio project and item templates
             -->
            <ResourceDictionary Source="Common/StandardStyles.xaml"/>
        </ResourceDictionary.MergedDictionaries>

        <!-- Application-specific resources -->

        <x:String x:Key="AppName">TaskClient</x:String>

        <DataTemplate x:Key="vm:UserViewModel">
            <vw:UserView />
        </DataTemplate>
    </ResourceDictionary>
</Application.Resources>

我已经尝试通过各种示例(例如http://joshsmithonwpf.wordpress.com/a-guided-tour-of-wpf/)搜索一个小时左右,但无法找到适合我的示例。

知道我做错了什么吗?

【问题讨论】:

    标签: c# xaml mvvm windows-8


    【解决方案1】:

    可能是错字,但当您通过 WCF 服务获取用户时,您似乎没有更新“_user”字段。你可能需要改变这个:

    private async void SetUser(int userId)
    {
        ServiceClient proxy = new ServiceClient();
        UserDTO referencedUser = await proxy.GetUserAsync(userId);
    }
    

    到这里:

    private async void SetUser(int userId)
    {
        ServiceClient proxy = new ServiceClient();
        _user = await proxy.GetUserAsync(userId);
    }
    

    我也没有看到您的 ViewModel 类实现了 INotifyPropertyChange 接口,这是 WPF 数据绑定的关键。完成此操作并加载用户后,您需要通知 WPF 属性正在更新:

    private async void SetUser(int userId)
    {
        ServiceClient proxy = new ServiceClient();
        _user = await proxy.GetUserAsync(userId);
        NotifyOfPropertyChange();
    }
    
    private void NotifyOfPropertyChange() 
    {
        NotifyChanged("FirstName"); //This would raise PropertyChanged event.
        NotifyChanged("LastName");
        NotifyChanged("Email");
    }
    

    【讨论】:

      【解决方案2】:

      我只是以文本形式进入我的 ListView“UserViewModel”(未创建 UserControl)

      您的DataTemplate 需要使用DataType 属性定义,并且没有x:Key 属性,以便隐式应用DataTemplate

      <DataTemplate DataType="{x:Type vm:UserViewModel}">
          <vw:UserView />
      </DataTemplate>
      

      指定了DataType 但没有x:Key 的DataTemplate 是隐式DataTemplate,这意味着只要WPF 需要绘制指定数据类型的对象,就会隐式使用它。

      一个带有x:Key属性的DataTemplate需要在你的代码中通过key实际指定,比如

      <ListView ItemTemplate="{StaticResource MyKey}" ... />
      

      另外,我不确定您的问题标题(“MVVM 的数据上下文:它去哪儿了?”)是否是错字,因为您的问题正文似乎没有正在询问DataContext,但我有一个beginners article on my blog explaining the DataContext,如果您难以理解DataContext,您可能会对它感兴趣

      【讨论】:

      • 现代 UI 应用程序没有 x:Type 属性,这是我的问题。不知道应该是什么方式。
      • @Mike 我没有意识到这一点。你可以使用 DataTemplateSelectors 吗?在 Silverlight 添加对隐式数据模板的支持之前,这就是我在 Silverlight 中使用的。也许像this 这样的东西会起作用?
      • 嗨,是的,这可能会起作用。无论如何,我必须在数据绑定之前解决一些异步加载问题。请参阅对相关问题的回答:stackoverflow.com/a/14189904/1462330。本质上,我现在在我的视图模型上有一个“初始化”任务属性。当您创建其中之一时,您等待初始化任务,以便加载所有 WCF 内容并分配属性。我在视图的初始化任务中做了类似的事情,除了在它们结束时我将它们绑定到它们刚刚初始化的东西似乎工作得很好。
      • 另外,我认为您对 Silverlight 的处理方式可能是正确的。我似乎记得听到人们抱怨他们在使用现代 UI 时习惯的一些东西消失了。我通常会制作 1-2 个窗口报告应用程序,所以大多数事情都隐藏在后面的代码中,所以我不必经常做很多复杂的 MVVM 结构。看起来绑定更痛苦。此外,我听说您需要使用服务,您也无法再直接连接到数据库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-03
      • 2014-03-15
      • 2015-07-17
      • 2012-10-30
      • 2013-05-23
      • 1970-01-01
      相关资源
      最近更新 更多