Laden...

EventToCommand mit MVVM - Silverlight

Erstellt von ProGamer vor 12 Jahren Letzter Beitrag vor 12 Jahren 8.745 Views
P
ProGamer Themenstarter:in
660 Beiträge seit 2008
vor 12 Jahren
EventToCommand mit MVVM - Silverlight

Beschreibung:
Hallo zusammen,

ich weiss nicht wofür das im MVVM nützlich sein sollte da man ja eigentlich alles mittels Bindings lösen kann, aber dennoch Poste ich mal eine Möglichkeit um einen Command mittels Event auszulösen

Wichtig ist dass vorher das Blend SDK für Silverlight Heruntergeladen und Installiert wird.

Ein Verweis auf die System.Windows.Interactivity (zu finden unter C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0\Libraries) hinzugefügt wird


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.Reflection;
using System.Linq;

namespace EventToCommand
{
    public class EventToCommandCore : TriggerAction<DependencyObject>
    {

        #region DelegateCommands

        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register( "CommandParameter", typeof( object ), typeof( EventToCommandCore ), null );

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register( "Command", typeof( ICommand ), typeof( EventToCommandCore ), null );

        public static readonly DependencyProperty InvokeParameterProperty =
            DependencyProperty.Register( "InvokeParameter", typeof( object ), typeof( EventToCommandCore ), null );

        #endregion

        #region Properties And Fields

        public object InvokeParameter
        {
            get { return this.GetValue( InvokeParameterProperty ); }
            set { this.SetValue( InvokeParameterProperty, value ); }
        }

        public ICommand Command
        {
            get { return (ICommand)this.GetValue( CommandProperty ); }
            set { this.SetValue( CommandProperty, value ); }
        }

        public string CommandName{get; set;}

        public object CommandParameter
        {
            get { return this.GetValue( CommandParameterProperty ); }
            set { this.SetValue( CommandParameterProperty, value ); }
        }

        #endregion

        #region methods

        protected override void Invoke( object parameter )
        {
            this.InvokeParameter = parameter;

            if ( this.AssociatedObject != null )
            {
                ICommand Command = this.ResolveCommand();
                if ( Command != null && Command.CanExecute( this.CommandParameter ) )
                {
                    Command.Execute( this.CommandParameter );
                }
            }
        }

        private ICommand ResolveCommand()
        {
            ICommand command = null;

            if ( this.Command != null )
            {
                return this.Command;
            }

            var frmElement = (FrameworkElement)this.AssociatedObject;

            if ( frmElement != null )
            {
                object dtContext = frmElement.DataContext;

                if ( dtContext != null )
                {
                    PropertyInfo cmdPropertyInfo = dtContext.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance ).
                        FirstOrDefault(
                            c =>
                            typeof( ICommand ).IsAssignableFrom( c.PropertyType ) &&
                            string.Equals( c.Name, this.CommandName, StringComparison.Ordinal )
                            );
                    if ( cmdPropertyInfo != null )
                    {
                        command = (ICommand)cmdPropertyInfo.GetValue( dtContext, null );
                    }
                }
            }

            return command;
        }

        #endregion

    }
}


Das ganze kann dann folgendermaßen verwendet werden


<UserControl x:Class="DemoApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:cmd="clr-namespace:EventToCommand"
             xmlns:VM="clr-namespace:DemoApp.ViewModel"
             >

    <UserControl.Resources>
        <VM:DemoAppViewModel x:Key="DAVM" />
    </UserControl.Resources>
    
    <StackPanel x:Name="LayoutRoot" Background="White" DataContext="{StaticResource DAVM}">
                    <sdk:DatePicker Name="DatePickerControl"
                                    Margin="5"
                                    SelectedDateFormat="Short"
                                    IsDropDownOpen="False"
                                    SelectedDate="{Binding Path=DatePickerProperty, Mode=TwoWay}"
                           <i:Interaction.Triggers>
                            <i:EventTrigger EventName="SelectedDateChanged">
                                <cmd:EventToCommandCore Command="{Binding Path=SelectionChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=InvokeParameter}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>

                    </sdk:DatePicker>
                </StackPanel>

Im ViewModel könnte es dann Folgendermaßen aussehen:
(Nur Methoden definition)


        private void SelectionChangedExecute( object state )
        {
            if ( state is SelectionChangedEventArgs )
            {
                //Do Some Stuff
            }
        }

Wie gesagt ich habe keine Ahnung wofür man das brauchen sollte...

Schlagwörter: Event, Command, Silverlight

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

742 Beiträge seit 2005
vor 12 Jahren

Ich finds ja lustig, dass du keine Ahnung hast wie man das brauchen, aber man kann das z.B. gut für das Loaded Event brauchen und dann Daten laden bzw. neu laden.

I
279 Beiträge seit 2008
vor 12 Jahren

Wie gesagt ich habe keine Ahnung wofür man das brauchen sollte...

Wieso machst du dir dann die Mühe so etwas zu programmieren?

Soetwas, ebenfalls "EventToCommand" benannt existiert schon im MVVM Light Toolkit von Codeplex ^^

P
ProGamer Themenstarter:in
660 Beiträge seit 2008
vor 12 Jahren

@malignate: danke für die Verwendungsmöglichkeit ^^

@iced-t89: Wie gesagt ich weiss nicht wofür man es gebrauchen kann da ja sogut wie alles über Bindings möglich ist.

Als ich mir den Code zusammengesucht hatte brauchte ich eine möglichkeit um vom DatePicker das CalendarClosed-Event im ViewModel zu verarbeiten. Mittlerweile ist dafür ein Converter im Einsatz.

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

I
1.739 Beiträge seit 2005
vor 12 Jahren

Das MVVM-"Pattern" kam leider erst nach der Entwicklung der WPF(/E) auf.
Sinn und Zweck des MVVM-"Patterns" ist die Entkopplung von Logik und UI, inkl. Testbarkeit der Logik mittels Unittests. (Wie bei richtigen Patterns auch.)
Databinding ist dort an sich ok, wenn man die Logik des ButtenClick nicht in Codebehinddatei abhandelt, sondern als Aktion betrachtet die an den Controller(Viewmodell) weitergeleitet wird.
In der WPF(/E) wurden leider Routet Events und ähnliche Scheusslichkeiten eingeführt die dieser Trennung entgegenwirken. Jedoch gibt es Workarounds...
MVVM is alles andere als Perfekt und wird wohl irgendwann durch das gute MVC ersetzt, wie bei ASP.Net(Da gab es auch erst ein propagiertes Ersatz"pattern")...
Natürlich geht MVC immer... - Besser jedoch mit Unterstützung der IDE und Herstellerenthusiasmus.