我希望将页面中的元素绑定到带有编译绑定的代码中的依赖项属性,同时使用常规绑定将另一个元素绑定到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依赖属性。
任何人都可以对这个问题有一个很好的解释吗?
答案 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}" />