Você está na página 1de 25

MVVM Framework

O padrão Model-View-ViewModel é o padrão mais popular para a escrita de aplicativos WPF.


Ele permite que você desenvolva uma arquitetura flexível com testes de unidade, o que é
realmente útil nas aplicações Line Of Business (LoB).

Uma vez que certos mecanismos são difíceis de implementar sem se afastar do MVVM,
existem problemas com a implementação de funcionalidades específicas. Além disso, as
limitações MVVM podem não se relacionar com nenhum controle particular, porque a própria
plataforma WPF não possui suporte total para o desenvolvimento do MVVM.

Para resolver isso, o DevExpress criou seu próprio Framework, que em conjunto com o
DevExpress Controls, é uma solução holística para uma aplicação MVVM bem projetada.

Com a biblioteca DevExpress WPF você pode facilmente criar as três camadas para MVVM -
View, ViewModel e Model - quer automaticamente, usando assistentes ou manualmente no
código usando classes derivadas. Os controles WPF fornecem tags inteligentes, que permitem
a ligação rápida ao ViewModels em tempo de design.

Observação:

Você pode usar os controles DevExpress MVVM Framework e DevExpress WPF separadamente
um do outro. Os controles DevExpress WPF podem ser usados com qualquer framework
MVVM.

ViewModels
O View Model é uma parte das aplicações MVVM responsável pela interação entre as outras
duas partes: Model e View.

O DevExpress MVVM Framework oferece várias classes de base, que você pode usar para
derivar seus Modelos de Visualização para a implementação fácil de propriedades vinculáveis,
validação, comandos, serviços de consumo e para implementar a interação entre Modelos de
Exibição.

Outra característica poderosa do DevExpress MVVM Framework é o mecanismo POCO, que


simplifica e acelera o processo de desenvolvimento do View Model.

BindableBase

A classe BindableBase implementa a interface INotifyPropertyChanged e fornece recursos para


a implementação fácil de propriedades vinculáveis com os métodos GetProperty e
SetProperty.
C#

public class ViewModel : BindableBase {


public string FirstName {
get { return GetProperty(() => FirstName); }
set { SetProperty(() => FirstName, value); }
}
}

O primeiro parâmetro dos métodos GetProperty e SetProperty é uma expressão lamda que
retorna a propriedade usada para identificar o nome da propriedade do destino (os nomes das
propriedades são obtidos internamente com o método estático
BindableBase.GetPropertyName <T>).

Os valores de propriedade são armazenados em um dicionário interno (o método GetProperty


usa este dicionário para obter um valor de propriedade com base no nome da propriedade, o
método SetProperty armazena um valor de propriedade usando o nome da propriedade como
uma chave). Essa abordagem simplifica o código e permite a verificação de código durante as
propriedades de compilação e renomeação com recursos de refatoração padrão do Visual
Studio.

O método SetProperty retorna valores Verdadeiros ou False que indicam se uma propriedade
foi ou não alterada com êxito (se você definir o mesmo valor para a propriedade, o método
SetProperty retorna false e as notificações em mudança não são enviadas). Algumas
sobrecargas do método SetProperty também utilizam um método de retorno de chamada
como parâmetro. Este retorno de chamada é invocado após o campo ter sido alterado.

C#

public class ViewModel : BindableBase {


public string FirstName {
get { return GetProperty(() => FirstName); }
set { SetProperty(() => FirstName, value,
OnFirstNameChanged); }
}
void OnFirstNameChanged() {
//...
}
}

Se você precisar aumentar manualmente o evento INotifyPropertyChanged.PropertyChanged


para uma propriedade específica, use o método RaisePropertyChanged /
RaisePropertiesChanged.
C#

public class ViewModel : BindableBase {


public string FullName {
get { return string.Format("{0} {1}", FirstName,
LastName); }
}
public string FirstName {
get { return GetProperty(() => FirstName); }
set { SetProperty(() => FirstName, value,
OnFirstNameChanged); }
}
public string LastName {
get { return GetProperty(() => LastName); }
set {
if(SetProperty(() => LastName, value))
RaisePropertyChanged(() => FullName);
}
}
void OnFirstNameChanged() {
RaisePropertyChanged(() => FullName);
}
}

Em casos raros, o desempenho do aplicativo pode se deteriorar quando uma propriedade é


