Blue Orange Green Pink Purple

Archive for March, 2010

You can use the search form below to go through the content and find a specific post or page:

Mar 26

HowTo: Deploy ASP.NET MVC auf ASP.NET Hostings

So, heute mal kein Codelastiger Eintrag sondern eher einer in Richtung Konfiguration.

Für einen Freund war ich letztens auf der Suche nach guten Webhostings für ASP.NET MVC. Nachdem ich irgendwie nicht wirklich fündig geworden bin, hab ich mir mal die Frage gestellt: “Warum eigentlich ein spezielles Hosting für ASP.NET MVC?”

Ja warum eigentlich?
ASP.NET MVC ist eigentlich nur ein Aufsatz auf den bereits schon lange bestehenden ASP.NET Kern. Das heißt, es erweitert die bestehende Funktionalität ohne dabei jegliche Konfigurationen an der Hardware bzw. am OS vorzunehmen. Dieser Aufsatz befindet sich in drei kleinen Assemblies:

  • System.Web.Mvc
  • System.Web.Routing
  • System.Web.Abstractions

Deployt man jetzt diese Assemblies mit seiner ASP.NET MVC Anwendung mit auf den Server, muss dort auch nicht zwingend das ASP.NET MVC Framework über einen Installer (sprich im GAC) installiert sein. Wie das Deployment im Detail funktioniert kann man hier nachlesen http://msdn.microsoft.com/en-us/library/dd410407.aspx.

Die Moral von der Geschichte ist jetzt folgende: Um ASP.NET MVC Webseiten zu deployen reicht ein einfachs MS ASP.NET Hosting vollkommen aus. Einzig und alleine die Vorraussetzung, das .NET 3.5 auf dem Server laufen muss schränkt einem beim Suchen nach dem richtigen Webhosting Provider ein.

In diesem Sinne.

Mar 09

MVVM: Behandeln von Events über Commands, Teil 2

In meinem letzten Eintrag gings darum, wie man Events eines WPF Controls auf Commands eines ViewModels umleiten kann. Verwendet habe ich dort die Attached Properties von WPF. Das Problem dabei war aber, dass man für diese Attached Properties für ein Control nur einmal verwenden kann. Das heißt, dass man zB für ein Border-Control nicht zugleich den MouseEnter- und MouseLeave-Event auf ein Command umleiten kann. Um das mit der Lösung der Attached Properties zu erreichen, wäre es notwendig, einen zusätzlichen Wrapper rund um das Border-Control einzuführen:


<Border Margin="50"
        commanding:AttachedCommand.Command="{Binding MouseEnterCommand}"
        commanding:AttachedCommand.EventName="MouseEnter">
   <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
           Background="YellowGreen" CornerRadius="20"
           commanding:AttachedCommand.Command="{Binding MouseLeaveCommand}"
           commanding:AttachedCommand.CommandParameter="Border #1"
           commanding:AttachedCommand.EventName="MouseLeave">
   </Border>
</Border>

Um diesem Umweg zu vermeiden, möchte ich heute einen neuen Ansatz präsentieren, der die seit Expression Blend 3 zur Verfügung stehenden Behaviors und Triggers verwendet.

TargetedTriggerAction aus System.Windows.Interactivity verwenden
Die Idee dahinter ist, einen Trigger zu erstellen, der diverse Dependency Properties implementiert. Diese Properties müssen deshalb Dependency Properties sein, weil wir sonst kein Databinding darauf anwenden können. Eine dieser DP ist vom Typ ICommand — also das Command, das wir ausführen wollen, wenn der Trigger gestartet wird:


public ICommand Command
{
   get { return (ICommand)GetValue(CommandProperty); }
   set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
 ´  DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandTrigger),
                                new PropertyMetadata(null, OnCommandChanged));

