.NET Blog   ·   .NET Casts   ·   .NET GUI Foren   ·   .NET BlogBook   ·   WPF Blogger   ·   visual studio one   ·   ASP.NET professional

  • ACHTUNG - NEUES BLOG

    Ab sofort steht unter http://devtyr.norberteder.com mein neues Blog zur Verfügung. Dieses Blog wird nicht weiter betreut, bleibt aber erhalten. Neue Eintr%auml;ge erfolgen nur mehr im neuen Blog. Kommentare werden ebenfalls nicht mehr behandelt. Wer weiterhin meinen Einträgen und Aktivitäten folgen möchte, möge bitte RSS-Feeds, Verlinkungen etc. an die neue Location anpassen.
Download .NET Essentials Installer
Trickkiste

Mit List.ForEach durch Listen iterieren

31.01.08 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Die meisten Leser werden wohl for und foreach kennen, um durch Listen zu iterieren. Es gibt jedoch bei den generischen Listen (auch Arrays) eine Methode ForEach.

Damit ist es möglich, eine Aktion auf jedes Element der Liste auszuführen. Nachfolgend ein Beispiel welches mit einer anonymen Methode arbeitet und die Methode ForEach verwendet:
List<int> testList = new List<int>();

for (int i = 0; i < 100; i++)
    testList.Add(i);

int sum = 0;

testList.ForEach(delegate(int val)
{
    sum += val;
});

Console.WriteLine(sum.ToString());

Der interessierte Leser fragt sich nun an dieser Stelle, wie es mit der Performance der einzelnen Möglichkeiten aussieht, woraus sich auch ergibt, welche Variante eingesetzt werden sollte (nicht ganz, denn in Bereichen an denen Performance nicht ganz so wichtig ist, entscheiden auch andere Aspekte).

Hierzu kann ich auf den Eintrag Performance of foreach vs. List.ForEach von Dustin Campbell verweisen. Diesbezügliche Fragen sollten damit aus dem Weg geräumt werden.
  2 Kommentare - 1568 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


String.IsNullOrEmpty als Extension Method

29.01.08 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Über Extension Methods hatte ich bereits berichtet. Einfach können hier beliebige Typen um Methoden erweitert werden.

Nun gibt es die statische Methode String.IsNullOrEmpty um zu überprüfen, ob ein String einen Wert enthält oder nicht.

Thomas Freudenberg hat hierzu ein kleines Beispiel erweitert, wie diese statische Methode als Extension Method genutzt werden kann und daher bei öfterer Verwendung doch einiges an Zeit sparen kann. Nette Idee.
  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


.NET BlogBook mit eigener Webpräsenz

27.01.08 - .NET, Grundlagen, Base Framework, WPF, ASP.NET, Silverlight, Mobile Devices, Datenverwaltung, Visual Studio, Allerlei, Internet, Community
Beitrag von Norbert Eder
 Das .NET BlogBook ist ab sofort auf einer eigenen Webpräsenz zu finden. Der Hintergrund besteht aus mehreren Punkten, wovon ich einige hier nennen möchte.

.NET Casts
Ursprünglich wurde das .NET BlogBook als Nebenprodukt von .NET Casts geführt. Thematisch passten beide Bereiche nicht optimal zusammen, wodurch diese nun getrennt wurden. Auf beiden Seiten wird nun der eigentilche Bereich entsprechend gefördert.

Andrang
Das .NET BlogBook darf sich größter Beliebtheit erfreuen, wodurch eine eigene Webpräsenz fast unumgänglich wurde. Dadurch besteht nun die Möglichkeit, zukünftig besser auf unsere Leser eingehen zu können. Aber dazu möchte ich vorerst noch nicht zuviel verraten.

Dieser Schritt soll das .NET BlogBook zu einem eigenständigen Produkt ausbauen und zukünftig auch wesentlich zur Verbesserung der Qualität beitragen.

Hier nun die Adresse, unter der das .NET BlogBook zukünftig zu erreichen ist:
http://www.dotnet-blogbook.com

PS: Die Inhalte bleiben noch die nächsten Tage auf der .NET Casts Website erhalten, werden anschließend jedoch mit einer entsprechenden Meldung von der Site genommen.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


dotnet-forum.de ist online

