为什么我不能在数据模板中使用 {x:Bind {RelativeSource Self}}?
Why can't I use {x:Bind {RelativeSource Self}} in a data template?
如果我在数据模板中使用 {x:Bind {RelativeSource Self}}
,编译时会出现以下错误:
Object reference not set to an instance of an object.
想法是像命令参数一样将模板化对象传递给 属性。这是一个例子 MainPage.xaml:
<Page
x:Class="XBindTest5.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XBindTest5"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<local:OpenItemCommand x:Key="OpenCommand"/>
</ResourceDictionary>
</Page.Resources>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ItemsControl ItemsSource="{x:Bind NewsItems, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:NewsItem">
<StackPanel>
<Button Command="{x:Bind {StaticResource OpenCommand}}" CommandParameter="{x:Bind {RelativeSource Self}}">
<TextBlock Text="{x:Bind Title}"/>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Page>
代码隐藏文件中定义了一个简单的模型MainPage.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Windows.UI.Xaml.Controls;
namespace XBindTest5 {
public class NewsItem {
public string Title { get; set; }
}
/// <summary>
/// command to open the item
/// </summary>
public class OpenItemCommand : ICommand {
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) {
return true;
}
public void Execute(object parameter) {
// ... example ...
}
}
public sealed partial class MainPage : Page {
public ObservableCollection<NewsItem> NewsItems { get; set; }
= new ObservableCollection<NewsItem>(new[] {
new NewsItem() { Title = "Item 1" },
new NewsItem() { Title = "Item 2" } });
public MainPage() {
this.InitializeComponent();
}
}
}
虽然看起来你的问题已经解决了,但我还是想做一些澄清,以免混淆,让以后的读者清楚。
正如@Peter Duniho 所提到的,{x:Bind}
无法与 DataContext
属性 一起使用并且 {x:Bind}
没有 Source
属性,因此您不能将 StaticResource
用作 {x:Bind}
中的数据上下文,但您可以改用 属性 或静态路径。在使用 {x:Bind}
时,它使用背景 class 作为其数据上下文。例如,当您设置 ItemsSource="{x:Bind NewsItems, Mode=OneWay}"
时,它使用 XBindTest5.MainPage
class 作为其数据上下文并将此 class 的 NewsItems
属性 绑定到ItemsSource
。在 DataTemplate 内部,{x:Bind}
使用 x:DataType
中声明的 class 作为其数据上下文。请注意DataTemplate and x:DataType中的以下解释:
Inside a DataTemplate (whether used as an item template, a content template, or a header template), the value of Path is not interpreted in the context of the page, but in the context of the data object being templated. So that its bindings can be validated (and efficient code generated for them) at compile-time, a DataTemplate needs to declare the type of its data object using x:DataType.
在你的例子中,你在DataTemplate
中使用Command
,所以你可以在NewsItem
中添加一个OpenCommand
属性并绑定这个属性 到 Command
来使用它。
在您的代码隐藏中:
public class NewsItem
{
public string Title { get; set; }
public OpenItemCommand OpenCommand { get; set; }
}
在XAML:
<DataTemplate x:DataType="local:NewsItem">
<StackPanel>
<Button Command="{x:Bind OpenCommand}" CommandParameter="{x:Bind}">
<TextBlock Text="{x:Bind Title}" />
</Button>
</StackPanel>
</DataTemplate>
另外{x:Bind}
不支持{RelativeSource}
,通常你可以给元素命名并在Path
中使用它的名字作为替代。有关详细信息,请参阅 {x:Bind} and {Binding} feature comparison。
但这不能用于 DataTemplate
,因为所有 Path
都应该是 NewsItem
的 属性。在您的情况下,我认为您要传递的是 NewsItem
而不是 Button
,因此您可以使用 CommandParameter="{x:Bind}"
将 NewsItem
作为 CommandParameter
.
PS: XAML 设计器中有一个小错误,您可能仍然会得到 Object reference not set to an instance of an object.
错误。您可以在像 {x:Bind }
这样的 Bind 之后添加一个 space 作为解决方法。
让我更具体地回答这个问题。 x:bind 只有一种可能的数据上下文,即基础 class。在页面上,它是页面(或代码隐藏)。在数据模板中,它是在数据模板的目标类型 属性 中指定的支持 class。另外,在控件模板中,根本不支持 x:bind - 尽管这只是时间问题。
也就是说 x:bind 的数据上下文是固定的,并且根据它的使用位置,我可以告诉您数据上下文而无需查看您的 XAML。为什么这么死板?部分原因是为了简化围绕它的代码生成。此外,为了使实施更简单。在任何一种情况下,这都是固定规则,RelativeSource、ElementName 和 Source 在 x:bind.
中不受支持
这并不意味着您不能引用相对源自身,您只需使用指定的 x:name 即可。你会做这样的事情 <Tag x:Name="Jerry" Tag="Nixon" Text="{x:Bind Jerry.Tag}" />
。
为什么那个特定的样本失败了?与{binding}
不同的是,{x:bind}
需要匹配类型,也就是说设置Text的字符串可以向下转型设置为Tag的对象,但是Tag的对象不能向上转型设置为Text的字符串值。您的要点是使用 x:bind 意味着您的类型必须匹配。
我希望这能帮助你走得更远。
祝你好运。
如果我在数据模板中使用 {x:Bind {RelativeSource Self}}
,编译时会出现以下错误:
Object reference not set to an instance of an object.
想法是像命令参数一样将模板化对象传递给 属性。这是一个例子 MainPage.xaml:
<Page
x:Class="XBindTest5.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XBindTest5"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<local:OpenItemCommand x:Key="OpenCommand"/>
</ResourceDictionary>
</Page.Resources>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ItemsControl ItemsSource="{x:Bind NewsItems, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:NewsItem">
<StackPanel>
<Button Command="{x:Bind {StaticResource OpenCommand}}" CommandParameter="{x:Bind {RelativeSource Self}}">
<TextBlock Text="{x:Bind Title}"/>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Page>
代码隐藏文件中定义了一个简单的模型MainPage.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Windows.UI.Xaml.Controls;
namespace XBindTest5 {
public class NewsItem {
public string Title { get; set; }
}
/// <summary>
/// command to open the item
/// </summary>
public class OpenItemCommand : ICommand {
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) {
return true;
}
public void Execute(object parameter) {
// ... example ...
}
}
public sealed partial class MainPage : Page {
public ObservableCollection<NewsItem> NewsItems { get; set; }
= new ObservableCollection<NewsItem>(new[] {
new NewsItem() { Title = "Item 1" },
new NewsItem() { Title = "Item 2" } });
public MainPage() {
this.InitializeComponent();
}
}
}
虽然看起来你的问题已经解决了,但我还是想做一些澄清,以免混淆,让以后的读者清楚。
正如@Peter Duniho 所提到的,{x:Bind}
无法与 DataContext
属性 一起使用并且 {x:Bind}
没有 Source
属性,因此您不能将 StaticResource
用作 {x:Bind}
中的数据上下文,但您可以改用 属性 或静态路径。在使用 {x:Bind}
时,它使用背景 class 作为其数据上下文。例如,当您设置 ItemsSource="{x:Bind NewsItems, Mode=OneWay}"
时,它使用 XBindTest5.MainPage
class 作为其数据上下文并将此 class 的 NewsItems
属性 绑定到ItemsSource
。在 DataTemplate 内部,{x:Bind}
使用 x:DataType
中声明的 class 作为其数据上下文。请注意DataTemplate and x:DataType中的以下解释:
Inside a DataTemplate (whether used as an item template, a content template, or a header template), the value of Path is not interpreted in the context of the page, but in the context of the data object being templated. So that its bindings can be validated (and efficient code generated for them) at compile-time, a DataTemplate needs to declare the type of its data object using x:DataType.
在你的例子中,你在DataTemplate
中使用Command
,所以你可以在NewsItem
中添加一个OpenCommand
属性并绑定这个属性 到 Command
来使用它。
在您的代码隐藏中:
public class NewsItem
{
public string Title { get; set; }
public OpenItemCommand OpenCommand { get; set; }
}
在XAML:
<DataTemplate x:DataType="local:NewsItem">
<StackPanel>
<Button Command="{x:Bind OpenCommand}" CommandParameter="{x:Bind}">
<TextBlock Text="{x:Bind Title}" />
</Button>
</StackPanel>
</DataTemplate>
另外{x:Bind}
不支持{RelativeSource}
,通常你可以给元素命名并在Path
中使用它的名字作为替代。有关详细信息,请参阅 {x:Bind} and {Binding} feature comparison。
但这不能用于 DataTemplate
,因为所有 Path
都应该是 NewsItem
的 属性。在您的情况下,我认为您要传递的是 NewsItem
而不是 Button
,因此您可以使用 CommandParameter="{x:Bind}"
将 NewsItem
作为 CommandParameter
.
PS: XAML 设计器中有一个小错误,您可能仍然会得到 Object reference not set to an instance of an object.
错误。您可以在像 {x:Bind }
这样的 Bind 之后添加一个 space 作为解决方法。
让我更具体地回答这个问题。 x:bind 只有一种可能的数据上下文,即基础 class。在页面上,它是页面(或代码隐藏)。在数据模板中,它是在数据模板的目标类型 属性 中指定的支持 class。另外,在控件模板中,根本不支持 x:bind - 尽管这只是时间问题。
也就是说 x:bind 的数据上下文是固定的,并且根据它的使用位置,我可以告诉您数据上下文而无需查看您的 XAML。为什么这么死板?部分原因是为了简化围绕它的代码生成。此外,为了使实施更简单。在任何一种情况下,这都是固定规则,RelativeSource、ElementName 和 Source 在 x:bind.
中不受支持这并不意味着您不能引用相对源自身,您只需使用指定的 x:name 即可。你会做这样的事情 <Tag x:Name="Jerry" Tag="Nixon" Text="{x:Bind Jerry.Tag}" />
。
为什么那个特定的样本失败了?与{binding}
不同的是,{x:bind}
需要匹配类型,也就是说设置Text的字符串可以向下转型设置为Tag的对象,但是Tag的对象不能向上转型设置为Text的字符串值。您的要点是使用 x:bind 意味着您的类型必须匹配。
我希望这能帮助你走得更远。
祝你好运。