frequentemente atualizada (devido ao cálculo de nomes de propriedades de expressões
lambda e ao acesso de propriedades do armazenamento do Dicionário). Para acomodar esses
cenários, use variáveis de armazenamento para propriedades e calcule nomes de propriedade
uma vez do construtor estático usando o método BindableBase.GetPropertyName <T>.
C#

public class ViewModel : BindableBase {


static string Property1Name;
static ViewModel() {
Property1Name = BindableBase.GetPropertyName(() => new
ViewModel().Property1);
}

string property1;
public string Property1 {
get { return property1; }
set { SetProperty(ref property1, value, Property1Name);
}
}
}

ViewModelBase

A classe ViewModelBase é um descendente BindableBase. Ele herda os recursos da classe


BindableBase (como os métodos GetProperty, SetProperty e RaisePropertyChanged /
RaisePropertiesChanged) e oferece as seguintes capacidades adicionais.

 Inicialize as propriedades separadamente para o tempo de execução e os modos de


tempo de design
 Serviços de acesso registrados em uma visão
 Usar View Models de relações pai-filho
 Passar dados entre View Models
 Criar comandos sem propriedades de comando
 Exemplo

Inicialize as propriedades separadamente


para o tempo de execução e os modos de
tempo de design
Uma View Model pode conter uma propriedade que requer acesso a um banco de dados.
Enquanto você trabalha no designer Visual Studio, o View Model não tem permissão para se
conectar ao banco de dados. Isso leva a um erro no designer.

Nesses casos, a classe ViewModelBase fornece os métodos virtuais protegidos


OnInitializeInDesignMode e OnInitializeInRuntime, que você pode substituir para inicializar as
propriedades para os modos de tempo de execução e tempo de design separadamente.

C#

public class ViewModel : ViewModelBase {


public IEnumerable<Employee> Employees {
get { return GetProperty(() => Employees); }
private set { SetProperty(() => Employees, value); }
}
protected override void OnInitializeInDesignMode() {
base.OnInitializeInDesignMode();
Employees = new List<Employee>() {
new Employee() { Name = "Employee 1" },
};
}
protected override void OnInitializeInRuntime() {
base.OnInitializeInRuntime();
Employees = DatabaseController.GetEmployees();
}
}

Serviços de acesso registrados em uma visão


A classe ViewModelBase implementa a interface ISupportServices que mantém o mecanismo
de Serviços. O método ViewModelBase.GetService, que emprega a interface ISupportServices,
permite acessar os serviços registrados em uma View.
XAML

<UserControl x:Class="ViewModelBaseSample.View"

xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:ViewModels="clr-
namespace:ViewModelBaseSample.ViewModels" ...>
<UserControl.DataContext>
<ViewModels:ViewModel/>
</UserControl.DataContext>
<dxmvvm:Interaction.Behaviors>
<dxmvvm:MessageBoxService/>
</dxmvvm:Interaction.Behaviors>
...
</UserControl>

C#
public class ViewModel : ViewModelBase {
public IMessageBoxService MessageBoxService { get { return
GetService<IMessageBoxService>(); } }
}

O tópico a seguir contém mais informações sobre como usar os serviços em View Models
herdados da classe ViewModelBase: Serviços em descendentes do ViewModelBase.

Usar View Models de relações pai-filho


Ver modelos herdados do ViewModelBase podem estar relacionados entre si com uma relação
pai-filho. Isso é alcançado com a interface ISupportParentViewModel que é implementada na
classe ViewModelBase. Neste caso, os Modelos de Exibição Infantil podem acessar os Serviços
registrados no Modelo de Visão principal. O tópico a seguir contém mais informações sobre
como você pode definir o relacionamento pai-filho e quais os benefícios que você pode obter
usando esse mecanismo: relacionamentos ViewModel (ISupportParentViewModel).
Passar dados entre View Models
A classe ViewModelBase implementa a interface ISupportParameter, que pode ser usada para
transmitir dados iniciais para View Models. O seguinte tópico de documentação descreve
como esse mecanismo funciona: Passando dados entre ViewModels (ISupportParameter).

Criar comandos sem propriedades de


comando
A classe ViewModelBase implementa a interface ICustomTypeDescriptor para fornecer a
capacidade de criar automaticamente propriedades de comando com base em métodos (com
o atributo Command) em tempo de execução.

A abordagem tradicional da criação de comandos é declarar propriedades de comando da