25.01.08 - .NET, Allerlei, Internet, Community
Beitrag von Norbert Eder
  Aktuell gibt es ja wahrlich eine Flut von neuen .NET Communities. Dieses Mal hat sich Jan Welker von .NET Snippets aufgemacht, ein neues Forum rund um das Microsoft .NET Framework zu starten.

Wie es auch sein muss, setzt er mit dem Forum auf ein .NET basiertes System.

Ich bin schon gespannt, welche der neuen Communities sich langfristig im deutschsprachigen Raum etablieren kann.

Hier geht es zum Forum: .NET-Forum.de
  2 Kommentare - 894 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


.NET Entwickler gesucht

24.01.08 - .NET, Allerlei
Beitrag von Norbert Eder
  Mein Arbeitgeber, die UPPER Network GmbH ist auf der Suche nach .NET Entwicklern. Als Standort kommen Wien oder Graz in Frage.

Weitere Informationen rund um uns, was wir tun, was wir bieten, was wir jedoch auch verlangen sind in der nachfolgenden Stellenausschreibung (PDF) zu finden:

Stellenausschreibung .NET Entwickler

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Globales Exception-Handling in WPF

22.01.08 - .NET, WPF
Beitrag von Norbert Eder
 Wie in jeder anderen Anwendung, kann natürlich auch in einer WPF-Applikation der Fehlerteufel stecken. Werden etwaige Fehlverhalten nicht abgefangen, kommt es zu ungewollten Abstürzen, die nicht nur beim Endkunden/-benutzer nur sehr unwillig aufgenommen werden. es gilt also, sämtliche Fehler abzufangen.

Grundsätzlich gibt es beim Exception-Handling keine Unterschiede zum Windows-Forms-Pendant, da es sich ja um eine Funktionalität des Frameworks handelt. Wobei es jedoch einen Unterschied gibt, ist das globale Abfangen von Fehlern.

Implementierung


Hat man bei einer Windows-Forms-Anwendung einen try-catch-Block um den Aufruf des Hauptfensters gelegt, steht in der Windows Presentation Foundation das Event DispatcherUnhandledException zur Verfügung. Hier stehen nun zwei Wege zur Verfügung, wie der dazu notwendige Eventhandler gesetzt werden kann.

Die erste Variante besteht in der Deklaration in der App.xaml, wie folgt:
<Application x:Class="WpfExceptionDemo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml" 
    DispatcherUnhandledException="App_DispatcherUnhandledException">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Weiters kann das Event, wie unter Windows Forms, direkt per Code abonniert werden:
public partial class App : Application
{
    public App()
    {
        this.DispatcherUnhandledException += 
            new DispatcherUnhandledExceptionEventHandler(
                App_DispatcherUnhandledException);
    }
}

Schlussendlich muss noch der Eventhandler selbst implementiert werden, welcher in diesem kleinen Beispiel lediglich eine MessageBox mit der Exception-Message ausgibt. An dieser Stelle wäre es durchaus sinnvoll, die nicht behandelten Exceptions in eine Log-Datei mitzuschreiben um später die Möglichkeit einer Auswertung zu haben.
void App_DispatcherUnhandledException(
    object sender, 
    DispatcherUnhandledExceptionEventArgs e)
{
    MessageBox.Show(
        String.Format("An error occured: {0}", e.Exception.Message), 
            "Error");
    e.Handled = true;
}

Durch das Setzen der Eigenschaft Handled wird festgesetzt, dass WPF diese Exception nicht weiter behandelt, da dies bereits innerhalb des Handlers vorgenommen wurde.

Wichtige Hinweise


Durch das Event DispatcherUnhandledException werden alle unbehandelte Ausnahmen gemeldet, welche im Thread des User Interfaces laufen. Treten Fehler beispielsweise innerhalb eines Background Workers auf, gibt es darüber keine Benachrichtigung über DispatcherUnhandledException. In diesen Fällen müssen Sie sich selbst darum kümmern, in dem entweder eigene Fehlerbehandlungsroutinen geschrieben werden, diese Exceptions an den Haupt-UI-Thread übergeben werden bzw. diese im Haupt-UI-Thread nochmals werfen, ohne sie direkt zu behandeln. Auch in diesem Fall wird diese Exception dann über das Event DispatcherUnhandledException gemeldet.

