我目前正在尝试使用新的已编译绑定(bind),并且(再次)达到了我在拼图中错过一分钱的地步:为什么我必须调用Bindings.Update
?直到现在,我还认为实现INotifyPropertyChanged
足够了?
在我的示例中,如果我调用此神秘方法(由编译的绑定(bind)自动生成),则GUI仅显示正确的值。
我正在使用具有以下xaml语法的用户控件:
<UserControl>
<TextBlock Text="x:Bind TextValue"/>
</UserControl>
其中
TextValue
是此用户控件的简单依赖项属性。在页面中,我将此控件用作:<Page>
<SampleControl TextValue="{x:Bind ViewModel.Instance.Name}"/>
</Page>
在哪里:
ViewModel
是在运行InitializeComponent()
之前设置的标准属性Instance
是实现INotifyPropertyChanged
的简单对象加载
Instance
后,我引发了Instance
的属性更改事件。我什至可以调试到该行,在该行中,用户控件的依赖属性TextValue
获得正确的值,但是什么也不显示。仅当我调用Bindings.Update()
时,才会显示该值。我在这里想念什么?更新
我也不使用
{x:Bind ... Mode=OneWay}
。更多代码
Person.cs:
using System.ComponentModel;
using System.Threading.Tasks;
namespace App1 {
public class Person : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name { get {
return this.name;
}
set {
name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public class ViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private Person instance;
public Person Instance {
get {
return instance;
}
set {
instance = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Instance"));
}
}
public Task Load() {
return Task.Delay(1000).ContinueWith((t) => {
var person = new Person() { Name = "Sample Person" };
this.Instance = person;
});
}
}
}
SampleControl.cs:
<UserControl
x:Class="App1.SampleControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="100"
d:DesignWidth="100">
<TextBlock Text="{x:Bind TextValue, Mode=OneWay}"/>
</UserControl>
SampleControl.xaml.cs:
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App1 {
public sealed partial class SampleControl : UserControl {
public SampleControl() {
this.InitializeComponent();
}
public string TextValue {
get { return (string)GetValue(TextValueProperty); }
set { SetValue(TextValueProperty, value); }
}
public static readonly DependencyProperty TextValueProperty =
DependencyProperty.Register("TextValue", typeof(string), typeof(SampleControl), new PropertyMetadata(string.Empty));
}
}
MainPage.xaml:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:SampleControl TextValue="{x:Bind ViewModel.Instance.Name, Mode=OneWay}"/>
</StackPanel>
</Page>
MainPage.xaml.cs:
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App1 {
public sealed partial class MainPage : Page
{
public MainPage()
{
this.DataContext = new ViewModel();
this.Loaded += MainPage_Loaded;
this.InitializeComponent();
}
public ViewModel ViewModel {
get {
return DataContext as ViewModel;
}
}
private void MainPage_Loaded(object sender, RoutedEventArgs e) {
ViewModel.Load();
Bindings.Update(); /* <<<<< Why ????? */
}
}
}
又一个更新
我更新了
Load
方法以使用任务(请参见上面的代码)! 最佳答案
有时,要显示的数据直到页面加载并呈现几秒钟后才可用(例如从服务器或数据库返回)。如果您在后台/异步过程中调用数据以释放UI而不挂起,则尤为如此。
到目前为止有意义吗?
现在创建一个绑定(bind);我们这样说:
<TextBlock Text="{x:Bind ViewModel.User.FirstName}" />
后面代码中ViewModel属性的值将具有实际值,并且可以很好地绑定(bind)。另一方面,您的用户将没有值,因为它尚未从服务器返回。结果既不能显示用户的名字,也不能显示用户的名字,对吗?
然后更新您的数据。
您认为将User对象的值设置为真实对象时,绑定(bind)会自动更新。特别是如果您花时间使其成为INotifyPropertyChanged属性,对吗?对于传统的{Binding}来说,这是正确的,因为默认的绑定(bind)模式是OneWay。
什么是OneWay绑定(bind)模式?
OneWay绑定(bind)模式意味着您可以更新实现INotifyPropertyChanged的后端模型属性,并且绑定(bind)到该属性的UI元素将反射(reflect)数据/值更改。太好了
为什么不起作用?
这不是因为{x:Bind}不支持Mode = OneWay,而是因为它默认为Mode = OneTime。回顾一下,传统的{Binding}默认为Mode = OneWay,编译的{x:Bind}默认为Mode = OneTime。
什么是OneTime绑定(bind)模式?
OneTime绑定(bind)模式意味着在使用绑定(bind)加载/渲染UI元素时,仅绑定(bind)一次到基础模型。这意味着,如果您的基础数据尚不可用,它将无法显示该数据,并且一旦数据可用,将不会显示该数据。为什么?因为OneTime不监视INotifyPropertyChanged。它仅在加载时读取。
如何解决此问题?
有几种方法。首先也是最简单的方法是将绑定(bind)从
="{x:Bind ViewModel.User.FirstName}
更改为="{x:Bind ViewModel.User.FirstName, Mode=OneWay}
。这样做将监视INotifyPropertyChanged事件。解决此问题并保持{x:Bind}开箱即用的性能优势的另一种方法是,在 View 模型完全准备好要呈现的数据之后,调用
Bindings.Update();
。如果您的工作是异步的,那么这很容易-但是,就像上面的示例一样,如果您不确定计时器可能是唯一可行的选择,那么这很容易。我希望这可以解释正在发生的事情。
祝你好运!
关于c# - 使用已编译的绑定(bind)(x :bind),,为什么我必须调用Bindings.Update()?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33070705/