Página Inicial > Windows Phone 7 > MVVM no Windows Phone 7 – Parte 1 (Commands)

MVVM no Windows Phone 7 – Parte 1 (Commands)

O padrão MVVM (Model-View-ViewModel) é uma especialização do padrão Presenter porém utilizando capacidades específicas de Silverlight e WPF como data binding, command e behaviors. O MVVM é semelhante a muitos outros padrões que separam a camada de apresentação da camada de lógica, sendo assim toda a lógica de negócio pode ser programada para qualquer tipo de interface XAML. Utilizando MVVM o código da sua view irá ficar totalmente limpo e muito mais fácil de dar manutenção. Sem utilizar MVVM o simples clique de um botão é definido da seguinte forma:

<Button Click="Button_Click" />
private void Button_Click(object sender, RoutedEventArgs e)
        {

        }

Mas qual o problema desta abordagem? Bom dou um bom exemplo: Você está desenvolvendo um sitema que tem um cliente Desktop WPF e um cliente móvel em WP7. Se os códigos estiverem todos nas views, terá que recodificar tudo em cada cliente. Com a utilização dos viewModels, você irá codificar esta ação uma única vez tanto para WPF quando para WP7. Deixando a teoria de lado, vamos por a mão na massa. Requisitos:

  • Prism v4 para Windows Phone 7

Crie um novo projeto utilizando o template Windows Phone Application, e coloque o nome de CommandWP7. Com nosso projeto criado adicione um botão à MainPage.xaml ScreenShot016

<!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Button Content="Botão com Command" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>

No WP7 por enquanto não temos uma propriedade Command e CommandParameter como no silverlight e wpf, então teremos que utilizar um Behavior para nosso command funcionar. Adicione a referência ao assembly System.Windows.Interactivity ao seu projeto e coloque no seu xaml o uso deste assembly

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

e modificaremos o código do nosso button para

            <Button Content="Botão com Command" HorizontalAlignment="Center" VerticalAlignment="Center">
                <i:Interaction.Behaviors>

                </i:Interaction.Behaviors>
            </Button>

Agora teremos que criar o nosso ButtonCommand que será uma implementação de um beehavior que irá fazer o binding do nosso botão com o comando no ViewModel, adicione a referência ao assembly Microsoft.Practices.Prism e Microsoft.Practices.Prism.Interactivity, crie uma nova classe e dê o nome de ButtonCommand.

    public class ButtonCommand : Behavior<Button>
    {
        public static readonly DependencyProperty CommandParameterBindingProperty =
            DependencyProperty.Register("CommandParameterBinding", typeof(Binding), typeof(ButtonCommand), new PropertyMetadata(HandleBindingChanged));

        public static readonly DependencyProperty CommandBindingProperty =
            DependencyProperty.Register("CommandBinding", typeof(Binding), typeof(ButtonCommand), new PropertyMetadata(HandleBindingChanged));

        private readonly BindingListener commandBindinglistener;
        private readonly BindingListener parameterBindinglistener;
        private ButtonClickCommandBinding binding;

        public ButtonCommand()
        {
            this.commandBindinglistener = new BindingListener(this.HandleCommandBindingValueChanged);
            this.parameterBindinglistener = new BindingListener(this.HandleCommandParameterBindingValueChanged);
        }

        public Binding CommandBinding
        {
            get { return (Binding)GetValue(CommandBindingProperty); }
            set { SetValue(CommandBindingProperty, value); }
        }

        public Binding CommandParameterBinding
        {
            get { return (Binding)GetValue(CommandParameterBindingProperty); }
            set { SetValue(CommandParameterBindingProperty, value); }
        }

        protected ICommand Command { get; set; }

        protected object CommandParameter { get; set; }

        protected override void OnAttached()
        {
            this.commandBindinglistener.Element = this.AssociatedObject;
            this.parameterBindinglistener.Element = this.AssociatedObject;
            this.CreateBinding();
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            this.commandBindinglistener.Element = null;
            this.parameterBindinglistener.Element = null;
            base.OnDetaching();
        }

        protected void OnBindingChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.Property == CommandBindingProperty)
            {
                this.commandBindinglistener.Binding = (Binding)e.NewValue;
            }

            if (e.Property == CommandParameterBindingProperty)
            {
                this.parameterBindinglistener.Binding = (Binding)e.NewValue;
            }

            this.CreateBinding();
        }

        private static void HandleBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((ButtonCommand)sender).OnBindingChanged(e);
        }

        private void HandleCommandBindingValueChanged(object sender, BindingChangedEventArgs e)
        {
            this.CreateBinding();
        }

        private void HandleCommandParameterBindingValueChanged(object sender, BindingChangedEventArgs e)
        {
            this.CreateBinding();
        }

        private void CreateBinding()
        {
            if (this.commandBindinglistener.Value != null)
            {
                if (this.binding != null)
                {
                    this.binding.Detach();
                }

                this.binding = new ButtonClickCommandBinding(
                    this.AssociatedObject,
                    (ICommand)this.commandBindinglistener.Value,
                    () => this.parameterBindinglistener.Value);
            }
        }

        public class ButtonClickCommandBinding
        {
            private readonly ICommand command;
            private readonly Button button;
            private readonly Func<object> parameterGetter;

            public ButtonClickCommandBinding(Button button, ICommand command, Func<object> parameterGetter)
            {
                this.command = command;
                this.button = button;
                this.parameterGetter = parameterGetter;

                this.command.CanExecuteChanged += this.CommandCanExecuteChanged;
                this.button.Click += this.IconButtonClicked;
                this.button.IsEnabled = this.command.CanExecute(this.parameterGetter());
            }

            public void Detach()
            {
                this.button.Click -= this.IconButtonClicked;
                this.command.CanExecuteChanged -= this.CommandCanExecuteChanged;
            }

            private void IconButtonClicked(object s, EventArgs e)
            {
                this.command.Execute(this.parameterGetter());
            }

            private void CommandCanExecuteChanged(object s, EventArgs ea)
            {
                this.button.IsEnabled = this.command.CanExecute(this.parameterGetter());
            }
        }
    }

Faça o build do projeto e volte ao nosso botão. Teremos que adicionar o namespace do projeto em nosso xaml

xmlns:local="clr-namespace:CommandWp7"

e então adicionar o nosso behavior de command ao nosso botão fazendo o binding para o comando no viewmodel.

            <Button Content="Botão com Command" HorizontalAlignment="Center" VerticalAlignment="Center">
                <i:Interaction.Behaviors>
                    <local:ButtonCommand CommandBinding="{Binding ViewCommand}"/>
                </i:Interaction.Behaviors>
            </Button>

Para criar o ViewModel, crie uma nova classe  e coloque o nome de MainPageViewModel

public class MainPageViewModel
    {

        public DelegateCommand ViewCommand { get; set; }

        public MainPageViewModel()
        {
            this.ViewCommand = new DelegateCommand(ViewCommandInvoke);
        }

        public void ViewCommandInvoke()
        {
            MessageBox.Show("Comando executado com sucesso");
        }

    }

e por último no MainPage.xaml.cs setamos o DataContext da view para o viewModel

    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new MainPageViewModel();
        }
    }

agora é só executar. ScreenShot019 ScreenShot018 O codigo fonte pode ser baixado aqui.

Categories: Windows Phone 7 Tags: ,
  1. Nenhum comentário ainda.
  1. Nenhum trackback ainda.