Всем привет!
Возможно вопрос типичный. Но не дает мне покоя. Если с моделями, вроде таблиц, вопросов не возникает, то в данном случае не смог найти ответа.
Суть: дорабатываю свою программу (WPF) вышивки крестиком, возникла потребность рисования с различными его аспектами (типы, выделение и тп).
Есть примерно такой код (идею подсмотрел в FastGrid):
enum CellBlockType
{
CrossStitch,
HalfStitch,
//...
}
interface ISchemeCellBlock
{
CellBlockType BlockType { get; }
//...
}
interface ISchemeCell
{
int BlockCount { get; }
ISchemeCellBlock GetBlock(int index);
}
interface ISchemeModel
{
int RowCount { get; }
int ColumnCount { get; }
ISchemeCell GetCell(ISchemeView view, int row, int column);
void HandleCommand(ISchemeView view, CellAddress address, object commandParameter, ref bool handled);
}
interface ISchemeView
{
void InvalidateCell(int row, int column);
void InvalidateAll();
bool ShowGuideline { get; set; }
//...
}
struct CellAddress { }
В данный момент все действия мыши обрабатываются в HandleCommand
, а в качестве commandParameter
передаются MouseEvenArgs
, чтобы понимать когда рисовать/не рисовать, перемещать/вставлять и тп.
Таким образом, ISchemeView
изменяет данные модели минуя ViewModel
, но и не в коде самого представления. В самой же ViewModel
предполагается выбор "кистей рисования", масштабирование, команды ввода/вывода и все косвенные изменения модели.
Имеет ли право на жизнь такой код в рамках MVVM? Или же надо "отправлять" действия мыши из ISchemeView
во ViewModel
, а уже через нее воздействовать на саму модель?
Если вы хотите следовать паттерну MVVM, то у вас пока не получается. Model ничего не должна знать про View, а у вас знает (вы передаете ISchemeView и MouseEvenArgs)
Познакомьтесь с командами (интерфейс ICommand). Часто используются сторонние реализации типа DelegateCommand:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public override bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public override void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if( CanExecuteChanged != null )
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
Команда содержит ссылку на метод, который будет выполняться при выполнении команды, и ссылку на метод, который указывает, может ли выполниться команда.
Таким образом, во ViewModel вы создаете свойство типа ICommand, пишите методы на выполнение и выяснение возможности выполнения, привязываете команду ко View. Конечно, для View должно быть определено dependency property, которое отдаст правильный параметр с координатам в команду (это уже другой вопрос, разработка своего контрола, сейчас не знаю какой компонент у вас во View). Но во ViewModel будет что-то примерно такое:
public class SchemeViewModel : NotifyPropertyChangedBase
{
ISchemeModel _model;
public ICommand SelectCommand {get;} = new DelegateCommand(Select, CanSelect);
void Select(object o)
{
var coords = o as CellAddress;
_model.Select(coords);
}
bool CanSelect(object o)
{
var coords = o as CellAddress;
return _model.CanSelect(coords);
}
}
Также откажитесь от интерфейса ISchemeView, который позволяет управлять View из модели. Это фишка паттера MVC, но не MVVM. Есть много разных способов сделать что вы хотите. Например, подписаться на события модели из вьюмодели. Помните, ваша модель должна работать как независимая часть программы. Вы должны уметь изменить модель кодом. Invalidate правда происходит во View, или оно происходит в модели, а View просто отображает состояние модели?
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
На windows 7 не всегда меняются обои, есть ли этому решение?
Заметил, что часто используют эти методы в связке:
Если нужно получить запись из базы данных по ее первичному ключу, можно воспользоваться и тем и другим методомОба метода вернут объект сущности,...