uwp - RaisePropertychanged 为 null,datacontext 改变后不通知属性

标签 uwp uno-platform winui

我有一个主页,我在其中调用我的用户控件。我的想法是,我有一个 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/

相关文章:

c# - UWP 引用问题 SQLite

c# - 如何检查电子邮件是否已存在于数据库中并将数据发送到 UWP

c# - 如何让我的 UWP 应用程序像 Microsoft UWP 应用程序(邮件、Groove 音乐)一样快?

c# - 在 Uno 平台上合并音频和视频

asp.net - ASP.NET 中的 UWP API

xaml - 如何在 (Uno 2.4) 中使用 Microsoft.UI.Xaml.Controls 资源

material-design - Uno平台 Material 卡使用Pathicon

c# - 如何使用 WinUI 3 添加桌面通知?

UWP/WinUI 桌面应用访问 Azure Key Vault secret