Raise属性changed 为 null,并且在数据上下文更改后不通知 属性
Raisepropertychanged is null and does not notify the property after datacontext changed
我有一个主页面,我在其中调用我的用户控件。我的想法是,我有一个 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>
测试视图模型:
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 中。
此处绑定不起作用的主要问题是您不应在此处设置绑定的 Source
属性:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Source = t.HeaderText,
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
这样做基本上是告诉绑定引擎在创建绑定时观察 t.HeaderText
中的字符串实例,它很可能为 null,并且不能更改 string
不可观察。
您需要执行以下操作:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Path = new PropertyPath("CreateModel.HeaderText"),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
当 TextBlock
添加到 TestViewModel
.[=26= 类型时,这将指示绑定引擎使用当前 DataContext
]
你也不需要这一行:
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
。
我有一个主页面,我在其中调用我的用户控件。我的想法是,我有一个 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>
测试视图模型:
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 中。
此处绑定不起作用的主要问题是您不应在此处设置绑定的 Source
属性:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Source = t.HeaderText,
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
这样做基本上是告诉绑定引擎在创建绑定时观察 t.HeaderText
中的字符串实例,它很可能为 null,并且不能更改 string
不可观察。
您需要执行以下操作:
tb.SetBinding(
TextBlock.TextProperty,
new Binding {
Path = new PropertyPath("CreateModel.HeaderText"),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
当 TextBlock
添加到 TestViewModel
.[=26= 类型时,这将指示绑定引擎使用当前 DataContext
]
你也不需要这一行:
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
。