Durch den Parameter DispatcherUnhandledExceptionEventArgs wird zum einen die geworfene Exception überreicht und weiters der Dispatcher, von dem aus die Exception geworfen wurde. Durch die Angabe der Exception kann nun auch überprüft werden, ob dieser Fehler überhaupt behebbar ist oder nicht. Nicht behebbar wäre beispielsweise eine StackOverflowException.

Fazit


Fehlerbehandlung ist ein absolut wichtiges Konzept, um den Benutzer vor Fehlern zu schützen und ein ungewolltes Beenden einer Anwendung zu verhindern. Verwenden Sie diese Methode, um alle behebbaren Exceptions abzufangen, die in ihrer Anwendung nicht behandelt werden. Achten Sie jedoch explizit auf Fehler, die in unterschiedlichen Threads auftreten.
  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Wieder einmal ...

22.01.08 - Blog-Intern
Beitrag von Norbert Eder
 ... gibt es ein Update der Trickkiste. Seit der letzten Anpassung sind wieder einige Artikel hinzugekommen - vor allem bezüglich Windows Presentation Foundation. Diese wurden nun in die Trickkiste integriert und stehen dort nun in der Übersicht zur Verfügung und sollten somit schnell gefunden werden können, als auch einigen Lesern helfen.
  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


WPF: x:Code Element - eine Diskussion

18.01.08 - .NET, WPF
Beitrag von Norbert Eder
 In der WPF gibt es ein Element namens x:Code. Dieses kann verwendet werden, um Code direkt in ein XAML einzufügen. Ein Beispiel:
<Window x:Class="WpfXCodeDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="63" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button x:Name="btnClickMe" 
                Content="Click Me" 
                Click="btnClickMeClick"/>
        <x:Code>
            void btnClickMeClick(object sender, 
                RoutedEventArgs e)
            {
                MessageBox.Show("Clicked");
            }
        </x:Code>
    </Grid>
</Window>

An diesem Beispiel ist zu sehen, dass ein Button definiert wurde. Dieser reagiert auf das Click-Ereignis. Anstatt nun einen Eventhandler zu setzen, welcher in der Code-Behind-Datei behandelt wird, wird dieser über x:Code direkt im XAML behandelt.

Hinweise zum x:Code Element


Der Vollständigkeit halber, hier ein paar Hinweise zu diesem Element.

Da hier Code direkt in XAML eingefügt wird, sollte normalerweise ein CDATA verwendet werden. Hintergrund ist, dass beispielsweise das Einfügen von < und > zu einem invaliden XML führen würde - und XAML ist ja im Endeffekt uach nur XML. Im obigen Beispiel wurde CDATA weggelassen, da kein spezielles Zeichen vorkommt.

Weiters gibt es bei der Verwendung von x:Code einige Limitierungen. Bei der Kompilierung wird sämtlicher Code innerhalb eines x:Code Elements als Teil der dahinterliegenden partiellen Klasse angesehen. Daher ist es nicht möglich, zusätzliche Klassen zu definieren (ausser nested Classes). Wird auf Entitäten ausserhalb der partiellen Klasse verwiesen, kann dies nur voll qualifiziert passieren.

Resultierende Probleme


Aus der Verwendung des x:Code Elements ergeben sich einige Probleme, die es zu wissen gilt.

Interpretierung/Kompilierung
Anwendungen, die XAML-Code interpretieren, müssen darin enthaltenen Sourcecode kompilieren können. Dies ist jedoch nicht immer der Fall. Beispielsweise kann dies der Internet Explorer nicht, Visual Studio hingegen schon. Dies bedeutet, dass obiger Code nicht im IE funktionieren würde, da die notwendigen Assemblies nicht im Hintergrund generiert werden können.

Trennung Design und Implementierung
WPF besitzt den Vorteil, dass Design und Implementierung voneinander getrennt werden können. Bei entsprechenden Ressourcen kann als XAML durch einen Designer aufbereitet werden, während ein Entwickler die tatsächliche Implementierung vornimmt. Wird nun das x:Code Element verwendet, wird der Präsentationsteil mit der Logik verbunden, was zum einen eine hohe Koppelung bringt und zudem einen wesentlich erhöhten Wartungsaufwand. Selbst Microsoft weist darauf hin:

In terms of architecture and coding philosophy, maintaining a separation between markup and code-behind keeps the designer and developer roles much more distinct.

Limitierung
Da für das x:Code Element (wie oben beschrieben) Limitierungen bestehen, kann kaum etwas ernsthaftes in ein XAML eingebettet werden.

