2

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

4

1 回答 1

3

绑定不起作用的主要问题是您不应该Source在此处设置绑定的属性:

tb.SetBinding(
  TextBlock.TextProperty, 
  new Binding { 
    Source = t.HeaderText, 
    Mode = BindingMode.TwoWay, 
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
  });

因为这样做基本上是告诉绑定引擎观察在t.HeaderText创建绑定时的字符串实例,这很可能是空的,并且不能更改,因为它string是不可观察的。

您需要执行以下操作:

tb.SetBinding(
  TextBlock.TextProperty,
  new Binding { 
    Path = new PropertyPath("CreateModel.HeaderText"), 
    Mode = BindingMode.TwoWay, 
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
  });

这将指示绑定引擎在被添加到DataContext时设置当前的 类型。TextBlockgridLayoutTestViewModel

您也不需要这一行:

grid.SetBinding(
  Grid.DataContextProperty, 
  new Binding { 
    Source = DataContext, 
    Mode = BindingMode.TwoWay 
  });

因为这是由框架自动完成的。

您还应该小心在已更改的 DataContext 上创建 UI 而不要清除它,其中:

gridlayout.Children.Add(grid);

将不断向TextBlock中添加实例gridLayout,而不删除以前的实例。

最后,您不应该以这种方式引发事件更改:

set { 
    _createModel = value;
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(5000);
        RaisePropertyChanged("CreateModel");

    });
}

因为您将从非 UI 线程引发,并会导致异常。确保改为使用Dispatcher.RunAsync

于 2020-05-10T00:38:48.180 回答