SetBinding не регистрируется на событие PropertyChanged

В приложении, над которым я работаю, я программно создаю несколько FrameworkElements с разными источниками данных. К сожалению, привязка данных не работает.

Мне удалось перегнать проблему в следующую программу:

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace TestBinding
{
    public class BindingSource : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }


        private string _text = "Initial Text";
        public string Text
        {
            get { return _text; }
            set { SetField(ref _text, value); }
        }
    }

    public sealed partial class MainPage : Page
    {
        BindingSource bs = new BindingSource();

        public MainPage()
        {
            this.InitializeComponent();

            TextBlock tb = new TextBlock();
            tb.HorizontalAlignment = HorizontalAlignment.Center;
            tb.VerticalAlignment = VerticalAlignment.Center;
            tb.FontSize = 36;

            Binding bind = new Binding() { Source = bs.Text, Mode=BindingMode.OneWay, UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged };
            tb.SetBinding(TextBlock.TextProperty, bind);

            Patergrid.Children.Add(tb);
        }

        private void ClickText1(object sender, RoutedEventArgs e)
        {
            bs.Text = "First text button clicked!";
        }

        private void ClickText2(object sender, RoutedEventArgs e)
        {
            bs.Text = "Second text button stroked!";
        }
    }
}

И вот xaml:

<Page
    x:Class="TestBinding.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestBinding"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid x:Name="Patergrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Text 1" Margin="25" HorizontalAlignment="Center" Click="ClickText1" />
            <Button Content="Text 2" Margin="25" HorizontalAlignment="Center" Click="ClickText2" />
        </StackPanel>
    </Grid>
</Page>

Пошагово выполняя код при изменении свойств, я вижу, что нет подписчиков на событие PropertyChanged.

Почему SetBinding не регистрируется для события PropertyChanged?


person Benjamin Chambers    schedule 23.07.2015    source источник


Ответы (1)


Вместо этого вы хотите:

Binding bind = new Binding()
{
    Source = bs,
    Path = new PropertyPath("Text"),
    Mode = BindingMode.TwoWay,
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};

Здесь, похоже, две проблемы:

  1. Код, который вы публикуете, пытается использовать объект string, возвращаемый свойством bs.Text, который не является наблюдаемым источником привязки. Система привязки достаточно гибкая, чтобы скопировать значение один раз, но после этого у нее нет возможности узнать, что объект изменился (даже если это возможно, и string является неизменяемым типом, поэтому объект все равно никогда не изменится).

Вместо этого вы хотите выполнить привязку к самому объекту BindingSource в качестве источника, используя свойство Text в качестве пути.

  1. Кроме того, нет смысла комбинировать BindingMode.OneWay с какими-то специфическими настройками для UpdateSourceTrigger. Когда режим привязки является односторонним, источник никогда не обновляется, поэтому не имеет значения, что является триггером.

Использование BindingMode.TwoWay позволит скопировать изменения в свойстве TextBlock.Text обратно в источник.

В качестве альтернативы просто не беспокойтесь о настройке UpdateSourceTrigger. В любом случае TextBlock не редактируется пользователем, поэтому, возможно, вы действительно хотели, чтобы привязка была односторонней, и просто оставили постороннюю инициализацию UpdateSourceTrigger из чего-то другого. Из вашего вопроса трудно понять, какая реализация подходит для ваших нужд.

person Peter Duniho    schedule 23.07.2015
comment
Я добавил UpdateSourceTrigger в качестве еще одного ответа, рекомендованного SO. Это не помогло, и это не имеет отношения к моим потребностям, поэтому я удалю это. - person Benjamin Chambers; 23.07.2015