Уведомить пользователя о том, что команда не может быть выполнена

#c# #wpf #mvvm #canexecute

#c# #wpf #mvvm #canexecute

Вопрос:

У меня есть текстовое поле, которое привязано к такой команде:

 <TextBox Text="{Binding Path=TextContent, UpdateSourceTrigger=PropertyChanged}">
        <TextBox.InputBindings>
            <KeyBinding Command="{Binding Path=MyCommand}" Key="Enter" />
        </TextBox.InputBindings>
</TextBox>
  

Свойство TextContent представляет собой строку, определенную в ViewModel. Команда MyCommand также определена в ViewModel . ViewModel не знает представления.

Команда будет вызываться всякий раз, когда текстовое поле находится в фокусе и нажата клавиша ввода. К сожалению, если CanExecute возвращает false , пользователь не может видеть (визуально), что команда не была выполнена, потому что в текстовом поле нет визуальных изменений.

Я ищу совет о том, как показать пользователю, что команда не может быть выполнена после того, как он нажал enter.

Мои идеи (и мои сомнения по поводу них):

  • Отключение текстового поля при CanExecute возврате false : это не вариант, потому что возвращаемое значение CanExecute может меняться каждый раз, когда вводится / изменяется буква (текст в текстовом поле влияет на результат CanExecute ). Когда он отключен в первый раз, пользователь больше не может вводить в него, поэтому он останется отключенным навсегда.

  • Показать окно сообщения о том, что команда не была выполнена: Помните, ViewModel не знает представления. Возможно ли вообще открыть окно сообщения из ViewModel?Кроме того, куда я должен поместить вызов для открытия окна сообщения? Не внутри CanExecute , потому что я хочу получать окно сообщения только после нажатия enter, а не при каждом CanExecute возврате false . Возможно, CanExecute всегда возвращайте true и выполняйте проверки внутри Execute : если проверки в порядке, выполните команду, если нет, покажите какое-либо сообщение пользователю. Но тогда смысл наличия CanExecute полностью пропущен…

Я хочу сохранить MVVM, но мне кажется, что какой-то код для перенаправления содержимого в ViewModel подходит.

Комментарии:

1. Что касается отображения окон сообщений из View Model , вы можете использовать сервис -ориентированный подход, в котором вы можете ввести класс обслуживания окна сообщений, который может использоваться вашей моделью представления для отображения окон сообщений. Это гарантирует, что ваша модель представления остается верной шаблону MVVM. Я написал небольшую библиотеку, которая делает это на GitHub .

Ответ №1:

Я предлагаю следующее решение.

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

Я хочу, чтобы пользователь ввел ограничение данных типа int, double или string. Он хочет проверить, чтобы пользователь ввел правильный тип. Я использую свойство ValidateLimits, которое проверяет строку MyLimits, которая в вашем случае является textContent .

Каждый раз, когда пользователь вводит что-либо в текстовое поле, ValidateLimits проверяет строку. Если это недопустимая строка в текстовом поле, верните false, в противном случае верните true. Если false, то выделите его с помощью DataTrigger, установив некоторые свойства в текстовом поле, которое в моем случае представляет собой некоторые цвета границы и переднего плана, а также всплывающую подсказку.

Также в вашем случае вы хотите вызвать свой метод Validate в своем методе CanExecute.

Если у вас уже есть функция для проверки того, что команда в порядке, просто добавьте ее в привязку DataTrigger.

 <TextBox Text="{Binding MyLimit1, UpdateSourceTrigger=PropertyChanged}" Margin="-6,0,-6,0">
  <TextBox.Style>
    <Style TargetType="TextBox">
     <!-- Properties that needs to be changed with the data trigger cannot be set outside the style. Default values needs to be set inside the style -->
     <Setter Property="ToolTip" Value="{Binding FriendlyCompareRule}"/>
       <Style.Triggers>
         <DataTrigger Binding="{Binding ValidateLimits}" Value="false">
           <Setter Property="Foreground" Value="Red"/>
           <Setter Property="BorderBrush" Value="Red"/>
           <Setter Property="BorderThickness" Value="2"/>
           <Setter Property="ToolTip" Value="Cannot parse value to correct data type"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </TextBox.Style>
  

 public bool ValidateLimits
{
  get
  {
    // Check if MyLimit1 is correct data type
    return true/false;
  }
}
  

Ответ №2:

Используйте свойство bool IsCommandExecuted в своем Command классе. Установите это свойство соответствующим образом.

Используйте a ToolTip и привяжите его IsOpen свойство к IsCommandExecuted свойству следующим образом :

 <TextBox ...>
    <TextBox.ToolTip>
        <ToolTip IsOpen="{Binding MyCommand.IsCommandExecuted}">...</ToolTip>
    </TextBox.ToolTip>
</TextBox>
  

Это объясняет концепцию, измените ее соответствующим образом.