Wichtig bei der Dependency Property ist der Callback OnCommandChanged, der dann aufgerufen wird, wenn der DP ein neuer Wert zugewiesen wird.
Warum ist das wichtig? Bei einer Command-Property, die out-of-the-box bei bereits vorhandenen Controls wie Button vom Framework mitgeliefert wird, wird der Status des Controls abhängig von der CanExecute-Methode des Commands verändert. Also liefert CanExecute false zurück, dann wird der Button, der das Command verwendt, deaktiviert. Genau diese Funktionalität müssen/sollen/wollen wir mit unserem Trigger auch abbilden.

Deshalb registrieren wir uns  in der OnCommandChanged Methode auf den CanExecuteChanged Event, den jede Klasse, die ICommand implementiert, selbstverständlich auch implementieren muss. Sobald dieser Event geworden wurde, wollen wir prüfen, ob unser Control, das ein Binding auf das Command besitzt, noch einen gültigen Status besitzt:


private static void OnCommandChanged(DependencyObject action, DependencyPropertyChangedEventArgs e)
{
   ((CommandTrigger)action)._RefreshCommandHandling((ICommand)e.OldValue, (ICommand)e.NewValue);
}

private void _RefreshCommandHandling(ICommand oldCommand, ICommand newCommand)
{
   if (oldCommand != null) oldCommand.CanExecuteChanged -= new EventHandler((sender, args) => _UpdateCanExecute());
   if (newCommand != null) newCommand.CanExecuteChanged += new EventHandler((sender, args) => _UpdateCanExecute());

   _UpdateCanExecute();
}

Wir bekommen im Eventhandler über die EventArgs den alten und den neuen Wert, den die Dependency Property angenommen hat. Das wir haben die Möglichkeit, uns vom Event des alten Commands (also des alten Wertes der DP) zu entfernen und uns auf den Event des neuen Commands (also der neue Wert der DP) zu registrieren. In der _UpdateCanExecute() Methode prüfen wir schlussendlich, ob das Control, auf dem der Trigger angewendet wird, noch den gültigen Status aufgrund von CanExecute besitzt:


private void _UpdateCanExecute()
{
   if (this.Command == null) return;

   RoutedCommand command = this.Command as RoutedCommand;

   if (command != null) this.IsEnabled = command.CanExecute(this.CommandParameter, this.CommandTarget);
   else this.IsEnabled = this.Command.CanExecute(this.CommandParameter);

   if (this.Target != null && this.SyncOwnerIsEnabled) this.Target.IsEnabled = this.IsEnabled;
}

Im XAML Code wird dieser Trigger jetzt ganz einfach verwendet, indem wir zuerst den richtigen Namespace einbinden und anschließend den Trigger auf ein beliebiges Control anwenden:


<Border>
   <interactivity:Interaction.Triggers>
      <interactivity:EventTrigger EventName="MouseEnter">
         <commanding:CommandTrigger Command="{Binding MouseEnterCommand}" />
      </interactivity:EventTrigger>

      <interactivity:EventTrigger EventName="MouseLeave">
         <commanding:CommandTrigger Command="{Binding MouseLeaveCommand}"  />
      </interactivity:EventTrigger>
   </interactivity:Interaction.Triggers>
</Border>

Das tolle an diesem Trigger ist jetzt, dass er mehrmals auf ein und dem selben Control angewendet werden kann. Wir können jetzt also mehrere Events über den selber Trigger behandeln und auf Commands weiterleiten.

Das Demoprojekt gibts wie immer unter http://downloads.juergenoberngruber.at/blog/CommandAction_Trigger.zip.

In diesem Sinne.

Mar 07

MVVM: Behandeln von Events über Commands, Teil 1