seguinte forma.

C#

public class ViewModel : ViewModelBase {


public ICommand SaveCommand { get; private set; }
public ViewModel() {
SaveCommand = new DelegateCommand(Save, CanSave);
}
public void Save() {
//...
}
public bool CanSave() {
//...
}
}

Derivar do ViewModelBase permite que você utilize uma definição mais curta. Defina o
atributo Command para o método que deseja usar como um comando.
C#

public class ViewModel : ViewModelBase {


[Command]
public void Save() {
//...
}
public bool CanSave() {
//...
}
}

Quando o atributo Command é aplicado a um método, o comando correspondente terá o


nome: [MethodName] Command "onde [MethodName] é o nome do método de destino. Para
o exemplo acima, o nome do comando será" SaveCommand ".

XAML

<Button Command="{Binding SaveCommand}"/>

O atributo Command pode ser aplicado a um método sem parâmetros ou a um método com
um parâmetro. Você também pode personalizar o comando definindo as propriedades do
atributo Command.

O tópico a seguir contém mais informações sobre commands: Commands.

Este exemplo demonstra como usar a classe ViewModelBase para herdar modelos de exibição.

Um projeto de amostra completo está disponível no banco de dados de Exemplos de código do


DevExpress em http://www.devexpress.com/example=E5169.

POCO ViewModels
POCO ( Objetos CLR antigos ) View Models simplificam e aceleram o
processo de desenvolvimento. As classes POCO permitem que você
defina facilmente propriedades e métodos vinculáveis sem a
necessidade de herdar de várias classes diferentes (por exemplo,
ViewModelBase) ou implementar inúmeras interfaces MVVM
específicas, como INotifyPropertyChanged e ICommand. POCO
ViewModels permite que você defina propriedades vinculáveis como
simples propriedades implementadas automaticamente, bem como
criar métodos que serão representados por comandos em tempo de
execução. Isso fornece um código MVVM limpo, simples, sustentável e
testável. Esta é uma ótima abordagem para o padrão MVVM.
Todos os controles DevExpress WPF, bem como outros controles WPF,
são totalmente compatíveis com POCO View Models.

 Fundamentos da geração de modelos de exibição POCO


 Propriedades vinculativas
 Comandos
 Serviços
 View Models de relações pai-filho
 Implementação automática IDataErrorInfo

Fundamentos da geração de modelos de


exibição POCO
Uma classe POCO não implementa uma interface e não precisa ser
herdada de uma classe base,
como ViewModelBase ou BindableBase. Para transformar uma classe
POCO em um ViewModel funcional, é necessário criá-la com
a classe DevExpress.Mvvm.POCO.ViewModelSource . Veja o
exemplo abaixo.
C#
public class LoginViewModel {
//This property will be converted to a bindable one
public virtual string UserName { get; set; }

//SaveAccountSettingsCommand will be created for the


SaveAccountSettings and CanSaveAccountSettings methods:
//SaveAccountSettingsCommand = new
DelegateCommand<string>(SaveAccountSettings,
CanSaveAccountSettings);
public void SaveAccountSettings(string fileName) {
//...
}
public bool CanSaveAccountSettings(string fileName) {
return !string.IsNullOrEmpty(fileName);
}

//We recommend that you not use public constructors to


prevent creating the View Model without the ViewModelSource
protected LoginViewModel() { }
//This is a helper method that uses the ViewModelSource
class for creating a LoginViewModel instance
public static LoginViewModel Create() {
return ViewModelSource.Create(() => new
LoginViewModel());
}
}

A classe ViewModelSource também pode ser usada para criar uma


instância do View Model no XAML.
XAML
<UserControl x:Class="DXPOCO.Views.LoginView"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:ViewModels="clr-namespace:DXPOCO.ViewModels"
DataContext="{dxmvvm:ViewModelSource
Type=ViewModels:LoginViewModel}"
...>
<Grid>
<!--...-->
</Grid>
</UserControl>
O método ViewModelSource.Create cria um descendente da classe
ViewModel passada usando Reflection Emit e retorna sua instância em
tempo de execução. O código abaixo é semelhante ao que o
ViewModelSource gera com base na classe LoginViewModel.
C#
public class LoginViewModel_EXTENSION : LoginViewModel,
INotifyPropertyChanged {
public override string UserName {
get { return base.UserName; }
set {
if(base.UserName == value) return;
base.UserName = value;
RaisePropertyChanged("UserName");
}
}
DelegateCommand<string> saveAccountSettingsCommand;
public DelegateCommand<string> SaveAccountSettingsCommand {
get {
return saveAccountSettingsCommand ??
(saveAccountSettingsCommand =
new
DelegateCommand<string>(SaveAccountSettings,
CanSaveAccountSettings));
}
}

//INotifyPropertyChanged Implementation
}

