我正在研究一个UWP应用程序,我意识到UpdateSourceTrigger
控件的默认TextBox
模式,即LostFocus
,在使用编译绑定时无法更改。
这意味着每当我想要为TextBox
更新绑定时,我必须使用所有这些重复的样板:
<TextBox
Text="{x:Bind ViewModel.Title, Mode=TwoWay}"
TextChanged="TextBox_OnTextChanged"/>
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
ViewModel.Title = ((TextBox)sender).Text;
}
现在,这不是太糟糕,但必须记住每次使用TextChanged
时都要创建TextBox
处理程序,这很烦人且容易出错。
这适用于经典绑定:
<TextBox Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
但是,当然,这里会有usinc经典绑定的额外开销(涉及运行时反射等)。
有没有办法获得UpdateSourceTrigger=PropertyChanged
的相同行为?我会完全没问题,比如写一个自定义附加属性来设置,只要我可以直接从XAML做我需要的一切,不涉及任何代码。
谢谢!
更新:(回应Nico Zhu - MSFT的回答)
对于我的测试,它运作良好。
它根本不适合我,正如我已多次说过,使用UpdateSourceTrigger
与x:Bind
是不可能的。它没有编译,属性在XAML编辑器中以红色显示,它就不存在。如果你说它适合你,我真的不知道你在哪里尝试。我目前最低目标是17763,我可以100%保证这不起作用。
Compiled Binding与{x:Bind}语法一起使用,而不是Classic Binding的{Binding}语法。
我很清楚这种差异,我已经多次提到过这个问题,我在这里提出了原始问题(也有代码片段)以及我的评论。
它仍然使用通知接口(如INotifyPropertyChanged)来监视更改
正如我所说,我也知道这一点。但同样,从这个问题来看,这根本不是问题所在。问题不在于从viewmodel到bound属性的更新,而是从绑定属性(在本例中为TextBox.Text)到viewmodel。
默认情况下,
{x:Bind}
是OneTime,而{Binding}则是OneWay。所以你需要为{x:Bind}声明绑定模式OneWay或TwoWay。
对不起,但我不得不说,在这一点上,我开始怀疑你是否真的读过我最初的问题。我知道这一点,事实上你可以在我的原始代码片段中看到我已经在我的两个绑定中使用了显式的Mode=TwoWay
属性。
再一次,这根本不是问题所在。
重申:这里的问题是TextBox.Text
属性默认为LostFocus
触发器,并且UpdateSourceTrigger
属性不可用于编译绑定。所以我想知道是否有一种方法可以在XAML中实现相同的编译绑定,而不必每次都手动创建一个TextChanged
处理程序(如果不打算,如果你计划最终添加UpdateSourceTrigger
)属性也可以编译绑定)。
旁注:我并不是说在这里听起来不尊重,我希望我们现在已经用我的问题解决了现有的误解。
更新#2:事实证明问题是由ReSharper插件引起的,该插件将UpdateSourceTrigger
属性标记为编译绑定中的错误。我在这里开了一个问题:https://youtrack.jetbrains.com/issue/RSRP-474438
请检查UpdateSourceTrigger
文档。
默认的UpdateSourceTrigger值是Default
。并使用来自使用绑定的依赖项属性的默认行为。在Windows运行时中,它使用PropertyChanged
计算与值相同的值。如果您使用Text="{x:Bind ViewModel.Title, Mode=TwoWay}"
,则在文本更改时将更改标题。我们不需要在TextChanged
甚至处理程序中修改viewmode。
前提是我们需要实现INotifyPropertyChanged
,如下所示。
public class HostViewModel : INotifyPropertyChanged
{
private string nextButtonText;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public HostViewModel()
{
this.NextButtonText = "Next";
}
public string NextButtonText
{
get { return this.nextButtonText; }
set
{
this.nextButtonText = value;
this.OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
有关更多详细信息,请参阅Data binding in depth文档。
更新
<TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
根本不编译,因为我说使用编译绑定时UpdateSourceTrigger
属性根本不可用。
对于我的测试,它运作良好。 Compiled Binding与{x:Bind}
语法一起使用,而不是经典绑定的{Binding}
语法。它仍然使用通知接口(如INotifyPropertyChanged
)来监视更改,但{x:Bind}
默认为OneTime,而{Binding}
则是OneWay。所以你需要为OneWay
声明绑定模式TwoWay
或{x:Bind}
。
XAML
<StackPanel Orientation="Vertical">
<TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{x:Bind Title, Mode=OneWay}" /> <!--declare bind mode-->
</StackPanel>
代码背后
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _title;
public string Title
{
get
{
return _title;
}
set
{
_title = value;
OnPropertyChanged();
}
}