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