Para passar parâmetros para o construtor do ViewModel, você pode


usar uma das seguintes abordagens.
 Embora esta abordagem seja a mais poderosa e linda, também é
a mais lenta, porque as expressões lambda não são comparáveis,
elas permanecem uncached e compilam de novo com cada
chamada de método.
C#
ViewModelSource.Create(() => new LoginViewModel(caption: "Login") {
UserName = "John Smith"
});

 Uma vez que as instâncias de delegado compiladas podem ser


armazenadas em cache, esta é a abordagem mais rápida para
passar parâmetros para o construtor ViewModel.

C#
var factory = ViewModelSource.Factory((string caption) => new
LoginViewModel(caption));
factory("Login");

Este exemplo demonstra como usar o mecanismo POCO para criar


modelos de exibição.

Mostre-me
Um projeto de amostra completo está disponível no banco de dados de Exemplos
de código do DevExpress em http://www.devexpress.com/example=E5167 .

Propriedades vinculativas
A regra para gerar propriedades vinculáveis é a seguinte: todas
as propriedades públicas auto-implementadas com o modificador virtual e
um getter público, juntamente com um setter protegido ou público,
tornam-se vinculáveis.
Você pode definir as funções que são invocadas quando as
propriedades são alteradas. Esses nomes de função devem usar os
seguintes
formatos: On[PropertyName]Changed e On[PropertyName]
Changing .
C#
public class LoginViewModel {
public virtual string UserName { get; set; }
protected void OnUserNameChanged() {
//...
}
}

public class LoginViewModel {


public virtual string UserName { get; set; }
protected void OnUserNameChanged(string oldValue) {
//...
}
protected void OnUserNameChanging(string newValue) {
//...
}
}

Para definir uma função que não corresponde à convenção, use


o atributo BindableProperty .

C#
public class LoginViewModel {
[BindableProperty(isBindable: false)]
public virtual bool IsEnabled { get; set; }

[BindableProperty(OnPropertyChangedMethodName = "Update")]
public virtual string UserName { get; set; }
protected void Update() {
//...
}
}

Você também pode aproveitar a API Fluent.


C#
[MetadataType(typeof(Metadata))]
public class LoginViewModel {
public class Metadata : IMetadataProvider<LoginViewModel> {
void IMetadataProvider<LoginViewModel>.BuildMetadata
(MetadataBuilder<LoginViewModel> builder) {

builder.Property(x => x.UserName).


OnPropertyChangedCall(x => x.Update());
builder.Property(x => x.IsEnabled).
DoNotMakeBindable();
}
}
public virtual bool IsEnabled { get; set; }
public virtual string UserName { get; set; }
protected void Update() {
//...
}
}

Comandos
Os comandos são gerados para todos os métodos públicos sem
parâmetros ou com apenas um parâmetro. Você pode controlar o
mecanismo de geração usando o atributo Command ou usando a API
Fluent.
C#
public class LoginViewModel {
[Command(isCommand: false)]
public void SaveCore() {
//...
}

[Command(CanExecuteMethodName = "CanSaveAccountSettings",
Name = "SaveCommand",
UseCommandManager = true)]
public void SaveAccountSettings(string fileName) {
//...
}
public bool CanSaveAccountSettings(string fileName) {
return !string.IsNullOrEmpty(fileName);
}
}

[MetadataType(typeof(Metadata))]
public class LoginViewModel {
public class Metadata : IMetadataProvider<LoginViewModel> {
void
IMetadataProvider<LoginViewModel>.BuildMetadata(MetadataBuilder<Log
inViewModel> builder) {
builder.CommandFromMethod(x => x.SaveCore()).
DoNotCreateCommand();
builder.CommandFromMethod(x =>
x.SaveAccountSettings(default(string))).
CanExecuteMethod(x =>
x.CanSaveAccountSettings(default(string))).
CommandName("SaveCommand");
}
}
public void SaveCore() {
//...
}
public void SaveAccountSettings(string fileName) {
//...
}
public bool CanSaveAccountSettings(string fileName) {
return !string.IsNullOrEmpty(fileName);
}
}
O tópico a seguir contém mais informações sobre
commands: Commands.

