在 UWP 中的 GridView 的 ItemTemplate 布局用户控件中使用 x:Bind
Using x:Bind inside the GridView's ItemTemplate layout User Control in UWP
在通用 Windows 平台 API 中,如何使用 x:Bind 在用户控件(旨在作为 GridView 的 ItemTemplate 的布局)内部绑定到实例属性GridView 的 ItemSource?
背景
我正在尝试 re-create 在 Windows 10 个股票应用程序中找到的布局,例如体育、新闻、财经等
我在应用程序的主要区域使用了两个 GridView;一张用于 "featured articles"(2 张带标题的大照片),一张用于所有其他文章(带标题的小照片)。
我能够绑定到我在后面的代码中提供的数据源(一个列表,其中 NewsItem 是一个带有图像和标题的 POCO 属性)这是 MainPage.xaml:
<Page ...
xmlns:data="using:NewsApp.Models" />
....
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
....
图像和标题绑定得很好(即使它们的样式不正确)。但是,相反,我认为我需要绑定到用户控件以获得我想要的样式选项,控制调整大小尤其是。当使用视觉状态触发器并总体上简化 XAML 时(至少,这是向我建议的技术。)
所以,我在项目中添加了一个新的用户控件 (FeaturedItemControl.xaml),并复制到 DataTemplate 的 child 网格中:
<UserControl ... >
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</UserControl>
然后返回 MainPage.xaml,我更改 DataTemplate 以引用新的 FeaturedItemControl:
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<local:FeaturedItemControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
但是,我收到图像和标题属性的错误消息:绑定路径无效 'Headline':无法在类型 'FeaturedItemControl' 上找到 属性 'Headline' .
我已经尝试了一些事情,但我只是在不理解我在做什么的情况下就把代码扔到问题上。任何帮助将不胜感激。
感谢您的关注。
x:Bind 并不像 Binding/DataContext 那样真正分层。此外,当您不直接在 DataTemplate 内(例如在您的用户控件内)时,x:Bind 尝试使用的 object 是 'this' 而不是 'this.DataContext'。我目前关于如何解决此类问题的思路是尽量不要在任何地方使用 UserControls。相反,更喜欢包含在 ResourceDictionary 中的 DataTemplates。不过,这种方法有一些非常强烈的警告,例如,如果您在从 ResourceDictionary 项模板(添加新项)创建的数据模板中使用 x:Bind,您将导致 xaml 编译器崩溃。你可以在这里找到一个非常完整的例子 https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBind 重要的是要注意他们在示例中显示正在使用的 ResourceDictionary 它实际上不仅仅是一个 ResourceDictionary.xaml 它也是一个 ResourceDictionary.xaml.cs (这是 x:Bind 生成的代码结束的地方)
另一种选择是将标题和图像作为属性添加到您的用户控件上,然后从模板中 x:Bind 添加它们,然后像您当前所做的那样在用户控件中添加 x:Bind,但现在 x:Bind 生成的路径 'this.Headline' 将存在。不幸的是,事物的顺序实际上是绑定的,这意味着您在用户控件中拥有的 x:Bind 必须是 OneWay 而不是默认的 OneTime。这是因为 x:Bind OneTime 在 InitializeComponent 调用中进行了绑定,任何一组 properties/DataContext 的东西都没有完成,直到已经 运行.
总而言之,您有两个选择,在任何地方使用数据模板,或者绑定到直接在用户控件上的属性。
嗯,可以在用户控件中使用 x:Bind,但您需要在后面添加一些额外的代码。
我在我的项目中遇到了同样的问题,你可以在这里看到结果:https://github.com/AppCreativity/Kliva/tree/master/src/Kliva/Controls
所以您需要做的是,在您的用户控件的隐藏代码中创建一个指向正确的 DataContext 的 属性。
如果这样做,您可以在控件的 xaml 中使用该 DataContext 的属性:例如:
请注意,在控件的构造函数中,您确实需要添加:DataContextChanged += (sender, args) => this.Bindings.Update();
因为数据上下文会根据使用控件的页面而变化!
然后在放置此控件的页面上,您还需要执行相同的操作才能使 x:bind 正常工作。
您将在我的 MainPage.DeviceFamily-Mobile.xaml
和 MainPage.xaml.cs
文件示例中看到这一点。
希望对您有所帮助。
根据 Depechie 的回答,我为后代制定了这个小骗局:
请注意,您必须使用此技术将 VisualStateManager 与数据绑定控件(GridView、ListView)数据模板中的项目一起使用。
1) 创建用户控件。
2) 在您的页面中剪切 DataTemplate 的内容并将其粘贴到替换模板网格的用户控件中。
3) 从数据模板中引用用户控件:
4) 修改用户控件的内容,更改 x:Bind 语句以使用 object.property 符号:
<UserControl>
<StackPanel>
<Image Source="{x:Bind NewsItem.LeadPhoto}" />
<TextBlock Text="{x:Bind NewsItem.Headline}" />
<TextBlock Text="{x:Bind NewsItem.Subhead}" />
</StackPanel>
</UserControl>
5) 在用户控件的隐藏代码中添加:
public Models.NewsItem NewsItem { get { return this.DataContext as Models.NewsItem; } }
public ContactTemplate()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => Bindings.Update();
}
在通用 Windows 平台 API 中,如何使用 x:Bind 在用户控件(旨在作为 GridView 的 ItemTemplate 的布局)内部绑定到实例属性GridView 的 ItemSource?
背景
我正在尝试 re-create 在 Windows 10 个股票应用程序中找到的布局,例如体育、新闻、财经等
我在应用程序的主要区域使用了两个 GridView;一张用于 "featured articles"(2 张带标题的大照片),一张用于所有其他文章(带标题的小照片)。
我能够绑定到我在后面的代码中提供的数据源(一个列表,其中 NewsItem 是一个带有图像和标题的 POCO 属性)这是 MainPage.xaml:
<Page ...
xmlns:data="using:NewsApp.Models" />
....
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
....
图像和标题绑定得很好(即使它们的样式不正确)。但是,相反,我认为我需要绑定到用户控件以获得我想要的样式选项,控制调整大小尤其是。当使用视觉状态触发器并总体上简化 XAML 时(至少,这是向我建议的技术。)
所以,我在项目中添加了一个新的用户控件 (FeaturedItemControl.xaml),并复制到 DataTemplate 的 child 网格中:
<UserControl ... >
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</UserControl>
然后返回 MainPage.xaml,我更改 DataTemplate 以引用新的 FeaturedItemControl:
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<local:FeaturedItemControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
但是,我收到图像和标题属性的错误消息:绑定路径无效 'Headline':无法在类型 'FeaturedItemControl' 上找到 属性 'Headline' .
我已经尝试了一些事情,但我只是在不理解我在做什么的情况下就把代码扔到问题上。任何帮助将不胜感激。
感谢您的关注。
x:Bind 并不像 Binding/DataContext 那样真正分层。此外,当您不直接在 DataTemplate 内(例如在您的用户控件内)时,x:Bind 尝试使用的 object 是 'this' 而不是 'this.DataContext'。我目前关于如何解决此类问题的思路是尽量不要在任何地方使用 UserControls。相反,更喜欢包含在 ResourceDictionary 中的 DataTemplates。不过,这种方法有一些非常强烈的警告,例如,如果您在从 ResourceDictionary 项模板(添加新项)创建的数据模板中使用 x:Bind,您将导致 xaml 编译器崩溃。你可以在这里找到一个非常完整的例子 https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBind 重要的是要注意他们在示例中显示正在使用的 ResourceDictionary 它实际上不仅仅是一个 ResourceDictionary.xaml 它也是一个 ResourceDictionary.xaml.cs (这是 x:Bind 生成的代码结束的地方)
另一种选择是将标题和图像作为属性添加到您的用户控件上,然后从模板中 x:Bind 添加它们,然后像您当前所做的那样在用户控件中添加 x:Bind,但现在 x:Bind 生成的路径 'this.Headline' 将存在。不幸的是,事物的顺序实际上是绑定的,这意味着您在用户控件中拥有的 x:Bind 必须是 OneWay 而不是默认的 OneTime。这是因为 x:Bind OneTime 在 InitializeComponent 调用中进行了绑定,任何一组 properties/DataContext 的东西都没有完成,直到已经 运行.
总而言之,您有两个选择,在任何地方使用数据模板,或者绑定到直接在用户控件上的属性。
嗯,可以在用户控件中使用 x:Bind,但您需要在后面添加一些额外的代码。 我在我的项目中遇到了同样的问题,你可以在这里看到结果:https://github.com/AppCreativity/Kliva/tree/master/src/Kliva/Controls
所以您需要做的是,在您的用户控件的隐藏代码中创建一个指向正确的 DataContext 的 属性。
如果这样做,您可以在控件的 xaml 中使用该 DataContext 的属性:例如:
请注意,在控件的构造函数中,您确实需要添加:DataContextChanged += (sender, args) => this.Bindings.Update();
因为数据上下文会根据使用控件的页面而变化!
然后在放置此控件的页面上,您还需要执行相同的操作才能使 x:bind 正常工作。
您将在我的 MainPage.DeviceFamily-Mobile.xaml
和 MainPage.xaml.cs
文件示例中看到这一点。
希望对您有所帮助。
根据 Depechie 的回答,我为后代制定了这个小骗局:
请注意,您必须使用此技术将 VisualStateManager 与数据绑定控件(GridView、ListView)数据模板中的项目一起使用。
1) 创建用户控件。
2) 在您的页面中剪切 DataTemplate 的内容并将其粘贴到替换模板网格的用户控件中。
3) 从数据模板中引用用户控件:
4) 修改用户控件的内容,更改 x:Bind 语句以使用 object.property 符号:
<UserControl>
<StackPanel>
<Image Source="{x:Bind NewsItem.LeadPhoto}" />
<TextBlock Text="{x:Bind NewsItem.Headline}" />
<TextBlock Text="{x:Bind NewsItem.Subhead}" />
</StackPanel>
</UserControl>
5) 在用户控件的隐藏代码中添加:
public Models.NewsItem NewsItem { get { return this.DataContext as Models.NewsItem; } }
public ContactTemplate()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => Bindings.Update();
}