Daher stellt sich die grundsätzliche Frage, warum es dieses Element überhaupt gibt, da es schlussendlich verleitet, eben mal schnell dann doch den Code direkt ins XAML zu schreiben.

Fazit


Warum es das x:Code Element gibt, kann schwer beantwortet werden. Möglicherweise gibt es einen guten Grund, welcher sich mir im Moment entzieht. In der Praxis sollte dieses Element jedoch nicht verwendet werden. Selbst für eine kurze Demonstration sollten man doch lieber zur sauberen Variante greifen.
  3 Kommentare - 2669 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Animationen mit WPF anhand einer kleinen Foto Gallery

17.01.08 - .NET, WPF
Beitrag von Norbert Eder
 

Einleitung


Animationen mittels WPF sind nicht schwer. Dieser Artikel soll eine kleine Einführung liefern und zeigen, wie einfach eine kleine Animation mit Fotos gemacht werden kann. Das Resultat ist nachfolgend kurz zu sehen.


Erste Schritte


Bevor es an die Animation selbst geht, entwerfen wir ein UserControl, welches für die Darstellung der Fotos zuständig ist. Hier auch gleich der entsprechende Code.

XAML
<UserControl x:Class="WpfAnimationDemo.PictureControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <DockPanel>
        <DockPanel Background="Black">
            <Image x:Name="ImageControl" Margin="5"/>
        </DockPanel>
    </DockPanel>
</UserControl>


Code-Behind
public partial class PictureControl : UserControl
{
    private Size _originSize;
    private Point _originLocation;

    public static DependencyProperty OriginSizeProperty = 
        DependencyProperty.Register(
            "OriginSize", 
            typeof(Size), typeof(Size));
    public static DependencyProperty OriginLocationProperty = 
        DependencyProperty.Register(
        "OriginLocation", 
        typeof(Point), typeof(Point));

    public PictureControl()
    {
        InitializeComponent();
    }

    public void SetImage(string path)
    {
        ImageControl.Source = BitmapFrame.Create(new Uri(path));
    }

    public Size OriginSize
    {
        get { return _originSize; }
        set { this._originSize = value; }
    }

    public Point OriginLocation
    {
        get { return _originLocation; }
        set { _originLocation = value; }
    }
}

Darin befinden sich keine Besonderheiten. Es wird lediglich eine Eigenschaft SetImage angeboten. Darüber kann das gewünschte Foto gesetzt und somit angezeigt werden.

Weiters wird dieses erstellte Control nun in ein Window eingebettet, damit auch tatsächlich Fotos angezeigt werden können. In dieser Demoanwendung werden insgesamt vier Fotos dargestellt - also wenig dynamisch.

Hier nun das XAML für das Fenster:
<Window x:Class="WpfAnimationDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfAnimationDemo"
    Title="Picture Animation Demo" Height="570" Width="800">
    <Canvas>
        <local:PictureControl 
            x:Name="PicControl1" 
            HorizontalAlignment="Left" 
            Width="160" 
            Height="120" 
            Canvas.Left="10" 
            Canvas.Top="10" />
        <local:PictureControl 
            x:Name="PicControl2" 
            HorizontalAlignment="Left" 
            Width="160" 
            Height="120" 
            Canvas.Left="10" 
            Canvas.Top="140"/>
        <local:PictureControl 
            x:Name="PicControl3" 
            HorizontalAlignment="Left" 
            Width="160" 
            Height="120" 
            Canvas.Left="10" 
            Canvas.Top="270" />
        <local:PictureControl 
            x:Name="PicControl4" 
            HorizontalAlignment="Left" 
            Width="160" 
            Height="120" 
            Canvas.Left="10" 
            Canvas.Top="400" />
    </Canvas>
</Window>


Da nun die grundlegenden Arbeiten erledigt sind, werden wir uns dem Thema Animation zuwenden.

Animation erstellen


Wichtigster Bestandteil für eine Animation ist das Storyboard. Dabei handelt es sich um eine Timeline, die auf einzelne Elemente und dazugehörige Animationen verweist. Mittels Begin werden die in einem Storyboard enthaltenen Animationen ausgeführt. Der Ablauf des StoryBoards kann mittels Stop angehalten werden. Weiters stehen Pause, Resume und Seek zur Verfügung. Zusätzlich stehen Events zur Verfügung, um beispielsweise auf die Beendigung des Durchlaufs eines Storyboards reagieren zu können. Es empfiehlt sich einen Blick auf die Storyboard Übersicht zu werfen.

