Включить кнопку «Отключить сохранение» во время проверки с использованием IDataErrorInfo и состояния кнопки обновления

Я новичок в WPF MVVM и хотел задать дополнительный вопрос к этой статье: Включить кнопку «Отключить сохранение» во время проверки с помощью IDataErrorInfo Я пытаюсь включить/отключить кнопку сохранения/обновления, если какой-либо из многих элементов управления при проверке формы не прошел/прошел. У меня есть метод IsValid, который проверяет логику проверки модели и возвращает значение True/False, которое будет передано в DelegateCommand в качестве предиката. Вопрос в следующем: моя кнопка имеет следующее свойство IsEnabled{binding IsValid}, это должно проверять все поля, чтобы убедиться, что они соответствуют критериям в модели, возвращает true/false в модель представления, а затем включает кнопку, если все верно. Проблема в том, что после создания экземпляра модели представления объект DelegateCommand создается с проверкой (IsValid) в ложном состоянии и остается таким на протяжении всего жизненного цикла объекта, даже если пользователь заполняет данные в текстовых полях. Как включить кнопку после выполнения всех условий? другими словами, как постоянно проверять и обновлять IsValid, чтобы включать кнопку после подтверждения каждого текстового поля значением true??

Спасибо,

У меня есть следующий код: Модель

public class UserModel : ObservePropertyChanged,IDataErrorInfo
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }
        // if there is an error throw an exception
        public string Error
        {
            get { throw new NotImplementedException(); }
        }
        public string this[string columnName]
        {
            get
            {
                string result = null;
                if (columnName == "Name")
                {
                    if (string.IsNullOrEmpty(Name))
                        result = "Please enter a Name";
                }
                return result;
            }
        }

        // the Josh Way
        static readonly string[] ValidatedProperties =
        {
            "Name"
        };

        public bool IsValid
        {
            get
            {
                foreach (string property in ValidatedProperties)
                {

                    if (GetValidationError(property) != null) // there is an error
                        return false;
                }
                return true;
            }
        }

        // a method that checks validation error
        private string GetValidationError(string propertyName)
        {
            string error = null;

            switch (propertyName)
            {
                case "Name":
                    error = this.ValidateName();
                    break;

                default:
                    error = null;
                    throw new Exception("Unexpected property being validated on Service");
            }
            return error;
        }
        private string ValidateName()
        {
            string ErrorMsg = null;
            if (string.IsNullOrWhiteSpace(Name))
            {
                ErrorMsg = "Name can't be empty!";
            };
            return ErrorMsg;
        }
}

** Модель просмотра **

public class UserViewModel:ObservePropertyChanged
    {
        UserModel model;
        public UserViewModel()
        {
            presentCommand = new DelegateCommand(param => PresentDataMethod(), param => CanSave);
            model = new UserModel();
        }

        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }
        private string info;

        public string Info
        {
            get { return info; }
            set { info = value; OnPropertyChanged("Info"); }
        }
        private DelegateCommand presentCommand;

        public DelegateCommand PresentCommand
        {
            get 
            {
                if (presentCommand==null)
                {
                    presentCommand = new DelegateCommand(param => PresentDataMethod(), param => CanSave);
                }
                return presentCommand; 
            }
        }
        private void PresentDataMethod() 
        {
            Info = $"Your Name is: {Name}.";
        }

        // The ViewModel then contains a CanSave Property that reads the IsValid property on the Model:
        protected bool CanSave
        {
            get
            {
                return model.IsValid;
            }
        }
    }

** Вид**

<TextBox x:Name = "Name" HorizontalAlignment = "Left" Height = "34" Margin = "285,145,0,0" TextWrapping = "Wrap" 
                 VerticalAlignment = "Top" Width = "248">
            <Binding Path = "Name" 
                     ValidatesOnDataErrors = "True" 
                     UpdateSourceTrigger = "PropertyChanged" 
                     Mode = "TwoWay">
            </Binding>
        </TextBox>
        <Button Content = "Present" FontSize = "20" HorizontalAlignment = "Left" 
                Margin = "285,184,0,0" VerticalAlignment = "Top" Width = "248" Height = "35"
                Command = "{Binding Path=PresentCommand}"
                IsEnabled = "{Binding IsValid}"
                >
        </Button>

Разве UserViewModel не нужно свойство IsValid, чтобы удовлетворить ваше выражение привязки для IsEnabled?

Jason Tyler 14.12.2020 20:32
Стоит ли изучать 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
1
198
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Если все, что вы хотите сделать, это обновить кнопку с помощью значения IsValid, все, что вам нужно сделать, это прослушать любые изменения ДРУГИХ свойств в вашей ViewModel, и когда это произойдет, скажите ему также обновить привязку IsValid (что на самом деле ваша CanSave собственность). Вот один из способов сделать это:

** Модель просмотра **

// ...

public UserViewModel()
{
    // ...
    this.PropertyChanged += OnViewModelPropertyChanged;
}

public void OnViewModelPropertyChanged(object sender, PropertyEventArgs e)
{
    // On any property that implements "OnPropertyChanged(propname)", refresh the CanSave binding too!
    OnPropertyChanged(nameof(this.CanSave));
}

// ...

Кстати, в целом хорошей практикой кодирования является избегание волшебных слов, таких как OnPropertyChanged("Name") или OnPropertyChanged("Info"), потому что вы никогда не знаете, когда разработчику придется переименовывать свои свойства, и если это произойдет, вы не получите здесь ошибку компиляции, и это может быть трудно отлаживать. Лучше всего использовать nameof, например OnPropertyChanged(nameof(Name)), чтобы вы знали, что получите ошибку компиляции, если когда-нибудь решите изменить свойство, скажем, на FirstName вместо Name.

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