Durch WPF ist eine neue Softwarearchitektur sehr in Mode gekommen: MVVM (Model – View – ViewModel; http://en.wikipedia.org/wiki/Model_View_ViewModel). Dank Databinding und Commanding ist diese Softwarearchitektur in WPF relativ einfach umsetzbar. Ein Problem, dass es jedoch nach wie vor gibt, ist die oft fehlende Command-Property bei diversen WPF Controls bzw. die fehlende Möglichkeit, Commands aufgrund von Events aufzurufen.

Ein Beispiel?
Angenommen wir haben eine View, die eine ListView verwendet. Diese ListView stellt einen Event namens “SelectionChanged” zur Verfügung. Wir haben über WPF nun keine Standard-Lösung, wie wir diesen Event auf ein Command einer ViewModel Klasse leiten. Also, wie wir ein Command aufrufen, sobald der Event der ListView gefeuert wird/wurde.

Abhilfe über Attached Properties
Die Lösung liegt in den von WPF eingeführten Attached Properties (http://msdn.microsoft.com/en-us/library/ms749011.aspx).

Wir wollen also erreichen, das ein Command ausgefürt wird, sobald eine Event gefeuert wird. Wir erstellen uns zuerst eine Klasse, die zwei unterschiedliche Attached Properties beinhaltet: Command und EventName. Command ist das Command, das ausgeführt werden soll, sobald der Event gefeuert wird. EventName ist der Name des Events, auf den wir horchen wollen — also der Event, der das Command triggern soll. Wichtig dabei ist, dass wir Callback-Methoden registrieren, die aufgerufen werden, sobald die Attached Property gesetzt wird. In diesen Eventhandler registrieren wir über .NET Reflection eine anonyme Methode als Eventhandler für den Event, der über die Attached Property angegeben wurde:


public class AttachedCommand : DependencyObject
{
   private static IDictionary<DependencyObject, CommandParameter> Parameter { get; set; }

   public static ICommand GetCommand(DependencyObject obj)
   {
      return (ICommand)obj.GetValue(CommandProperty);
   }
   public static void SetCommand(DependencyObject obj, ICommand value)
   {
      obj.SetValue(CommandProperty, value);
   }
   public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(AttachedCommand), new UIPropertyMetadata(CommandChanged));

   public static string GetEventName(DependencyObject obj)
   {
      return (string)obj.GetValue(EventNameProperty);
   }
   public static void SetEventName(DependencyObject obj, string value)
   {
      obj.SetValue(EventNameProperty, value);
   }
   public static readonly DependencyProperty EventNameProperty =
       DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(AttachedCommand), new UIPropertyMetadata(EventNameChanged));

   public static void CommandChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
   {
      if (!Parameter.ContainsKey(dependencyObject)) Parameter.Add(dependencyObject, CommandParameter.Default);

      Parameter[dependencyObject].Command = args.NewValue as ICommand;

      _AttachEventHandler(dependencyObject);
   }

   public static void EventNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
   {
      if (!Parameter.ContainsKey(dependencyObject)) Parameter.Add(dependencyObject, CommandParameter.Default);

      Parameter[dependencyObject].EventName = args.NewValue as string;

      _AttachEventHandler(dependencyObject);
   }

   private static void _AttachEventHandler(DependencyObject dependencyObject)
   {
      if (dependencyObject == null) throw new ArgumentNullException("DependencyObject is null");
      if (!Parameter.ContainsKey(dependencyObject)) return;

      CommandParameter parameter = Parameter[dependencyObject];
      if (parameter.Command == null || string.IsNullOrEmpty(parameter.EventName)) return;

      EventInfo eventInfo = dependencyObject.GetType().GetEvent(parameter.EventName);
      if (eventInfo == null)
          throw new InvalidProgramException(string.Format("Cannot find am event with the name <{0}>.", parameter.EventName));

      parameter.Callback = _CreateHandler(eventInfo, () => { parameter.Command.Execute(null); });

      eventInfo.AddEventHandler(dependencyObject, parameter.Callback);
   }
}

Parameter speichert eine Liste von CommandParameter, die notwendige Metadaten für das Commanding speichert. Wir brauchen diese Liste deshalb, weil wir die Attached Properties ja auf unterschiedlichen WPF Controls verwenden können. In der _AttachEventHandler Methode holen wir uns den Event über Reflection und speichern einen neuen Eventhandler für den Event, der schlussendlich das Command ausführt.

