#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>
Это объясняет концепцию, измените ее соответствующим образом.