Durch die WPF werden bereits einige vordefinierte Animationen unterstützt. Diese leiten von AnimationTimeline. Diese Klasse basiert wiederum auf Timeline.

Folgende Ableitungen von AnimationTimeline stehen zur Verfügung, worauf dann weitere Timelines basieren.
  • DoubleAnimationBase
  • BooleanAnimationBase
  • ByteAnimationBase
  • CharAnimationBase
  • ColorAnimationBase
  • DecimalAnimationBase
  • Int16AnimationBase
  • Int32AnimationBase
  • Int64AnimationBase
  • MatrixAnimationBase
  • ObjectAnimationBase
  • Point3DAnimationBase
  • PointAnimationBase
  • QuaternionAnimationBase
  • RectAnimationBase
  • Rotation3DAnimationBase
  • SingleAnimationBase
  • SizeAnimationBase
  • StringAnimationBase
  • Vector3DAnimationBase
  • VectorAnimationBase

In unserem Beispiel wird DoubleAnimation verwendet (basiert auf DoubleAnimationBase). Jede dieser Animationen beschränkt sich (wie zu sehen ist) auf einen bestimmten Typ, welcher verändert werden kann.

Hier ein Beispiel zur Verdeutlichung:
DoubleAnimation doubleAnimHeight = new DoubleAnimation();
doubleAnimHeight.From = 10;
doubleAnimHeight.To = 100;
doubleAnimHeight.Duration = new Duration(
    TimeSpan.FromSeconds(0.5));

Diese defnierte DoubleAnimation bewirkt, dass innerhalb einer bestimmten Duration (also Zeitpannse) der Wert von 10 auf 100 erhöht wird. Andere Animationen funktionieren auf dieselbe Art und Weise.

Im zugrunde liegenden Beispiel soll nun bei einem Klick auf ein Foto, dieses in den Contentbereich verschoben und vergrößert werden. Bei nochmaligem Klick, soll sich das Foto an die ursprüngliche Position zurück animieren. Dafür benötigen wir wir insgesamt vier DoubleAnimations, jeweils für die Höhe, Breite, Top-Position und Left-Position:
DoubleAnimation doubleAnimWidth = new DoubleAnimation();
doubleAnimWidth.From = picControl.Width;
doubleAnimWidth.To = size.Width;
doubleAnimWidth.Duration = new Duration(
    TimeSpan.FromSeconds(0.5));

DoubleAnimation doubleAnimHeight = new DoubleAnimation();
doubleAnimHeight.From = picControl.Height;
doubleAnimHeight.To = size.Height;
doubleAnimHeight.Duration = new Duration(
    TimeSpan.FromSeconds(0.5));

DoubleAnimation doubleAnimTop = new DoubleAnimation();
doubleAnimTop.From = Canvas.GetTop(picControl);
doubleAnimTop.To = location.Y;
doubleAnimTop.Duration = new Duration(
    TimeSpan.FromSeconds(0.5));

DoubleAnimation doubleAnimLeft = new DoubleAnimation();
doubleAnimLeft.From = Canvas.GetLeft(picControl);
doubleAnimLeft.To = location.X;
doubleAnimLeft.Duration = new Duration(
    TimeSpan.FromSeconds(0.5));

Wie zu sehen ist, werden die Eigenschaften From und To nicht fix zugewiesen, sondern stammen von einer zuvor definierten Logik:
PictureControl picControl = (PictureControl)sender;

Point location = new Point(
    Canvas.GetLeft(picControl), 
    Canvas.GetTop(picControl));
Size size = new Size(
    picControl.ActualWidth, 
    picControl.ActualHeight);

if (location != _targetLocation)
{
    location = _targetLocation;
    size = _targetSize;
}
else
{
    location = picControl.OriginLocation;
    size = picControl.OriginSize;
}

Zu beachten ist, dass sich dieser Code im MouseDown-Eventhandler befindet. Bei der Instanzierung der Picture-Steuerelemente wird die ursprüngliche Position und Größe gesetzt. Mit lokalen Variablen kann nun die aktuelle Position abgefragt werden, entspricht diese der Position des Contentbereichs, muss das Foto wieder an den ursprünglichen Platz zurück animiert werden, andernfalls ist der Contentbereich zu füllen.