In der View können wir diese Attached Properties jetzt ganz einfach verwenden, in dem wir zuerst den Namespace einbinden und anschließend auf einem beliebigen Controls die Properties anwenden:

<Window x:Class="CommandAction.Views.Master"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:commanding="clr-namespace:CommandAction.Commanding"
             xmlns:viewmodels="clr-namespace:CommandAction.ViewModels"
             Title="Master" Height="306" Width="722"
             WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <viewmodels:MasterViewModel />
    </Window.DataContext>

    <Border Margin="50" CornerRadius="20" Background="YellowGreen"
               commanding:AttachedCommand.Command="{Binding MouseLeaveCommand}" commanding:AttachedCommand.EventName="MouseLeave">
    </Border>

</Window>

Problem?
Soweit so gut. Das einzige Problem das wir über diese Methode bekommen ist, dass wir für ein WPF Control nur einen Event auf ein Command umleiten können, weil für die Attached Properties nur einmal auf ein WPF Control anwenden können. Wollen wir mehrere Events auf Commands umleiten, müssen wir uns einen anderen Weg einfallen lassen. Angenommen wir wollen für ein Image Control den MouseEnter und MouseLeave Event über zwei unterschiedliche Commands behandeln, können wir das mit der Attached Property Variante nicht umsetzen (außer wir wrappen rund um das Image Control ein anderes Control).
Lösen können wir das mit den seit Expression Blend 3 zur Verfügung stehenden Behaviors/Triggers. Wie das ganze funktioniert, erklär ich in meinem nächsten Post, der in den nächsten Tagen kommen wird.

Das Demoprojekt gibts wie immer unter http://downloads.juergenoberngruber.at/blog/CommandAction.zip zu finden.

In diesem Sinne.

  • Recent Posts
    • HowTo: Eigene Regeln für Microsoft StyleCop erstellen
    • HowTo: Microsoft StyleCop Integration mit Visual Studio und MSBuild
    • HowTo: Eigene Templates für Visual Studio 2008 erstellen, Teil 2
    • HowTo: Eigene Templates für Visual Studio 2008 erstellen, Teil 1
    • Performance des Cassini Webservers in Kombination mit Firefox
  • Archives
    • June 2010 (2)
    • May 2010 (3)
    • March 2010 (3)
    • February 2010 (4)
    • January 2010 (3)
    • December 2009 (1)
    • November 2009 (9)
  • Tags
    .net AOP ASP.NET ASP.NET MVC blend Bootmanager C# ci Codequality Configuration Continuous Integration css Cursor DateTime DDD Deployment dynamisch emit Exrpession Extensibility Fluent HowTo Microsoft MVVM Pattern PostSharp Reflection Repository ruby silverlight Software Design StyleCop System teamcity Templates VHD Virtual Images Visual Studio Vorlagen web Windows 7 Windows Mobile WinForms WPF XAML
  • About

    Jürgen Oberngruber is a project manager and software architect living in Wels, Austria and currently working at ecomplexx Austria, Wels. During his study at the University of Applied Sciences in Hagenberg, Austria he gained a deep knowledge in the field of software engineering using a lot of different programming languages. Since a few years he's focusing on the Microsofts .NET platform including all relevant technologies. One of his passion is to explore, to test and to evaluate new technologies and programming languages (mostly in the field of Microsofts .NET platform). Checkout more information on www.juergenoberngruber.at

  • Meta
    • Log in
    • Entries RSS
    • Comments RSS
    • WordPress.org
  • Archives
    • June 2010
    • May 2010
    • March 2010
    • February 2010
    • January 2010
    • December 2009
    • November 2009
  • Search






  • Home

© Copyright Jürgen Oberngruber's Blog. All rights reserved.
Designed by FTL WordPress Themes brought to you by DT Web Template

Back to Top