Можно ли обновить источник привязки вручную из целевого элемента управления в WPF? - PullRequest
0 голосов
/ 06 декабря 2010

У меня есть сценарий, для которого я предложу простой пример, чтобы проиллюстрировать это.

Допустим, я пишу пользовательский элемент управления в стиле CheckBox, который может быть проверен при возникновении определенного события. Событие может быть любым, например MouseEnter, или даже каким-либо другим событием, не относящимся к пользовательскому интерфейсу, например, когда разрывается сетевое соединение. Дело в том, что в какой-то момент мне нужно вручную установить значение в источнике привязки.

Я предполагаю, что этот тип функциональности должен быть возможен для того, чтобы элементы управления, такие как TextBox, работали, поскольку они могут работать таким образом, чтобы свойство Text могло обновляться до значений, основанных на том, что печатает клавиатура, но без очистки любая привязка, которая может существовать в свойстве Text. Поэтому я пытаюсь найти основной способ добиться этого.

Попытка # 1

Установка целевого свойства привязки (например, IsChecked), как показано ниже, приведет к очистке привязки. Так что эта опция не будет работать (ИСПРАВЛЕНИЕ! См. мой ответ ниже).

this.IsChecked = true;

или альтернативно:

this.SetValue(CheckBox.IsCheckedProperty, true);

Попытка # 2

Класс BindingBase имеет свойство ProvideValue, которое, как описано в документации MSDN «Возвращает объект, который должен быть установлен в свойстве, где применяются эта привязка и расширение». Это звучит многообещающе, поэтому я попытался реализовать свой собственный IServiceProvider двумя способами, показанными ниже.

Реализация A:

public class CheckProvider : IServiceProvider
{
    public object Value { get; set; }

    public object GetService(Type serviceType)
    {
        return Value;
    }
}

Реализация B:

public class CheckProvider : IServiceProvider
{
    public object Value { get; set; }

    public object GetService(Type serviceType)
    {
        return new ObjectProvider() { TargetObject = new TempDependencyObject() { IsSelected = Value }, TargetProperty = TempDependencyObject.IsSelectedProperty };
    }

    public class TempDependencyObject : DependencyObject
    {
        public object IsSelected
        {
            get { return (object)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(object), typeof(TempDependencyObject));
    }

    public class ObjectProvider : System.Windows.Markup.IProvideValueTarget
    {

        public object TargetObject { get; set; }

        public object TargetProperty { get; set; }
    }
}

А вот как я пытаюсь вручную обновить источник привязки, используя эти классы.

myControl.DataContext = obj;
myBinding.ProvideValue(new CheckProvider() { Value = true });

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

Ответы [ 2 ]

2 голосов
/ 06 декабря 2010

Пара вещей, вы заявили ...

TextBox для работы, так как они могут работать таким образом, что позволяет свойство Text обновляться до значений на основе чего клавиатура печатает, но без очистка любой привязки, что мой существует на свойство Text

Это происходит так, что TextBox ведет себя по отношению к UpdateSourceTrigger. По умолчанию установлено значение LostFocus. Как только LostFocus происходит, фактическое значение передается объекту, который связан с элементом управления. Если бы это было установлено как PropertyChanged, это происходило бы после каждого нажатия клавиши.

Чтобы получить желаемое поведение, вы можете установить для свойства UpdatesourceTrigger значение Explicit в вашем XAML ...

<TextBox Name="MyTextBox"
         Text="{Binding Path=FirstName, UpdateSourceTrigger=Explicit}" />

Тогда в вашем коде можно в любой момент явно обновить источник ...

BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();

Это будет связано с вашей необходимостью обновления источника, когда происходит какое-то случайное событие или когда происходит какая-то другая серия событий.

Если вы пытаетесь установить значение привязываемого свойства, внешнего по отношению к элементу управления, и ожидаете, что привязанные к свойству свойства не изменятся; это невозможно из коробки. Вам нужно будет получить свой собственный элемент управления и управлять им внутренне, выставив DependencyProperty, который может принять тип, который вы хотите обновить. Если вы заходите в VS и набираете propdp, есть фрагмент кода для DependencyProperty.

Вы бы получили что-то вроде ...

    public List<byte> Text
    {
        get { return (List<byte>)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(List<byte>), typeof(RichTextBoxExtended), new UIPropertyMetadata());

Text - это привязываемое свойство для этого пользовательского типа, которое наследуется от RichTextBox. Поэтому, если у кого-то есть экземпляр этого типа, он может вызвать само свойство для установки и изменения значения. При этом будут уведомлены все объекты, использующие это свойство и необязательно связанные с ним.

1 голос
/ 07 декабря 2010

Короткий ответ на мой вопрос - ДА!После просмотра кода для CheckBox в Reflector я понял, что в этом коде они устанавливают IsChecked непосредственно в ответ на событие Click, и он работает, как и ожидалось.Первоначально я предполагал, что это очистит лежащую в основе привязку, но вместо этого установил свойство зависимости вместо швов, чтобы сделать именно то, что я искал, в этом он устанавливает целевое значение свойства и затем обновляет источник привязки, если привязка используетРежимы привязки TwoWay или OneWayToSource.

Таким образом, чтобы быть понятными два приведенных ниже примера.

Таким образом, этот параметр должен работать для обновления свойства зависимости и, следовательно, источника привязки, который может быть установлен на этомсобственности.

this.IsChecked = true;

или альтернативно:

this.SetValue(CheckBox.IsCheckedProperty, true);

Спасибо Аарону за помощь при попытке решить эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...