Im abschließenden Schritt muss noch das Storyboard mit den Animationen und den notwendigen Zuweisungen gefüttert werden:
board.Children.Clear();
board.Children.Add(doubleAnimWidth);
board.Children.Add(doubleAnimHeight);
board.Children.Add(doubleAnimTop);
board.Children.Add(doubleAnimLeft);

Storyboard.SetTargetName(
    doubleAnimWidth, 
    picControl.Name);
Storyboard.SetTargetName(
    doubleAnimHeight, 
    picControl.Name);
Storyboard.SetTargetName(
    doubleAnimLeft, 
    picControl.Name);
Storyboard.SetTargetName(
    doubleAnimTop, 
    picControl.Name);

Storyboard.SetTargetProperty(
    doubleAnimWidth, 
    new PropertyPath(PictureControl.WidthProperty));
Storyboard.SetTargetProperty(
    doubleAnimHeight, 
    new PropertyPath(PictureControl.HeightProperty));
Storyboard.SetTargetProperty(
    doubleAnimLeft, 
    new PropertyPath(Canvas.LeftProperty));
Storyboard.SetTargetProperty(
    doubleAnimTop, 
    new PropertyPath(Canvas.TopProperty));

board.Begin(this);

Zuerst werden alle Kindelemente unseres Storyboard namens board mittels Clear gelöscht und alle zuvor definierten Animationen hinzugefügt. Danach muss das Zielelement definiert werden. Dieses wird beim MouseDown-Event durch das Objekt sender präsentiert, worüber wir den Namen des Objektes abfragen und dem Storyboard mittels SetTargetName übermitteln. Hier muss auch die entsprechende Animation als Parameter übergeben werden, damit das Storyboard weiß, welche Animation auf welches Element angewandt werden muss.

Ist dies erledigt, muss dem Storyboard noch mitgeteilt werden, welche Properties durch die Animationen betroffen sind. Hier gilt es nun, ebenfalls pro Animation den PropertyPath des Zielelementes zu definieren.

Schlussendlich wird das Storyboard mittels Begin gestartet.

Fazit


Dies war eine kurze Einführung in die Welt der Animationen unter WPF. Natürlich sind weitaus komplexere Animation möglich. Auf dieser Basis ist es aber möglich, sich weiter in dieses Thema zu vertiefen und verbesserte Lösungen zu schaffen.

Download Beispielanwendung

  2 Kommentare - 3094 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


WPF: Validierung von Eingaben

16.01.08 - .NET, WPF
Beitrag von Norbert Eder
 Eingaben sollten immer validiert, also auf Korrektheit überprüft, werden, um Fehler bereits frühzeitig abzufangen und so eventuell einen langen Verarbeitungsweg einzusparen. Dieser Artikel zeigt, wie die Eingabe von Datumswerten in Textfelder unter WPF auf Gültigkeit hin überprüft werden können.

Einführung


In der Windows Presentation Foundation gibt es die sogenannten ValidationRules, welche an einem Databinding hängen und darüber auch verwendet werden können. Mit Hilfe dieser ValidationRules können nun Eingaben auf einfache Art und Weise überprüft werden. Es wird jedoch vorausgesetzt, dass der zu prüfende Wert per Databinding an das jeweilige Control gebunden wurde.

Erstellung einer ValidationRule


Das Erstellen einer ValidationRule ist sehr einfach gehalten. Dazu muss von der abstrakten Klasse System.Windows.Controls.ValidationRule abgeleitet werden. Weiters muss die abstrakte Methode Validate überschrieben werden. Diese bekommt als Parameter den geänderten Wert der Eingabe übermittelt, welcher in weiterer Folge überprüft werden muss. Als Ergebnis wird ein Objekt des Typs ValidationResult zurück geliefert. Darin wird vermerkt, ob die Validierung erfolgreich war (oder nicht) und ein Fehlerobjekt (das kann beispielsweise eine Fehlermeldung sein).

Für das hier gezeigte Beispiel wird eine ValidationRule für die Validierung eines Datums implementiert und kann wie folgt aussehen:
public class DateTimeValidationRule : ValidationRule
{
    public override ValidationResult Validate(
        object value, 
        System.Globalization.CultureInfo cultureInfo)
    {
        string val = value as string;
        DateTime dtResult;
        bool bRet = DateTime.TryParse(val, out dtResult);
        ValidationResult vr = new ValidationResult(bRet, "No valid date");
        return vr;
    }
}

