У меня есть Button как аксессуар в моем TabControl, где находится 5 TabItem. Эта кнопка копирует другой объект, используемый в вкладках. Каждый TabItem имеет CustomView (где все его компоненты находятся, TextView, TextBox и т.д.). Я хочу иметь возможность реализовать другую функциональность для этой кнопки для каждой вкладки в одной команде, поэтому я внедрил общую команду копирования, которая проверяет текущий вкладка, чтобы увидеть, что мы в настоящее время находимся на какой вкладке, но теперь лучший способ справиться с моими не может выполнить условия без повторения моего случая переключения в методе "Условия"? Например, первая кнопка закладки не может быть выполнена (отключена), если ее объект равен нулю, вторая кнопка вкладки не может быть выполнена, когда ее объект имеет значение null.
Первая вкладка "Пользователи" имеет CustomerView
Вторая вкладка "Активность" имеет ActivityView
Код:
public RelayCommandWithCannotExecuteReason Copy
{
get
{
if (_copy == null)
{
_copy = new RelayCommandWithCannotExecuteReason(
x =>
{
switch (SelectedTabIndex) {
case 1:
Clipboard.SetData("First", object1);
break;
case 2:
Clipboard.SetData("Second", object2;
break;
}
}, CanCopyConditions);
}
return _copy;
}
}
Почему бы не подклассифицировать тип RelayCommandWithCannotExecuteReason
и создать выделенный объект команды? Вся эта логика содержится в команде, и все, что вы делаете, - это создание нескольких команд во всех ваших моделях.
Нет ничего плохого в создании выделенного командного класса для обработки специфической логики VM, что и делают программисты. Создание конкретной реализации абстракции, такой как ICommand
или ваш RelayCommandWithCannotExecuteReason
является SOLID.
public class CopyCommand : RelayCommandWithCannotExecuteReason
{
ViewModel _vm;
public CopyCommand( ViewModel vm)
{
_vm = vm;
}
public void Execute(object parameter)
{
switch (_vm.SelectedTabIndex)
{
case 1:
_vm.Clipboard.SetData("First", object1);
break;
case 2:
_vm.Clipboard.SetData("Second", object2;
break;
}
}
public bool CanExecute(object parameter)
{
return true;
}
}
Теперь вы используете эту команду в своей виртуальной машине. Есть много простых способов, вот пример, похожий на то, как у вас есть это сейчас...
public CopyCommand Copy
{
get
{
if (_copy == null)
{
_copy = new CopyCommand(this);
}
return _copy;
}
Или создайте экземпляр в конструкторе или инициализаторе основной виртуальной машины:
public ViewModel() //constructor
{
_copy = new CopyCommand(this);
}
public CopyCommand Copy
{
get
{
return _copy;
}
}
Если у вас есть экземпляр модели просмотра для каждой вкладки, и вы хотите делегировать логику CanExecute() на "SelectedTab", вам понадобится что-то вроде этого:
Предположим, что все ваши модели представлений наследуют базовый класс, подобный этому:
public abstract class BaseTabViewModel
{
public abstract bool CanCopy();
}
Затем вы будете подклассифицировать этот базовый класс в моделях просмотра вкладок. Вы бы выполнили абстракцию:
public class Tab1ViewModel : BaseTabViewModel
{
…
public override bool CanCopy(){
//custom logic....
return true;
}
Теперь нам нужно изменить порядок CopyCommand для ссылки на абстракцию, я изначально закодировал эту команду для использования ViewModel
, теперь мы вместо этого определим тип как абстракцию. Поэтому измените класс ViewModel:
public class CopyCommand : RelayCommandWithCannotExecuteReason
{
BaseTabViewModel _vm;
public CopyCommand( BaseTabViewModel vm)
{
_vm = vm;
}
Теперь метод CanExecute() может вызвать соответствующую логику:
public bool CanExecute(object parameter)
{
return _vm.CanCopy();
}
Это работает только в том случае, если:
BaseTabViewModel
являются экземплярами типа BaseTabViewModel
.Этот механизм намного более OO и более гибкий. Удачи.