UWP(通用 Windows 平台)中的 x:Bind 是什么?

6

好的,从WPF迁移到UWP时,我正在尝试使用x:Bind来获得编译时优势。简单的场景都能很好地工作;但我发现了一些问题,我无法解决它们。它们都相关,所以我想把它们放在一个地方:

  1. 我无法让Intellisense与x:Bind一起工作。我在XAML和构造函数中设置了DataContext(以及d:DataContext,就像我们在WPF中一样),但无论如何都不会显示成员。有成功的经验吗?
  2. 然后我在某个地方读到,在UWP中,DataContext总是设置为Page的代码后台(真的吗?),我需要在代码后台中定义一个ViewModel类型属性,然后在x:Bind中使用该属性。这正确吗?我尝试过这样做,它有效,但也引发了下一个问题。
  3. 如果我在Page的代码后台中定义了一个ViewModel类型的属性,则引发PropertyChanged通知的任何子属性都不会更新UI。例如,如果代码后台属性名为Game(类型为GameVM),而在GameVM中有一个名为Player(类型为GamePlayer)的公共属性,GamePlayer又包含一个名为Name的属性,则x:Bind路径将看起来像{x:Bind Path=Game.Player.Name}。但是,如果我这样做,任何从Name属性内部引发的更改通知都不会更新Page的UI。

我尝试了一个替代方法,就是在每个级别侦听PropertyChanged,然后将其向上冒泡到层次结构中,但这并没有起作用。即使它起作用了,这样做似乎有点太麻烦了。在WPF中,像Game.Player.Name这样的子属性可以正常工作,而无需进行属性更改冒泡。难道我错过了什么吗?


对于您的第一个观点:在获取建议之前,您始终需要构建项目。我总是先构建项目,然后打开属性窗口,从可能的资源列表中选择绑定源。 - Matthias Herrmann
@MatthiasHerrmann:这不是问题所在。我已经多次构建了这个项目。请阅读我在Monish答案下面的讨论。 - dotNET
4
{x:Bind} 的默认模式是 OneTime,而对于大多数情况下的 {Binding} 默认为 OneWay。相关问答:使用编译绑定(x:bind),为什么我需要调用 Bindings.Update()? - IInspectable
@IInspectable:哎呀,那会造成严重破坏。让我看看。 - dotNET
3个回答

14

好的。经过几天的尝试和搜索了许多参考资料,这是我的发现:

  1. {x:Bind} 缺乏设计时支持。不过该功能已在 愿望清单上。你可以在那里为它投票。 (Visual Studio 15.4.4 的新版本确实在所需的方式下支持 {x:Bind} 的智能感知了。)
  2. {x:Bind} 使用后台代码作为其 DataContext。因此,您需要在代码后台中定义 ViewModel 类型的公共属性,然后在您的 {x:Bind} 路径中使用它。
  3. 正如 IInspectable 指出的那样,默认模式 {x:Bind}OneTime,而不像 {Binding} 在几乎所有情况下都使用 OneWayTwoWay。因此,您需要在绑定中明确指定 Mode。来自 WPF 的人们应特别注意。
  4. 实现通知更改的子属性在 {x:Bind} 中完全正常工作。没有必要将这些通知向上冒泡到属性层次结构中。我遇到的问题(#3)是因为我的子属性类型是 List<T>。我将其更改为 ObservableCollection<T>,它就开始工作了。

希望这些可以帮助到未来的某个人。


我不明白这个,为什么这个框架要求将viewmodel属性放在代码后面?我想让我的代码后面保持干净,因为我正在使用mvvm。为什么为什么为什么? - IronHide
@IronHide:对于像我这样来自WPF的人来说,这可能看起来有点奇怪,但实际上,将其驯服到您的需求非常简单。只需在代码后台中定义ViewModel类型的属性,然后在根XMAL元素(例如Window或UserControl)上使用'DataContext(加上d:DataContext`),指向此属性。然后,您就可以像在WPF中一样设置ViewModel绑定。 - dotNET

1
作为一个初学者,我能回答你的唯一问题就是第一个。在{x:Bind}内部,Intellisense不起作用。由于某些未知原因,在UWP中从未显示成员。至于你的下两个问题,我仍在努力解决。

有关(Intellisense)的任何官方说明或其他参考资料吗? - dotNET
https://social.msdn.microsoft.com/Forums/windowsapps/en-US/f4cdeeb6-c55a-4916-a885-83b16817fe47/no-intellisense-for-xbind?forum=wpdevelop 希望这可以帮助您。 - Monish Koyott
你所说的部分内容是不正确的。Intellisense与{Binding}很好地配合使用。当我在UWP中使用{Binding}时,我可以在XAML中看到我的VM成员。只有{x:Bind}缺乏Intellisense。你提供的链接只涉及x:Bind - dotNET
好的。现在看起来更好了,即使那不是我想听到的 : ) 。无论如何,我想现在我可以暂时没有智能感知(Intellisense)也生存下去。然而,另外两个问题更加重要。 - dotNET

0

我遇到了你所看到的同样的挑战。根据我的经验,为了创建编译时绑定并使其随着自定义对象作为属性更新,Page类似乎需要知道数据上下文自定义对象...你只需要在代码后台引用它们,然后在XAML中进行绑定。这将创建所需的代码生成对象。

例如,我有一个名为CustomerViewModel的视图模型,在XAML中进行绑定。该视图模型还具有类型为IGuest的属性。为了使用客人对象并使其正确更新,我在代码后台想出了以下解决方案...

        CustomerViewModel vm
        {
            get
            {
                return (CustomerViewModel)DataContext;
            }
        }
      IGuest g
        {
            get
            {
                return vm.CurrentGuest;
            }
        }
        public CartGuestControl()
        {
            this.InitializeComponent();
        }

你不需要从代码后台分配任何UI数据上下文...只需引用在XAML中绑定的数据上下文即可。当绑定到任何直接视图模型属性时,我使用{x:Bind Path=vm.IsEditing, Mode=OneWay}。对于绑定到任何客人属性,它看起来像这样:{x:Bind Path=g.FirstName, Mode=TwoWay}。您可以为Player对象执行类似的操作。
我遇到过x:Bind有时无论我尝试什么都不能满足我的预期的情况。通常可以通过将事物拆分为具有更具体数据上下文的较小用户控件或使用“常规”绑定来解决这个问题。

感谢分享信息。如果您仔细看一下您所建议的内容,您的 x:Bind 仍然使用代码后台类作为其 DataContext。您所做的只是在代码后台创建顶级属性,这些属性充当那些嵌套对象属性的包装器。这正是我最终所做的(问题的最后一段),但当时这对我没有起作用。我现在已经找到了那个问题的根本原因。挖掘完成后,我将发布我的发现。 - dotNET

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接