【问题标题】:ListView renders UserControl before bindListView 在绑定之前呈现 UserControl
【发布时间】:2019-04-10 10:19:53
【问题描述】:

简而言之,我的问题是:

  • 我正在 Windows 通用/UWP 应用中使用ListView(和DataTemplate)呈现一组不可变项。
  • 由于集合中的项目是不可变的,我想避免更改通知代码并使用高效的{x:Bind Mode=OneTime} 默认值。
  • 但是,MyUserControl 在其UserControlViewModel 绑定之前呈现。调试,我看到set之前有一个属性get

如何确保在呈现OneTime 之前设置UserControlViewModel


一个完整的例子如下:

MainPage.xaml

<Page x:Class="MyApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyApp" xmlns:sys="using:System">
    <ListView ItemsSource="{x:Bind PageViewModel}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="sys:String">
                <local:MyUserControl UserControlViewModel="{x:Bind}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

MainPage.xaml.cs

using Windows.UI.Xaml.Controls;
namespace MyApp {
    public sealed partial class MainPage : Page {
        public string[] PageViewModel { get; set; } = new string[] { "Item1", "Item2" };
        public MainPage() { InitializeComponent(); }
    }
}

MyUserControl.xaml

<UserControl x:Class="MyApp.MyUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TextBlock Text="{x:Bind ViewModel}" />
</UserControl>

MyUserControl.xaml.cs

using Windows.UI.Xaml.Controls;
namespace MyApp {
    public sealed partial class MyUserControl : UserControl {
        public string UserControlViewModel { get; set; } = "Default Value";
        public MyUserControl() { InitializeComponent(); }
    }
}

此代码呈现一个包含两行文本“默认值”的页面;相反,我的意图是显示值“Item1”和“Item2”。


如果我们将PageViewModel 设为空ObservableCollection&lt;string&gt; 并稍后填充它,问题仍然存在。有趣的是,将ListView 替换为ListBox,或完全删除ListView,将setget 之前,并按预期呈现:

MainPage.xaml

<Page x:Class="MyApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyApp">
    <local:MyUserControl UserControlViewModel="{x:Bind PageViewModel[0]}" />
</Page>

【问题讨论】:

  • 旁注:您提到集合是可变的,在您的代码中是一个字符串数组。更改字符串数组的内容(=改变它)不会触发 UI 的更新,因为(字符串)数组无法通知绑定机制。选择具有内置更改通知(例如 ObservableCollection)的集合类型而不是数组,这将使您能够在绑定 ItemsControl 自动更新其视图的同时改变集合...
  • 我不知道您所说的“没有 ListView 容器(即单个项目)是什么意思?”。因此,我不确定我是否应该感到惊讶;-)
  • 其实,让我收回我的第一条评论。我检查了文档。 x:Bind 似乎没有要求绑定目标必须是 DependencyProperty(这似乎仅适用于传统绑定 {Binding ...})。很抱歉造成混乱:(
  • 嗯,文档 (docs.microsoft.com/en-us/windows/uwp/xaml-platform/…) 有点欠缺。当您指定没有路径{x:Bind} 的 x-bind 时,它并没有清楚地说明操作模式是什么。由于无法测试自己(此处没有 Windows 10),我只能猜测问题与未在模板中指定带有 {x:Bind} 的路径有关。如果您将字符串包装在带有字符串属性的结构中,使用带有这些结构的数组,并让模板中的 {x:Bind} 引用结构字符串属性会发生什么?
  • 除了我在上一条评论中的建议之外,如果您在数据模板中使用 {x:Bind Path=.} 或类似名称会怎样?

标签: c# xaml mvvm data-binding uwp


【解决方案1】:

有了some help from FEC-4RP at an MSDN forum,我开始明白发生了什么。通过为MyUserControl 的每个实例分配一个唯一ID 并将其中的100 个呈现在ListView 中,我看到控件被框架回收。因此它们显然也需要支持后期绑定。

也就是说,ListView 似乎在设计绑定控件之前会渲染控件,并且在 UI 虚拟化面板中不允许 OneTime 绑定。但是,我不确定,因为我还没有在文档中找到它。

我怀疑VirtualizingStackPanel.VirtualizationMode 默认值从Standard in .NET 更改为Recycling in UWP

添加 DependencyProperty 并将 MyUserControl(或依赖于控件视图模型的所有绑定,通常是所有这些绑定)上的默认绑定模式设置为 OneTime 以外的其他东西似乎是必要的。

请随时在这里更完整地解释,我会接受您的回答,否则我会在完成后在此处提供完整信息。

【讨论】:

    猜你喜欢
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多