WPF, как правильно привязать значение к TextBox с шаблоном MVVM

В настоящее время я экспериментирую с WPF. Я создал демонстрационный проект с помощью Windows Template Studio для Visual Studio.

Теперь я хочу добавить текстовое поле, которое должно автоматически сохраняться шаблоном MVVM. Я добавил следующий XAML на свою страницу настроек.

<TextBlock
   Style = "{StaticResource BodyTextStyle}"
   Text = "Default Page" />
<TextBox Text = "{Binding DefaultPage}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName = "TextChanged">
            <i:InvokeCommandAction Command = "{Binding SetDefaultPageCommand}" CommandParameter = "{Binding DefaultPage}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

В SettingsViewModel я добавил следующие строки:

private readonly IDefaultPageService _defaultPageService;
private string _defaultPage;
public ICommand SetDefaultPageCommand => _setDefaultPageCommand ?? (_setDefaultPageCommand = new RelayCommand<string>(OnSetDefaultPage));

public string DefaultPage
{
    get { return _defaultPage; }
    set { Set(ref _defaultPage , value); }
}

private void OnSetDefaultPage(string defaultPage)
{
    _defaultPageService.SetDefaultPage(defaultPage);
}

Сервис для сохранения реализован как:

public class DefaultPageService : IDefaultPageService
{
    public DefaultPageService()
    {
    }

    public void InitializeDefaultPage()
    {
        var theme = GetDefaultPage();
        SetDefaultPage(theme);
    }

    public void SetDefaultPage(string defaultPage)
    {
        App.Current.Properties["DefaultPage"] = defaultPage.ToString();
    }

    public string GetDefaultPage()
    {
        if (App.Current.Properties.Contains("DefaultPage"))
        {
            var defaultPage = App.Current.Properties["DefaultPage"].ToString();
            return defaultPage;
        }

        return "https://google.com";
    }

}

Сохранение моей новой строки работает, но, к сожалению, моя команда вызывается до того, как фактическое связанное свойство изменило свое значение. Я уже перепробовал кучу различных событий TextBox, таких как KeyUp и KeyDown. Единственное событие, которое, как я обнаружил, работает, это LayoutUpdated, но оно снова и снова запускается графическим интерфейсом, поэтому я почти уверен, что есть лучший способ.

Кто-нибудь знает, как я могу это исправить?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
502
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поведение привязки TextBox по умолчанию заключается в обновлении привязки после того, как TextBox теряет фокус, поэтому ваше связанное свойство изменяется только ПОСЛЕ того, как пользователь вводит, а затем выполняет любое действие для потери фокуса на TextBox. Вы, очевидно, не можете использовать событие TextChanged, потому что оно будет срабатывать при каждом нажатии клавиши.

Лучший способ сохранить ваш MVVM и полагаться на то, что ограничивающее свойство изменится в первую очередь, — это полностью избавиться от вашего EventTrigger и вашего ICommand и просто воспользоваться преимуществами, когда вызывается ваш установщик DefaultPage.

В вашей SettingsViewModel:

private readonly IDefaultPageService _defaultPageService;
private string _defaultPage;

public string DefaultPage
{
    get { return _defaultPage; }
    set { Set(ref _defaultPage , value); OnSetDefaultPage(_defaultPage); }
}

private void OnSetDefaultPage(string defaultPage)
{
    _defaultPageService.SetDefaultPage(defaultPage);
}

Добавить вариант привязки

UpdateSourceTrigger=PropertyChanged

<TextBox Text = "{Binding DefaultPage, UpdateSourceTrigger=PropertyChanged}"/>
And setter

Вы можете получить значение, когда значение textBox изменилось.

class ViewModel
{
    private string _defaultPage;
    public string DefaultPage
    {
        get { return _DefaultPage; }
        set { _DefaultPage = value; OpPropertyChanged(); DefaultPageChanged(value); }
    }

    private void DefaultPageChanged(string v)
    {
        // Service some...
    }
}

Другие вопросы по теме