我想要将页面中的一个元素绑定到代码中的依赖属性,同时使用常规绑定将另一个元素绑定到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为空时,它将ViewModel传递给UserDataTemplate而不是CurrentUser依赖属性。
有人能对这个问题有一个很好的解释吗?
发布于 2015-08-25 15:29:21
如果您删除DataContext="{Binding Main, Source={StaticResource Locator}}",它将正常工作。为什么?因为{x:Bind CurrentUser}正在寻找一个名为CurrentUser的属性,它位于您的MainPage.xaml.cs中。由于CurrentUser确实是页面的依赖属性,因此它将正常工作。
但是,通过指定页面的DataContext,x:Bind现在将在MainViewModel实例中排除CurrentUser属性,当然它将找不到该属性,因此将抛出编译时错误。
一种可能的解决方法是,甚至在调用InitializeComponent之前就设置this.CurrentUser。
this.CurrentUser = new User();
InitializeComponent();但这不是做事情的正确方法,因为它基本上是一个赛车游戏-它试图在DataContext更新之前填充ContentPresenter,最终你会得到TextBlock ( Text绑定到Title)和ContentPresenter附加到不同的上下文!
因此,问问自己,为什么需要在Page对象中为CurrentUser创建依赖属性,而不是在MainViewModel中拥有一个普通属性(使用INotifyPropertyChanged实现)?我更喜欢后者,因为它在语义上更正确。
发布于 2015-08-25 04:40:34
这个问题很有趣,我所做的只是删除了数据上下文,这是后面的代码与您的类似:
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数据。
更新。当用户为null时,就会发生错误,因此就像x:Bind是null一样,它会传播到绑定,以解决这个问题(这很困难):
<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,并按元素名称绑定,它不会崩溃,我还添加了一个等待代码来测试和设置当前用户,它可以工作。这是一个挑战。希望它也适用于你。
发布于 2015-08-25 04:51:06
尽管它稍微打破了MVVM的概念,但您可以像这样向页面添加一个属性:
public MainViewModel viewModel => DataContext as MainViewModel;然后在XAML代码中引用页面属性
<ContentPresenter Content="{x:Bind viewModel.CurrentUser, Mode=OneWay}" />https://stackoverflow.com/questions/32188269
复制相似问题