我有一个主页,我在其中调用我的用户控件。我的想法是,我有一个 TextBlock
,单击按钮后,我将更改 Hello World 名称上方的文本。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Hello, world!" Margin="20" FontSize="30" />
<local1:GenericControl></local1:GenericControl>
<Button x:Name="create" Click="clickBtn"/>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public TestViewModel viewModel { get; set; } = new TestViewModel();
public MainPage()
{
this.InitializeComponent();
this.DataContext = viewModel;
}
public void clickBtn(object sender, RoutedEventArgs e) {
var m = ((Button)sender).DataContext as TestViewModel;
m.CreateModel.HeaderText = "tripathi";
viewModel = m;
var s = new GenericControl {
DataContext = viewModel
};
}
}
下面是我从后面的代码创建的用户控件:
public GenericControl()
{
this.InitializeComponent();
//this.DataContext = this;
DataContextChanged += (s, e) =>
{
var createModel = this.DataContext as TestViewModel;
CreateControl(createModel.CreateModel);
};
}
private void CreateControl(Test t) {
var grid = new Grid();
grid.SetBinding(Grid.DataContextProperty, new Binding { Source = DataContext, Mode = BindingMode.TwoWay });
//grid.DataContext = this.DataContext;
var tb = new TextBlock();
tb.SetBinding(TextBlock.TextProperty, new Binding { Source = t.HeaderText, Mode = BindingMode.TwoWay
, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged});
grid.Children.Add(tb);
gridlayout.Children.Add(grid);
}
GenericControl.xaml:
<Grid Name="gridlayout">
</Grid>
测试 View 模型:
private Test _createModel = new Test();
private string _textHeader;
public Test CreateModel
{
get { return _createModel; }
set { _createModel = value;
Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
RaisePropertyChanged("CreateModel");
});
}
}
public TestViewModel() {
CreateModel.HeaderText = "Ankit";
CreateModel = CreateModel;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName]string prop = "")
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
型号:
private string _headerText;
public string HeaderText
{
get { return _headerText; }
set { _headerText = value;
Task.Factory.StartNew(() =>
{
Thread.Sleep(10000);
RaisePropertyChanged("HeaderText");
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName]string prop = "") {
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
我在调试时获得了正确的值,但它没有显示在 UI 中。
最佳答案
绑定(bind)不起作用的主要问题是您不应该在此处设置绑定(bind)的 Source
属性:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Source = t.HeaderText,
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
这样做基本上是告诉绑定(bind)引擎在创建绑定(bind)时观察 t.HeaderText
中的字符串实例,该实例很可能为 null,并且不能更改,因为它 string
不可观察。
您需要执行以下操作:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Path = new PropertyPath("CreateModel.HeaderText"),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
当 TextBlock
添加到 gridLayout
(类型为 )时,这将指示绑定(bind)引擎设置当前的
.DataContext
TestViewModel
您也不需要这一行:
grid.SetBinding(
Grid.DataContextProperty,
new Binding {
Source = DataContext,
Mode = BindingMode.TwoWay
});
因为这是由框架自动完成的。
您还应该小心在已更改的 DataContext 上创建 UI 并且不清除它,其中:
gridlayout.Children.Add(grid);
将不断向 gridLayout
添加 TextBlock
实例,而不删除之前的实例。
最后,您不应该以这种方式引发事件更改:
set {
_createModel = value;
Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
RaisePropertyChanged("CreateModel");
});
}
因为您将从非 UI 线程引发,并且会导致异常。确保使用Dispatcher.RunAsync
相反。
关于uwp - RaisePropertychanged 为 null,datacontext 改变后不通知属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61704658/