Serviços
O DevExpress MVVM Framework fornece o mecanismo de Serviços. O
código abaixo é um exemplo de como obter acesso ao serviço Caixa de
mensagens.
C#
using DevExpress.Mvvm.POCO;
...
public class LoginViewModel {
public IMessageBoxService MessageBoxService { get {
return this.GetService<IMessageBoxService>(); } }
}

Por favor, reveja o tópico a seguir para saber mais sobre o acesso a
serviços: Serviços em objetos POCO .

Ver relações modelo pai-filho


POCO View Models pode estar relacionado entre si com a relação pai-
filho. Isso é alcançado com a interface ISupportParentViewModel que é
implementada automaticamente quando você cria um objeto POCO
com a classe ViewModelSource. Com esta interface, os modelos de
exibição infantil podem acessar serviços registrados no modelo de
exibição principal. O tópico a seguir contém mais informações sobre
como você pode definir o relacionamento pai-filho e quais benefícios
podem ser obtidos usando este mecanismo: relacionamentos ViewModel
(ISupportParentViewModel).

Implementação automática IDataErrorInfo


A interface IDataErrorInfo é o mecanismo padrão para validação de
dados no WPF. Usando essa interface, você pode fornecer regras de
validação para cada propriedade isoladamente ou, alternativamente,
em todo o objeto. O mecanismo POCO permite que você implemente
automaticamente a interface IDataErrorInfo com base em atributos
definidos ou API Fluente.
Para habilitar esse recurso, aplique o atributo POCOViewModel para o
seu Modelo de exibição e defina
o parâmetro POCOViewModel.ImplementIDataErrorInfo como
Verdadeiro.
C#
//Attribute-based approach
[POCOViewModel(ImplementIDataErrorInfo = true)]
public class LoginViewModel {
[Required(ErrorMessage = "Please enter the user name.")]
public virtual string UserName { get; set; }
}

//Fluent API
[POCOViewModel(ImplementIDataErrorInfo = true)]
[MetadataType(typeof(LoginViewModel.Metadata))]
public class LoginViewModel {
public class Metadata : IMetadataProvider<LoginViewModel> {
void
IMetadataProvider<LoginViewModel>.BuildMetadata(MetadataBuilder<Log
inViewModel> builder) {
builder.Property(x => x.UserName).
Required(() => "Please enter the user name.");
}
}
public virtual string UserName { get; set; }
}

Quando o ViewModelSource gera um descendente de um View Model,


ele implementa a interface IDataErrorInfo da seguinte maneira.
C#
public class LoginViewModel : IDataErrorInfo {
...
string IDataErrorInfo.Error {
get { return string.Empty; }
}
string IDataErrorInfo.this[string columnName] {
get { return IDataErrorInfoHelper.GetErrorText(this,
columnName); }
}
}

A classe IDataErrorInfoHelper fornece a capacidade de obter um erro


com base em atributos DataAnnotation definidos ou API Fluente.
O exemplo de código abaixo demonstra como usar o mecanismo
POCO para implementar a interface IDataErrorInfo.

Mostre-me
Um projeto de amostra completo está disponível no banco de dados de Exemplos
de código do DevExpress em http://www.devexpress.com/example=E5151 .

Interação de ViewModels

A arquitetura de um aplicativo depende do grau de conexão entre seus módulos. Por exemplo,
em pequenas aplicações, os Modelos de Visualização podem saber sobre outros Modelos de
Visualização (Os Modelos de Visualização podem criar outros Modelos de Exibição, definir suas
propriedades ou manipular eventos). Esse tipo de arquitetura é bem acoplado. Esta é uma boa
e clara, se você desenvolver uma aplicação sozinha ou em uma pequena equipe.

