与ViewModel

时间:2015-08-24 17:35:07

标签: c# xaml uwp win-universal-app

我希望将页面中的元素绑定到带有编译绑定的代码中的依赖项属性,同时使用常规绑定将另一个元素绑定到ViewModel。但它会产生运行时错误。

这是我的xaml代码。

<Page
x:Class="XbindingProblem.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XbindingProblem"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding Main, Source={StaticResource Locator}}"
mc:Ignorable="d">
<Page.Resources>
    <DataTemplate x:Key="UserDataTemplate" x:DataType="local:User">
        <StackPanel>
            <TextBlock Text="{x:Bind Name}" />
            <TextBlock Text="{x:Bind Age}" />
        </StackPanel>
    </DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <TextBlock Text="{Binding Title}"/>
        <ContentPresenter ContentTemplate="{StaticResource UserDataTemplate}" Content="{x:Bind CurrentUser, Mode=OneWay}"/>
    </StackPanel>        
</Grid>

此处CurrentUser是依赖项属性,它最初为null,然后在运行时更改。这会产生以下运行时错误。

Incorrect type passed into template. Based on the x:DataType global::XbindingProblem.User was expected.

问题是当CurrentUser为null时,它将ViewModel传递给UserDataTemplate而不是CurrentUser依赖属性。

任何人都可以对这个问题有一个很好的解释吗?

2 个答案:

答案 0 :(得分:1)

问题很有趣,我所做的只是删除datacontext,这背后的代码与你的类似:

public sealed partial class BlankPage1 : Page
{
    public User CurrentUser
    {
        get { return (User)GetValue(CurrentUserProperty); }
        set { SetValue(CurrentUserProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CurrentUser.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CurrentUserProperty =
        DependencyProperty.Register("CurrentUser", typeof(User), typeof(BlankPage1), new PropertyMetadata(null));

    public BlankPage1()
    {
        this.InitializeComponent();

        CurrentUser = new User() { Name = "Hello", Age = "20" };
    }
}

public class User
{
    public String Name { get; set; }
    public String Age { get; set; }
}

可能是您在另一个命名空间中有User类,或者在依赖项属性的typeof(...)中有另一个类。因为我测试了它并且有效。页面的DataContext可以是您想要的任何影响。

然后我添加了datacontext来测试:

<Page.DataContext>
    <local:Main/>
</Page.DataContext>

以及仅用于测试的代码:

public class Main
{
    public String Title { get; } = "title";
    public User MainUser { get; set; }
}

它不会抛出任何异常,显示主数据和CurrentUser数据。

更新。当User为null时发生错误,因此它就像x:Bind为null它传播到Binding,为了解决这个问题(很难):

<Page x:Name="Root"
    x:Class="Deletetb.BlankPage1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Deletetb"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" >
    <Page.DataContext>
        <local:Main/>
    </Page.DataContext>

    <Page.Resources>
        <DataTemplate x:Key="UserDataTemplate" x:DataType="local:User">
            <StackPanel>
                <TextBlock Text="{x:Bind Name}" />
                <TextBlock Text="{x:Bind Age}" />
            </StackPanel>
        </DataTemplate>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel DataContext="{x:Null}">
            <TextBlock Text="{Binding DataContext.Title, ElementName=Root}" />
            <ContentPresenter  ContentTemplate="{StaticResource UserDataTemplate}" Content="{x:Bind CurrentUser, Mode=OneWay}"/>
        </StackPanel>
    </Grid>
</Page>

绑定定义的位置(TextBlock)我在父容器(StackPanel)中将datacontext设置为null并按元素名称绑定,并且它不会崩溃,我还添加了等待代码来测试和设置当前用户和有用。这是一个挑战。希望它也适合你。

答案 1 :(得分:1)

虽然它打破了MVVM的想法,但您可以像这样在页面中添加一个属性:

public MainViewModel viewModel => DataContext as MainViewModel;

然后在XAML代码中引用页面属性

<ContentPresenter Content="{x:Bind viewModel.CurrentUser, Mode=OneWay}" />