Есть ли способ получить UpdateSourceTrigger = PropertyChanged для скомпилированных привязок? - PullRequest
1 голос
/ 21 апреля 2019

Я работаю над приложением UWP и понял, что режим UpdateSourceTrigger по умолчанию для элемента управления TextBox, который является LostFocus, не может быть изменен при использовании скомпилированной привязки.

Это означает, что всякий раз, когда я хочу обновить привязку для TextBox, я должен использовать все эти повторяющиеся шаблоны:

<TextBox
    Text="{x:Bind ViewModel.Title, Mode=TwoWay}"
    TextChanged="TextBox_OnTextChanged"/>
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
    ViewModel.Title = ((TextBox)sender).Text;
}

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

Это будет нормально работать с классической привязкой:

<TextBox Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

Но, конечно,здесь могут возникнуть дополнительные издержки при использовании классических привязок usinc (включая отражения во время выполнения и т.Я был бы вполне согласен, скажем, с написанием пользовательского присоединенного свойства, которое настраивает вещи, если я могу делать все, что мне нужно, прямо из XAML, без участия кода.

Спасибо!

ОБНОВЛЕНИЕ: (в ответ на Нико Чжу - ответ MSFT)

Для моего тестирования это работает хорошо.

Это вообще не для меня, как я уже говорил несколько раз, использование UpdateSourceTrigger с x:Bind просто невозможно .Он не компилируется, свойство отображается красным цветом в редакторе XAML, просто его там нет.Я действительно не знаю, где вы пытаетесь это сделать, если вы говорите, что это работает для вас.В настоящее время я нацеливаюсь как минимум на 17763, и я могу на 100% гарантировать, что это работает , а не .

Скомпилированное связывание используется с синтаксисом {x: Bind} в отличие отсинтаксис {Binding} классической привязки.

Я хорошо знаю разницу, я уже упоминал об этом несколько раз, как в моем первоначальном вопросе здесь (также с фрагментами кода), а такжекак в моих комментариях.

Он по-прежнему использует уведомляющие интерфейсы (например, INotifyPropertyChanged) для отслеживания изменений

Как я уже сказал, я тоже об этом знаю.Но опять же, как и из этого вопроса, это не проблема здесь вообще.Проблема заключается в не с обновлениями от модели представления до связанного свойства, но с связанного свойства (в данном случае TextBox.Text) до viewmodel.

{x:Bind} по умолчанию OneTime по сравнению с {Binding}, который является OneWay.поэтому вам нужно объявить режим связывания OneWay или TwoWay для {x: Bind}.

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

И снова, это был , а не , о чем вообще был вопрос.

Повторюсь: проблема здесь в том, что свойство TextBox.Text по умолчанию имеет триггер LostFocus, и что UpdateSourceTrigger свойство не доступно для скомпилированных привязок.Поэтому я хотел бы знать, есть ли способ добиться того же с помощью скомпилированной привязки, только в XAML, без необходимости вручную создавать обработчик TextChanged каждый раз (и если нет, если вы планируете в конечном итоге добавитьсвойство UpdateSourceTrigger также для скомпилированных привязок).

Примечание: я не хотел показаться здесь неуважительным, и я надеюсь, что мы теперь разрешили существующие недоразумения с моим вопросом.

UPDATE # 2: выясняет, что проблема была вызвана плагином ReSharper, который помечал свойство UpdateSourceTrigger как ошибку в скомпилированных привязках.Я открыл для этого вопрос здесь: https://youtrack.jetbrains.com/issue/RSRP-474438

1 Ответ

0 голосов
/ 22 апреля 2019

Пожалуйста, проверьте документацию UpdateSourceTrigger.

Значение UpdateSourceTrigger по умолчанию равно Default.И используя поведение по умолчанию из свойства зависимости, которое использует привязку.В среде выполнения Windows он оценивается так же, как значение со значением PropertyChanged.Если вы использовали Text="{x:Bind ViewModel.Title, Mode=TwoWay}", Заголовок будет изменен при изменении текста.нам не нужно изменять режим просмотра в TextChanged даже обработчике.

Предполагается, что нам нужно реализовать INotifyPropertyChanged, как показано ниже.

public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set
        {
            this.nextButtonText = value;
            this.OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Для получения более подробной информации см. Глубина привязки данных документ.

Обновление

<TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> не компилируется вообще, как я уже говорил, свойство UpdateSourceTriggerнедоступно при использовании скомпилированной привязки.

Для моего тестирования это работает хорошо.Скомпилированное связывание используется с синтаксисом {x:Bind} в отличие от синтаксиса {Binding} классического связывания.Он по-прежнему использует уведомляющие интерфейсы (например, INotifyPropertyChanged) для отслеживания изменений, но {x:Bind} по умолчанию является OneTime по сравнению с {Binding}, который является OneWay.поэтому вам нужно объявить bind Mode OneWay или TwoWay для {x:Bind}.

Xaml

<StackPanel Orientation="Vertical">
    <TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock Text="{x:Bind Title, Mode=OneWay}" /> <!--declare bind mode-->
</StackPanel>

Код позади

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _title;
public string Title
{
    get
    {
        return _title;
    }
    set
    {
        _title = value;
        OnPropertyChanged();
    }
}
...