No entanto, se você desenvolver uma grande aplicação, a arquitetura bem acoplada não é
adequada, pois qualquer alteração pode quebrar todo o sistema. A arquitetura vagamente
acoplada resolve esse problema. Isso implica muitos módulos dispersos, operando sem
consciência uns dos outros. Idealmente, os módulos são os blocos de construção de um design
adaptável. Por sua vez, os módulos podem ser construídos com a arquitetura bem acoplada.
Isso permite que você suporte facilmente e melhore seu aplicativo, porque adicionar ou
remover funcionalidades simplesmente significa registrar ou cancelar o registro de um módulo
específico, sem preocupação com nenhum outro módulo.
Ao desenvolver aplicativos usando a arquitetura de Modelos de Visualização Livres, é
necessário organizar a interação entre módulos. O DevExpress MVVM Framework oferece
vários recursos para esse fim (veja a lista abaixo).

 Passando dados entre ViewModels (ISupportParameter)


 Relações ViewModel (ISupportParentViewModel)
 Mensageiro

Passando dados entre ViewModels


(ISupportParameter)

A classe ViewModelBase implementa a interface ISupportParameter. Esta interface fornece a


propriedade Parameter, que pode ser usada para passar dados iniciais para View Models.

Nota

Observe que o mecanismo POCO não gera automaticamente a implementação da interface


ISupportParameter, mas você pode implementar esta interface em seu modelo de exibição
POCO manualmente.

O código a seguir demonstra como você pode definir a propriedade Parameter no código para
trás, quando um modelo de exibição detalhada é criado a partir do modelo de exibição
principal.

C#

public class MainViewModel : ViewModelBase {


public DetailViewModel DetailViewModel { get; private set; }
public MainViewModel() {
DetailViewModel = new DetailViewModel();
((ISupportParameter)DetailViewModel).Parameter = "Document
1";
}
}

Quando a propriedade ISupportParameter.Parameter é definida, o método virtual


ViewModelBase.OnParameterChanged é invocado. Você pode substituí-lo para processar
dados passados.
C#

public class DetailViewModel : ViewModelBase {


protected override void OnParameterChanged(object parameter) {
base.OnParameterChanged(parameter);
if(IsInDesignMode) {
//...
} else {
//...
}
}
}

Também é possível implementar a passagem de dados de um Modelo de Vista Principal para


um Detalhe quando estes Modelos de Visualização estão livremente acoplados, ou seja,
quando os Modelos de Visualização não conhecem uns dos outros. Esse mecanismo implica
vincular a propriedade Parameter no XAML. O esquema que demonstra o procedimento é
mostrado no seguinte diagrama:

DIAGRAMA

Aqui, a View principal contém uma instância de uma View de detalhes. Os DataContexts de
cada um são o modelo principal ViewModel e Detail View, respectivamente. A tarefa é passar
dados do Main View / Main ViewModel para o Detail ViewModel. Para realizar isso, os dados a
serem passados são atribuídos à propriedade ViewModelExtensions.Parameter anexada na
instância View Detail.
XAML

<UserControl x:Class="Example.View.MainView" ...


xmlns:ViewModel="clr-namespace:Example.ViewModel"
xmlns:View="clr-namespace:Example.View"

xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm">
<UserControl.DataContext>
<ViewModel:MainViewModel/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot">
...
<!-- It is necessary to use the ElementName binding mode,
because the DetailView's DataContext is a DetailViewModel object.
That is why the following regular binding cannot be used in
this case: dxmvvm:ViewModelExtensions.Parameter="{Binding}"
Instead, use one of the following constructions:-->
<View:DetailView
dxmvvm:ViewModelExtensions.Parameter="{Binding DataContext,
ElementName=LayoutRoot}"/>
<ContentControl>
<ContentControl.ContentTemplate>
<DataTemplate>
<View:DetailView
dxmvvm:ViewModelExtensions.Parameter="{Binding DataContext,
Source={x:Reference LayoutRoot}}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
...
</Grid>
</UserControl>

A classe ViewModelExtensions, expondo a propriedade Parameter attached na instância View


Detail, executa todas as ações necessárias para passar dados da instância View Detail para o
ViewModel associado. Quando a propriedade Parâmetro anexado é definida na Vista de
detalhes, a classe ViewModelExtensions identifica se o DataContext da View é um ViewModel
(um objeto ViewModelBase ou para ser mais preciso, se o DataContext é um objeto que
implementa a interface ISupportParameter). Em caso afirmativo, o novo valor do parâmetro é
passado para ViewModel da Visualização detalhada (é atribuído à propriedade privada
ISupportParameter.Parameter do ViewModel). Como resultado da alteração da propriedade
privada Parameter, o DetailModel de detalhes chama seu método protegido
OnParameterChanged, que você pode substituir manualmente para obter e usar o novo valor
do parâmetro.
Mostre-me