Damit ist die notwendige ValidationRule erstellt. Da diese jedoch nur auf ein Binding angewendet werden kann, wird noch eine Datenklasse benötigt, welche den entsprechenden Wert an unser Textfeld bindet.

Binding erstellen


Für das Binding wird eine einfache Datenklasse erstellt. Diese enthält nur den angezeigten Datumswert und wird bei der Instanzierung mit dem aktuellen Datum befüllt (siehe Konstruktor).
public class MyData
{
    private string _date;

    public string Date
    {
        get { return _date; }
        set { _date = value; }
    }

    public MyData()
    {
        _date = DateTime.Now.ToShortDateString();
    }
}

Der nächste Schritt besteht nun darin, ein Window mit den entsprechenden Feldern und dem Binding zu erstellen.

WPF Window und Bindings erstellen


Für das Fenster der Testanwendung müssen einige kleine Punkte erledigt werden. So ist die Datenquelle anzubinden, eine TextBox zu erstellen und das DataBinding zu setzen. Weiters muss dem DataBinding die ValidationRule bekannt gemacht werden, sowie ein entsprechender Trigger gesetzt werden (PropertyChanged). Letztere Schritt wird benötigt, um Änderungen an der Eingabe zu erkennen und dadurch die Validierung zu starten.
<Window.Resources>
    <my:MyData x:Key="md"/>
    
    <ControlTemplate x:Key="validationTemplate">
        <DockPanel>
            <TextBlock Foreground="Red" 
                       FontSize="14">!</TextBlock>
            <AdornedElementPlaceholder/>
        </DockPanel>
    </ControlTemplate>

    <Style x:Key="ErrorTextBoxStyle" 
           TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" 
                     Value="true">
                <Setter 
                    Property="ToolTip" 
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
                    Path=(Validation.Errors)[0].ErrorContent}"/>
                <Setter 
                    Property="Foreground" 
                    Value="Red"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

In den Ressourcen für das Window wird im ersten Schritt die Datenquelle für das Binding angegeben. my ist lediglich ein Namespace, welcher auf das aktuelle Projekt verweist, damit die Klasse MyData gefunden werden kann.

Interessant ist der definierte Style, welcher an den Typ TextBox gebunden wird und einen Trigger auf die Eigenschaft Validation.HasError besitzt. Dieser wird also immer dann ausgelöst, wenn die Validierung einen Fehler zurück liefert. Ist dies der Fall, wird die Schriftfarbe gesetzt, als auch der ToolTip befüllt (dieser ist zuständig, um die zurück gelieferte Fehlermeldung anzuzeigen).

Schließlich fehlt noch die Definition des Textfeldes, welches der grundlegende Bestandteil dieser Demo ist.
<TextBox Grid.Row="1" Name="textBox1" Width="75"
    HorizontalAlignment="Left"
    Validation.ErrorTemplate="{StaticResource validationTemplate}"
    Style="{StaticResource ErrorTextBoxStyle}"
    Margin="2">
        <TextBox.Text>
            <Binding Path="Date" Source="{StaticResource md}"
                UpdateSourceTrigger="PropertyChanged" >
                <Binding.ValidationRules>
                    <my:DateTimeValidationRule/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
</TextBox>

Es wird deutlich, dass hier sowohl ein ErrorTemplate zugewiesen wird und ein entsprechender Style. Zudem findet ein Binding auf unsere zuvor definierte Datenquelle statt. Dieser wird ein UpdateSourceTrigger zugewiesen, der bei einer Veränderung des eingegebenen Wertes die ValidationRule startet. In diesem Fall DateTimeValidationRule, welche zu Beginn dieses Artikels erstellt wurde.

Der Rest besteht eigentlich nur darin, um die TextBox herum die grundlegenden Bestandteile eines Fensters zu definieren. In diesem Beispiel wurde mit einem Grid gearbeitet, was durchaus auch an der Definition des Textfeldes zu erkennen ist.

Fazit


Mit diesem Beispiel sollte es nun möglich sein, eigene Validierungen für Felder zu implementieren. Es ist durchaus sinnvoll, ein wenig mit dem oben gezeigten Code zu experimentieren und einige Einstellungen etc. zu ändern, um daraus zu lernen.
  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL



Zurück Weiter