更改视图模型
本文关键字:模型 视图 | 更新日期: 2023-09-27 17:55:42
>我简化了应用程序来显示我的问题
当我单击按钮时,它会更改Text
ViewModel
的属性并更新TextBlock.Text
。
MainPage.xaml
<StackPanel>
<Button Click="ButtonBase_OnClick">Button to change text</Button>
<TextBlock Text="{x:Bind ViewModel.Text, Mode=OneWay}"></TextBlock>
</StackPanel>
MainPage.xaml.cs
public MainPage()
{
ViewModel = new ViewModel();
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel.Text = "x:Bind works";
}
ViewModel 类有一个字符串属性(文本)并实现了 INotifyPropertyChange 接口。
当 ctor 中未设置ViewModel
时,问题开始(即 viewModel 为空并在运行时更改):
public MainPage()
{
//ViewModel = new ViewModel();//this line has been removed
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel();//this line has been added
ViewModel.Text = "x:Bind does not work";
}
编译绑定不起作用(文本未更改),我无法弄清楚为什么会这样......我需要将视图模型从空更改(vm 为空,因为它正在等待实际应用程序中的某些数据)
{x:Bind} 绑定(通常称为编译绑定)使用生成的代码来实现其优势。在 XAML 加载时,{x:Bind} 将转换为可视为绑定的对象,并且此对象从数据源上的属性获取值。这些生成的代码可以在obj
文件夹中找到,其名称类似于(对于 C#) <view name>.g.cs
。
对于您的代码,生成的代码将如下所示:
// Update methods for each path node used in binding steps.
private void Update_(global::UWP.BlankPage3 obj, int phase)
{
if (obj != null)
{
if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
{
this.Update_ViewModel(obj.ViewModel, phase);
}
}
}
private void Update_ViewModel(global::UWP.ViewModel obj, int phase)
{
this.bindingsTracking.UpdateChildListeners_ViewModel(obj);
if (obj != null)
{
if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
{
this.Update_ViewModel_Text(obj.Text, phase);
}
}
}
...
private global::UWP.ViewModel cache_ViewModel = null;
public void UpdateChildListeners_ViewModel(global::UWP.ViewModel obj)
{
if (obj != cache_ViewModel)
{
if (cache_ViewModel != null)
{
((global::System.ComponentModel.INotifyPropertyChanged)cache_ViewModel).PropertyChanged -= PropertyChanged_ViewModel;
cache_ViewModel = null;
}
if (obj != null)
{
cache_ViewModel = obj;
((global::System.ComponentModel.INotifyPropertyChanged)obj).PropertyChanged += PropertyChanged_ViewModel;
}
}
}
在这里,我只是复制一些与您的问题相关的方法。从这些方法中,您可以发现在更新TextBlock
或PropertyChanged
侦听器之前,它会检查ViewModel
是否null
。如果null
,什么都不会做。因此,为了使 {x:Bind} 工作,我们必须在页面加载之前初始化ViewModel
。这就是为什么 {x:Bind} 在事件中初始化ViewModel
时不起作用的原因Button.Click
。
要解决此问题,您可以像 Filip 所说的那样为ViewModel
实现INotifyPropertyChanged
接口,以便在ViewModel
更改(从 null
到 new ViewModel()
)时通知生成的代码并更新您的 UI。
但我认为您可以在构造函数中初始化ViewModel
。初始化 ViewModel
时,可以设置等待null
的属性,如下所示:
public MainPage()
{
ViewModel = new ViewModel() { Text = null };
this.InitializeComponent();
}
然后在日期准备就绪时更新这些属性。这样,您就不会在页面上实现INotifyPropertyChanged
接口。
除此之外,还有另一种更便宜的方法,您可以调用this.Bindings.Update();
方法在初始化后强制更新绑定ViewModel
如下所示:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel();
ViewModel.Text = "x:Bind does not work";
this.Bindings.Update();
}
您是否像这样在页面上实现了INotifyPropertyChanged
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private ViewModel viewModel;
public ViewModel ViewModel
{
get { return viewModel; }
set
{
viewModel = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViewModel)));
}
}
public MainPage()
{
ViewModel = new ViewModel { };
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel { };//this line has been added
ViewModel.Text = "x:Bind does not work";
}
public event PropertyChangedEventHandler PropertyChanged;
}
这对我有用。