Um projeto de amostra completo está disponível no banco de dados de Exemplos de código


DevExpress em http://www.devexpress.com/example=T144439.

Relações ViewModel
(ISupportParentViewModel)
Os modelos de exibição herdados do ViewModelBase podem estar
relacionados entre si com uma relação pai-filho. Isso é alcançado com
a interface ISupportParentViewModel , implementada na classe
ViewModelBase. Se você usar o mecanismo POCO , a interface
ISupportParentViewModel é implementada automaticamente quando
você cria um objeto POCO com a classe ViewModelSource .
A interface ISupportParentViewModel é mostrada abaixo.
C#
public interface ISupportParentViewModel {
object ParentViewModel { get; set; }
}

Quando você cria um modelo de exibição detalhada de outro modelo


de exibição, você pode passar o modelo de exibição principal para o
detalhe usando
a propriedade ISupportParentViewModel.ParentViewModel . Isso
permite que o View View do detalhe acesse os Serviços que estão
registrados para o modelo de exibição principal.
C#
public class DetailViewModel : ViewModelBase {
public IMessageBoxService MessageBoxService { get { return
GetService<IMessageBoxService>(); } }
}
public class MainViewModel : ViewModelBase {
public IMessageBoxService MessageBoxService { get { return
GetService<IMessageBoxService>(); } }
public DetailViewModel DetailViewModel { get; private set; }
public MainViewModel() {
DetailViewModel = new DetailViewModel();
((ISupportParentViewModel)DetailViewModel).ParentViewModel
= this;
}
}

O parâmetro ParentViewModel pode ser definido no XAML com


a propriedade anexada ViewModelExtensions.ParentViewModel. O
esquema que demonstra como o Main ViewModel é propagado para
um DetailModel de detalhes é mostrado no seguinte diagrama:

DIAGRAMA
Aqui, a Vista principal contém uma instância de uma Vista de
detalhes. Os DataContexts de cada um são o modelo principal
ViewModel e Detail View, respectivamente. A tarefa é passar o Main
ViewModel para o Detail ViewModel. Para realizar isso, atribua o Main
ViewModel
a propriedade ViewModelExtensions.ParentViewModel anexado na
instância View Detail.
XAML
<UserControl x:Class="Example.View.MainView" ...
xmlns:ViewModel="clr-namespace:Example.ViewModel"
xmlns:View="clr-namespace:Example.View"

xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm">
<UserControl.DataContext>
<ViewModel:MainViewModel/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot">
...
<!-- It is necessary to use the ElementName binding mode,
because the DetailView's DataContext is a DetailViewModel object.
That is why the following regular binding cannot be used in
this case: dxmvvm:ViewModelExtensions.Parameter="{Binding}"
Instead, use one of the following constructions:-->
<View:DetailView
dxmvvm:ViewModelExtensions.ParentViewModel="{Binding DataContext,
ElementName=LayoutRoot}"/>
<ContentControl>
<ContentControl.ContentTemplate>
<DataTemplate>
<View:DetailView
dxmvvm:ViewModelExtensions.ParentViewModel="{Binding DataContext,
Source={x:Reference LayoutRoot}}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
...
</Grid>
</UserControl>

A classe ViewModelExtensions , que expõe a propriedade


anexada ParentViewModel na instância View Detail, executa todas as
ações necessárias para passar dados para o DetailModel
Detail. Quando a propriedade anexada ParentViewModel é definida
na Vista de detalhes, a classe ViewModelExtensions identifica se o
DataContext do View é um ViewModel (um objeto ViewModelBase ou
para ser mais preciso, se o DataContext é um objeto que implementa
a interface ISupportParentViewModel ). E se assim for, o novo valor é
passado para ViewModel da Visualização Detalhada (é atribuído à
propriedade privada ISupportParentViewModel.ParentViewModel do
ViewModel). Como resultado da alteração do
modelo ParentViewpropriedade privada, o DetailModel de detalhes
chama seu método protegido OnParentViewModelChanged, que
você pode substituir manualmente para obter e usar o Main
ViewModel.
O tópico de documentação a seguir contém um exemplo de como usar
serviços quando os Modelos de Visualização estão relacionados entre
si com a relação pai-filho: DXMessageBoxService.