【问题标题】:XAML x:bind oneTime on initially null property still works. Why?XAML x:bind oneTime 在最初的 null 属性上仍然有效。为什么?
【发布时间】:2017-07-25 02:18:24
【问题描述】:

x:Bind 默认为 OneTime,当 Page 的 Loading 事件触发生成代码的 Initialize 函数时,用数据更新目标 UI。

我有一个带有 ViewModel 属性的页面。此 ViewModel 类为其属性实现 INPC。 viewModel 的数据是异步加载的,只有在页面加载之后。因此,在 Page 初始化以及随后生成的代码初始化时,使用 x:Bind 的 UI 目标将具有空数据。

因为它是 OneTime,它不应该改变,除非我手动调用 Update(我没有)。

那么为什么我的 x:Bind UI 可以工作?

以下是一些简化的代码sn-ps。

<Page x:Name="MyPage" x:Class="MyProject.Pages.MyPage">
  <Button Command="{x:Bind ViewModel.GoToAnotherPageCommand}">


public sealed partial class MyPage : Page
{
    public MyPageViewModel ViewModel { get; set; }

    public MyPage()
    {
        this.InitializeComponent();
    }

    // called by an event bound to a Frame's Navigated, which all pages use
    public void OnNavigatedTo()
    {
        this.ViewModel = new MyPageViewModel();
    }
}

public class MyPageViewModel : INotifyPropertyChanged, INotifyPropertyChanging
{
    // GoToAnotherPageCommand is an INPC property and its set in the constructor

【问题讨论】:

  • 总结贾斯汀的回答,页面的加载事件发生在框架的导航事件之前,因此在导航上完成 ViewModel 初始化的页面调用 .Navigate 将在 OneTime x:Bind 时提供数据获取数据的值。一个例外是数据的异步初始化,不能保证在引发 Loading 事件时准备好。

标签: c# xaml uwp


【解决方案1】:

您的命令运行良好的原因是OnNavigatedTo 将在命令实例化之前被调用。这意味着当代码尝试设置命令时,ViewModel 已经被实例化并且不再是 null

为了证明我的观点,首先打开以下路径下的文件(可能是 ARM 或 *x64,具体取决于您运行的平台)-

obj/x86/Debug/MyPage.g.cs

这基本上是代码生成的文件,它为您的页面连接了所有x:Bind 内容。

现在在设置命令的位置放置一个断点。在我的例子中,它是一个名为Set_Windows_UI_Xaml_Controls_Primitives_ButtonBase_Command 的方法。然后在OnNavigatedTo 放置另一个断点

现在运行应用程序,您将看到首先调用了OnNavigatedTo 方法。

如果您的页面的NavigationCacheMode 设置为Disabled,则此行为使OnNavigatedTo 成为实例化x:Bind 绑定的理想位置,因此该页面仅在用户实际导航到它时才使用内存来创建这些新对象,而不是在页面构造函数中做所有事情。

不要在PageLoaded 事件中执行此操作。因为它会在命令实例化之后被调用。你可以试试下面的代码来实例化ViewModel,结果很不一样(你的命令不行)。

public MyPage()
{
    InitializeComponent();

    Loaded += (s, e) => ViewModel = new MyPageViewModel();
}

【讨论】:

  • 好的,当我们在 Frame 上调用 .Navigate 时,它​​的 Navigated 事件是否会在引发 Page 的 Loading 事件之前触发?
【解决方案2】:

已编译的绑定系统 (x:Bind) 足够智能,可以检查初始空值,而不会将它们视为您希望绑定的实际值。它将等待第一个非空值并绑定该值。

这是设计使然,因为绑定到初始 null 值(几乎)绝不是绑定的意图。

我没有找到这些信息的来源,但我相信它是在 2015 年详细介绍 x:Bind 系统的构建谈话中。


更新:

正如贾斯汀在下面的 cmets 和他自己的回答中提到的那样,如果在绑定操作发生后设置视图模型,则绑定将不起作用。

我认为这是因为绑定在属性链中遇到空引用时终止,但我没有对此进行测试,所以我可能不正确。

【讨论】:

  • 如果是这种情况,请尝试将其设置为已加载,该命令将不再起作用。我不认为这是正确的。
  • 是否可以使用常规绑定? ViewModel 不是 INPC 也不是 DP,因此绑定不会收到属性更改的通知
  • 实际上,我只是在传统绑定中再次考虑了这一点,它仅在分配数据上下文之后才开始评估绑定。因此,即使在 Loaded 内部,它也应该可以正常工作。 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
相关资源
最近更新 更多