разработка Эффективная .net-приложений с...
TRANSCRIPT
![Page 1: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/1.jpg)
Эффективная кроссплатформенная разработка .NET-приложенийс использованием MVVM
![Page 2: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/2.jpg)
MVVM? А зачем оно надо?”When capabilities are extended, the codebase should become smaller”.
@Thinking Out Loud
Четкое разделение бизнес-логики и логики представления.Отсюда все вытекающие бенефиты и профиты.
![Page 3: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/3.jpg)
MVVM. Типичная схема...
ViewView Model
Business Logicand Data
View Model
Presentation Logic
Data binding
Commands
Notifications
![Page 4: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/4.jpg)
… и типичные проблемы: реализация уведомленийреализация командограничения механизма привязкиреализация механизма сервисов
INotifyPropertyChangedDelegateCommandRelayCommand
BooleanToVisibilityConverer
MultiBindingDataContext
BehaviorMessenger
ServiceContainer
![Page 5: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/5.jpg)
А есть ли тут кроссплатформенность?
ViewView Model
Business Logicand Data
View Model
Presentation Logic
Data binding
Commands
Notifications
Code-behind
Events
Methods
![Page 6: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/6.jpg)
class AccountCollectionViewPresenter { public CollectionViewPresenter(GridView gridView, AccountCollectionViewModel viewModel) { gridView.FocusedRowObjectChanged += (s, e) => { viewModel.SelectedEntity = e.Row as Model.Account; }; ((INotifyPropertyChanged)viewModel).PropertyChanged += (s, e) => { if(e.PropertyName == "SelectedEntity") { var entity = viewModel.SelectedEntity; if(entity != null) gridView.FocusedRowHandle = gridView.LocateByValue("Id", entity.ID); else gridView.FocusedRowHandle = GridControl.InvalidRowHandle; } }; }}
От MVVM к MVPVM. Presenter.Выделяем узконаправленный код в специализированные классы
![Page 7: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/7.jpg)
class AccountCollectionViewPresenter { public CollectionViewPresenter(GridView gridView, AccountCollectionViewModel viewModel) { gridView.FocusedRowObjectChanged += (s, e) => { viewModel.SelectedEntity = e.Row as Model.Account; }; ((INotifyPropertyChanged)viewModel).PropertyChanged += (s, e) => { if(e.PropertyName == "SelectedEntity") { var entity = viewModel.SelectedEntity; if(entity != null) gridView.FocusedRowHandle = gridView.LocateByValue("Id", entity.ID); else gridView.FocusedRowHandle = GridControl.InvalidRowHandle; } }; }}
gridView.FocusedRowObjectChanged += (s, e) => { viewModel.SelectedEntity = e.Row as Model.Account;};
От MVVM к MVPVM. Presenter.Выделяем узконаправленный код в специализированные классы
![Page 8: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/8.jpg)
Presenter повсюду.● User Control и его Code-Behind● Отдельный класс● Отдельный метод для настройки
контрола● Специфичный кусок Code-Behind● Обработчик события● Привязка(Binding)
![Page 9: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/9.jpg)
• Привязки к данным.• Команды и привязки к командам.• Поведения и сервисы.• Бонус – удобный механизм реализации уведомлений, зависимостей, команд
MVPVM без буквы “P”.больше удобства, меньше кода
![Page 10: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/10.jpg)
Уведомления об измененииpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(userNameCore == value) return;
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
дать возможность стороннему наблюдателю узнать об изменении значения свойства или состояния целевого объекта
![Page 11: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/11.jpg)
Уведомления об измененииpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
public class LoginViewModel : BindableBase {
string userNameCore;
public string UserName {
get { return userNameCore; }
set { SetProperty(ref userNameCore, "UserName");}
}
}
![Page 12: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/12.jpg)
Уведомления об измененииpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
POCO-ViewModel:
public class LoginViewModel {
public virtual string UserName { get; set; }
}
Plain Old Clr Object
![Page 13: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/13.jpg)
POCO-трансформация
???POCO-class
Full-featured
ViewModel
DevExpress.Mvvm.POCO.ViewModelSource
![Page 14: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/14.jpg)
POCO-трансформация (INPC-проход)
Метаданные для генерации• Свойства и методы• Атрибуты свойств
POCO-class
![Page 15: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/15.jpg)
Уведомления об измененииpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
POCO-ViewModel:
public class LoginViewModel {
public virtual string UserName { get; set; }
}
![Page 16: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/16.jpg)
POCO-трансформация (INPC-проход)
Метаинформация Сгенерированный тип-наследник
var viewModel = ViewModelSource.Create<ViewModel>();
![Page 17: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/17.jpg)
Зависимости свойствpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(userNameCore == value) return;
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
OnUserNameChanged(); // OnUserNameChanged(oldValue)
}
}
}
дать возможность явно уведомить сторонних наблюдателей об изменении значения свойства или состояния целевого объекта
![Page 18: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/18.jpg)
Зависимости свойствpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
public class LoginViewModel : BindableBase {
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
SetProperty(ref userNameCore,
"UserName", OnUserNameChanged);
}
}
}
![Page 19: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/19.jpg)
Зависимости свойствpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
POCO-ViewModel:
public class LoginViewModel {
public virtual string UserName { get; set; }
protected void OnUserNameChanged() {/*...*/}
}
![Page 20: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/20.jpg)
Ручное обновление зависимостейpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(userNameCore == value) return;
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
OnUserNameChanged();
}
}
}
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
![Page 21: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/21.jpg)
Ручное обновление зависимостейpublic class LoginViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string userNameCore;
public string UserName {
get { return userNameCore; }
set {
if(value != userNameCore) {
this.userNameCore = value;
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs("UserName"));
}
}
}
}
POCO-ViewModel:
// Extension method
this.RaisePropertyChanged(x => x.UserName);
![Page 22: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/22.jpg)
Команды public class DelegateCommand<T> : System.Windows.Input.ICommand {
readonly Predicate<T> _canExecute;
readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null) {
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute) {
_execute = execute;
_canExecute = canExecute;
}
//...
}
public class MyViewModel { public MyViewModel() { this.SayHelloCommand = new DelegateCommand(SayHello); } public System.Windows.Input.ICommand SayHelloCommand { get; private set; } public void SayHello() { /* do something */ }}
дать возможность инкапсулировать действие в отдельном объекте
![Page 23: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/23.jpg)
Команды public class DelegateCommand<T> : System.Windows.Input.ICommand {
readonly Predicate<T> _canExecute;
readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null) {
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute) {
_execute = execute;
_canExecute = canExecute;
}
//...
}
POCO-ViewModel:public class MyViewModel { public void SayHello() { /* do something */ }}
POCO-ViewModel:public class MyViewModel { public void SaySomething(string str) { /* ... */ } public bool CanSaySomething(string str) { /* ... */ }}
POCO-ViewModel:public class MyViewModel { public Task DoSomething () { /* asynchronous !!! */ }}
![Page 24: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/24.jpg)
Как это использовать?
Commands (XAML):
<Button Command="{Binding SayHelloCommand}" />
<Button Command="{Binding SayCommand}"CommandParameter="Hi!"/>
Data-Bindings (XAML):
<dxe:TextEdit Text="{Binding UserName}"/>
![Page 25: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/25.jpg)
Как написать простейший Event-trigger
Тип+EventName(EventInfo)• Тип EventHandler• Методы Add/Remove
Source
![Page 26: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/26.jpg)
Как написать простейший Event-trigger
МетаинформацияСгенерированны
й метод-обработчик
события
EventHandlerType eventHandler = (s,e) => OnEvent();
![Page 27: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/27.jpg)
Как написать простейший Event-triggerstatic Delegate GetHandler( Type handlerType, MethodCallExpression triggerExpression, ParameterExpression[] handlerParameters) { // Create&Compile Expression of specific type return Expression.Lambda(handlerType, triggerExpression, handlerParameters ).Compile();}
![Page 28: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/28.jpg)
Как написать простейший Event-triggerpublic class EventTrigger<TEventArgs> { protected TEventArgs Args { get; } protected virtual void OnEvent() { /* do something */ }}
![Page 29: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/29.jpg)
Binding
Как сделать простейший Binding.
INPC-EventTrigger
Source
PCE-EventTrigger
Target
![Page 30: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/30.jpg)
CommandBinding
Как сделать Binding к команде.
Сгенерированные методы: Action => ExecuteFunc<bool> => CanExecute
Command
CanExecuteChanged(EventTrigger)
![Page 31: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/31.jpg)
MVVMContext
MVVMContext – собираем все в кучу
Создание ViewModel
Создание Binding
Создание CommandBinding
![Page 32: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/32.jpg)
Как это использовать?Code-behind(MVVM Context API):
public LoginViewModel ViewModel {
get { return mvvmContext.GetViewModel<LoginViewModel>(); }
}
// ...
mvvmContext.SetBinding(tbUserName,
t => t.Text, ViewModel, "UserName");
Code-behind(MVVM Context Fluent-API):var fluent = mvvmContext.OfType<MyViewModel>();
fluent.SetBinding(tbTitle, t => t.Text, x => x.Title);
![Page 33: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/33.jpg)
Как это использовать?Code-behind (MVVMContext API):public MyViewModel ViewModel {
get { return mvvmContext.GetViewModel<MyViewModel>(); }
}
//
btnSayHello.BindCommand(
() => ViewModel.SayHello(), ViewModel);
btnSay.BindCommand(
() => ViewModel.Say(null), ViewModel, () => ViewModel.Name);
Code-behind (MVVMContext Fluent API):var fluent = mvvmContext.OfType<MyViewModel>();
fluent.BindCommand(btnSayHello, x => x.SayHello());
fluent.BindCommand(btnSay,(x,s) => x.Say(s), x => x.Name);
![Page 34: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/34.jpg)
Теперь попробуем все это на практике
https://github.com/DmitryGaravsky/DevExpress.Mvvm.Examples
![Page 35: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/35.jpg)
Интерактивность. Сервисы.
ViewModel:public class MyViewModel {
protected IMessageBoxService MessageBoxService {
get { /* ... */ }
}
public void SayHello() {
MessageBoxService.Show("Hello!");
}
}
дать возможность взаимодействовать с пользователем не нарушая концепцию разделения слоев
![Page 36: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/36.jpg)
POCO ViewModel:protected IMessageBoxService MessageBoxService {
get { this.GetService<IMessageBoxService>(); }
}
protected virtual IMessageBoxService MessageBoxService {
get { throw new System.NotImplementedException(); }
}
Интерактивность. Сервисы.
![Page 37: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/37.jpg)
Как это использовать?
Code-behind (MVVMContext API):mvvmContext.RegisterService(new MessageBoxService());
//...
var mbService = mvvmContext.GetService<IMessageBoxService>();
mbService.Show("Something happens!");
![Page 38: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/38.jpg)
Сервисы и проблема навигации.
• Независимость от View• Поддержка разных типов UI• Кроссплатформенность внутри одной платформы
![Page 39: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/39.jpg)
public class ConfirmationBehavior
: ConfirmationBehavior<FormClosingEventArgs> {
public ConfirmationBehavior() : base("FormClosing") { }
protected override string GetConfirmationCaption() {
return "Oops!";
}
protected override string GetConfirmationText() {
return "Form will be closed. Are you sure?";
}
}
Поведения.
Code-behind (MVVMContext API)://...
mvvmContext.AttachBehavior<ConfirmationBehavior>(this);
дать возможность наделить объект дополнительным функционаломдействуя снаружи объекта
![Page 40: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/40.jpg)
Поведения.
Code-behind (MVVMContext Fluent API)://...
mvvmContext.WithEvent<CancelEventArgs>(this, "Closing")
.Confirmation(
settings => {
settings.Caption = "Closing Confirmation";
settings.Text = "Form will be closed. Press OK to confirm.";
settings.Buttons = ConfirmationButtons.OKCancel;
settings.ShowQuestionIcon = false;
});
![Page 41: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/41.jpg)
Поведения. EventToCommand.
public class ClickToSayHello :
EventToCommandBehavior<MyViewModel, EventArgs> {
public ClickToSayHello()
: base("Click", x => x.SayHello()) {
}
}
Code-behind (MVVMContext API)://...
mvvmContext.AttachBehavior<ClickToSayHello>(thirdPartyButton);
![Page 42: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/42.jpg)
Поведения. EventToCommand.Code-behind (MVVMContext Fluent API):
mvvmContext.WithEvent<ViewModel, EventArgs> (thirdPartyButton, "Click") .EventToCommand(x => x.SayHello());
Code-behind (MVVMContext Fluent API):
fluent.WithEvent<RowClickEventArgs>(gridView, "RowClick") .EventToCommand( x => x.Edit(null), x => x.SelectedEntity, a => (a.Clicks==2) && (a.Button == MouseButtons.Left));
![Page 43: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/43.jpg)
Behavior
Как сделать Behavior?
Services
EventTrigger
TargetSetting
![Page 44: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/44.jpg)
Поведения и проблема INPC для Model.Классы Model как правило не INPC
Code-behind (MVVMContext Fluent API):
var fluent = mvvmContext.OfType<AccountViewModel>();fluent.SetObjectDataSourceBinding( bindingSource, x => x.Entity, x => x.Update());
![Page 45: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/45.jpg)
Проблема Legacy кода. ViewModel.Хотим использовать все наработки
Code-behind (MVVMContext Fluent API):
var viewModel = new LegacyViewModel("Legacy ViewModel");// initialize the MVVMContext with the specific ViewModel's instancemvvmContext.SetViewModel(typeof(LegacyViewModel), viewModel);
![Page 46: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/46.jpg)
Проблема кроссплатформенного DataLayerПодойдет ли нам Entity Framework?
![Page 47: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/47.jpg)
Проблема кроссплатформенного GUIНет ответа. Есть мнение.
![Page 48: разработка Эффективная .NET-приложений с использованием …public.jugru.org/dotnext/2015/piter/dotnext2015SPB... · and Data View Model](https://reader033.vdocuments.mx/reader033/viewer/2022042420/5f37930747a5b578b80fb28d/html5/thumbnails/48.jpg)
Подведем итоги
• Бесплатное и кроссплатформенное ядро(WPF/Silverlight/WinRT/UWP/WinForms + MONO)
• Вся мощь системы привязок на любой платформе
• Эффективность и уверенность в положительном результате
MVVM подход + MVVM.Utils