У меня есть элемент управления Custom Textbox, который работает нормально.
public class TextBoxExt : TextBox
{
public event ehEmptyArgument ClearAll, Save;
public TextBoxExt()
{
SetResourceReference(StyleProperty, typeof(TextBoxExt));
SetValue(FocusNextControlProperty, true);
}
#region FocusNextControl
public static DependencyProperty FocusNextControlProperty =
DependencyProperty.Register("FocusNextControl", typeof(bool), typeof(TextBoxExt),
new PropertyMetadata(true, new PropertyChangedCallback(OnFocusNextControl)));
public bool FocusNextControl
{
get => Convert.ToBoolean(GetValue(FocusNextControlProperty));
set => SetValue(FocusNextControlProperty, value);
}
static void OnFocusNextControl(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBoxExt dt = d as TextBoxExt;
dt.FocusNextControl = Convert.ToBoolean(e.NewValue);
}
#endregion
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (FocusNextControl) UI.ProcessTabKey(true);
else Save?.Invoke();
}
else if (e.Key == Key.Escape) ClearAll?.Invoke();
base.OnKeyUp(e);
}
}
Здесь, как вы можете видеть, Save & ClearAll — это события, которые вызываются Key Pressed и обрабатываются в коде C# для XAML Form.
Сейчас я полностью перехожу на ViewModel и хочу избежать написания кода в XAML C# файле.
Как я могу этого добиться?
Дополнительная информация для ясного понимания на основе запросов в комментариях
Я также создал собственные элементы управления, такие как ComboboxExt, DateTextBox, NumericTextBox и т. д. с той же функциональностью.
Все они используются в форме ввода данных, поэтому пользователям не нужно использовать мышь или клавиши табуляции для нажатия кнопки.
Событие сохранения запускается при последнем элементе управления всей формой, чтобы сообщить коду, что пользователь завершил ввод всех данных, а проверка и обновление выполняются в ViewModel
Событие Clear запускается, когда пользователь нажимает escape key, чтобы отменить любые изменения, внесенные пользователем, а также закрыть форму. Это также обрабатывается в ViewModel
Здесь они помогли быстро ввести данные, не прикасаясь снова и снова к мыши.





Сделать пользовательские элементы управления WPF дружественными к MVVM очень легко. Все, что вам нужно сделать, это создать ICommand-типизированные DependencyProperty и вместо вызова event вызвать ICommand.Execute:
#region ICommand SaveCommand dependency property
public static DependencyProperty SaveCommandProperty = DependencyProperty.Register(
"SaveCommand",
typeof(ICommand),
typeof(TextBoxExt),
new PropertyMetadata((ICommand)null));
public ICommand SaveCommand
{
get
{
return (ICommand)GetValue(SaveCommandProperty);
}
set
{
SetValue(SaveCommandProperty, value);
}
}
#endregion
#region ICommand ClearAllCommand dependency property
public static DependencyProperty ClearAllCommandProperty = DependencyProperty.Register(
"ClearAllCommand",
typeof(ICommand),
typeof(TextBoxExt),
new PropertyMetadata((ICommand)null));
public ICommand ClearAllCommand
{
get
{
return (ICommand)GetValue(ClearAllCommandProperty);
}
set
{
SetValue(ClearAllCommandProperty, value);
}
}
#endregion
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (FocusNextControl)
UI.ProcessTabKey(true);
else
this.SaveCommand?.Execute(null);
}
else if (e.Key == Key.Escape)
this.ClearAllCommand?.Execute(null);
base.OnKeyUp(e);
}
Затем в XAML вы можете привязываться к этим свойствам точно так же, как вы можете привязываться к Button.Command и т. д. Если вам нужно передать команде дополнительную информацию, вы всегда можете определить типы аргументов для конкретного приложения в общей сборке и передать их в ваши модели представлений в качестве аргумента для Execute.
Хотя это отлично работает для ваших собственных пользовательских элементов управления, знайте, что вы также можете использовать аналогичный метод с любым элементом управления, используя прикрепленный шаблон команды, как я описываю здесь: Назначает функцию PreviewTextInput в Texbox, сохраняя шаблон WPF.
Я также хочу решить, подходят ли подобные события для обработки с помощью связанных команд в модели представления. Правда в том, что не существует жесткого и быстрого правила, определяющего, является ли абстрактная логика достаточно «связанной с пользовательским интерфейсом», чтобы она принадлежала к специфичному для платформы представлению или модели представления, независимой от платформы. Часто концептуальная линия размыта, и те, кто пытается дать вам здесь совет, не могут предложить никакого действующего стандарта, кроме «Я так говорю».
Единственный объективный, черно-белый стандарт, которому я рекомендую вам следовать, заключается в следующем: если логика может быть выражена с относительной легкостью и элегантностью в модели представления, независимой от каких-либо типов или кода, специфичных для WPF (или другой платформы), тогда она принадлежит именно этому. . И наоборот, если у вас есть логика, специфичная для пользовательского интерфейса, которая выходит за рамки какого-либо одного приложения и/или сильно зависит от особенностей платформы (например, WPF), то ее, вероятно, лучше всего реализовать с помощью представления. Если интересно, я могу сказать обо всем этом больше здесь: В MVVM допустимо ли получать доступ к ViewModel в коде представления?.
Тем не менее, с помощью умных приемов, таких как интерфейсы и внедрение зависимостей, можно обрабатывать практически всю логику пользовательского интерфейса независимым от платформы, но слишком сложным способом и, таким образом, зайти в этом совете слишком далеко. (Я виновен в этом, когда впервые узнал о шаблоне MVVM 10 лет назад). Вопрос, который следует задать: боретесь ли вы с течением и закручиваете себя в логические узлы, просто чтобы попытаться скрыть код? Вы тратите гораздо больше времени на создание индивидуальных интерфейсов и присоединенных команд, чем при более простом подходе, специфичном для конкретной платформы? Если да, то, возможно, вам стоит переосмыслить ситуацию.
Но я не вижу здесь никакой опасности. Решение на основе модели представления простое и элегантное, а внесение изменений в ваши настройки TextBox просто. Поскольку вы используете настраиваемый элемент управления (что, кстати, здорово), теперь у вас есть дружественный к MVVM компонент пользовательского интерфейса, который можно повторно использовать во всех ваших приложениях WPF, поскольку он не привязан к специфике вашего приложения. И если вы когда-нибудь захотите перенести свое приложение на другую платформу, поскольку вы избежали беспорядочного одноцелевого кода программной части .xaml.cs, вам придется заменить гораздо меньше кода, специфичного для платформы. Это совершенно правильный способ практиковать MVVM и максимизировать ценность каждой строки кода, что, в конце концов, является единственной причиной следовать любому шаблону проектирования.
Я ожидаю, что этот ответ получит как минимум пару отрицательных голосов, потому что по какой-то причине прагматичный подход, который я отстаиваю, не популярен на этом сайте. Однако я предлагаю вам проигнорировать это и просто попробовать это решение и, в конечном итоге, принять собственное решение о том, как лучше всего спроектировать свое приложение. По крайней мере, по моему мнению, ваши инстинкты и путь, по которому вы идете, на 100% верны.