.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

WPF: Data Template zur Laufzeit ändern

29.05.08 - .NET, WPF
Beitrag von Norbert Eder
 Wer WPF-Anwendungen entwickelt, kommt sehr schnell zur Problematik, dass dich Data Templates zur Laufzeit ändern sollen. Dies kann passieren, da bei einem MouseOver zusätzliche Informationen angezeigt werden sollen, oder es soll auf eine andere Aktion eine Reaktion gezeigt werden. Die Realisierung ist recht einfach, aber häufig gefragt.

Nehmen wir also ein kleines Beispiel. Gegeben sei ein Button, der eine Beschriftung anzeigt, die durch ein standardmäßig gesetztes Data Template erweitert wird. Beim MouseOver (also quasi als Hover-Effekt), sollt dieses Data Template ersetzt werden und vor der eigentlichen Beschriftung des Buttons einen anderen Text anzeigen, welcher beim Verlassen wieder zurückgesetzt wird.

Dafür erstellen wir ein Fenster, welches die jeweiligen Data Templates enthält, sowie die Darstellung des Buttons. Hier das Innenleben des Fensters als XAML:
<Window.Resources>
    <DataTemplate x:Key="DefaultTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Default: "/>
            <TextBlock Text="{Binding}"/>
        </StackPanel>        
    </DataTemplate>
    <DataTemplate x:Key="SpecialTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Special: "/>
            <TextBlock Text="{Binding}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <Button 
        x:Name="TestButton" 
        Content="Test" 
        ContentTemplate="{StaticResource DefaultTemplate}"/>
</Grid>

Damit wären nun die beiden Data Templates definiert und der anzuzeigende Button. Das Template namens DefaultTemplate ist dem Button standardmäßig zugewiesen und setzt der eigentlichen Beschriftung des Buttons ein Default: voraus. Das Template, auf welches bei einem Hover gewechselt werden soll, setzt der eigentlichen Besschriftung ein Special: voraus.

In der Codebehind-Datei werden nun die notwendigen Events abonniert:
  • MouseOver
  • MouseLeft

Befindet sich die Maus über dem Button, soll das spezielle Template angewendet werden. Beim Verlassen der Maus, muss das ursprüngliche Template (also das DefaultTemplate) wieder hergestellt werden. Sehen wir uns dazu den C#-Code an:
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        this.TestButton.MouseMove += 
            new MouseEventHandler(TestButton_MouseMove);
        this.TestButton.MouseLeave += 
            new MouseEventHandler(TestButton_MouseLeave);
    }

    private void TestButton_MouseMove(
        object sender, 
        MouseEventArgs e)
    {
        TestButton.ContentTemplate = 
            this.FindResource("SpecialTemplate") as DataTemplate;
    }

    private void TestButton_MouseLeave(
        object sender, 
        MouseEventArgs e)
    {
        TestButton.ContentTemplate = 
            this.FindResource("DefaultTemplate") as DataTemplate;
    }
}

Im Konstruktor des Fensters werden die beiden benötigten Events abonniert. In den jeweiligen Events wird nichts anderes gemacht, als in den Ressourcen nach dem gewünschten DatenTemplate zu suchen und es der Eigenschaft ContentTemplate des Buttons zuzuweisen. Idealerweise sollte noch eine Sicherheitsabfrage bezüglich der Existenz der Ressource untergebracht werden.

Damit ist es nun möglich, zur Laufzeit das Data Template eines Elements zu wechseln.

  3 Kommentare - 1890 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


WPF Application Lifetime Cycle

26.05.08 - .NET, WPF
Beitrag von Norbert Eder
 Den Lifetime Cycle zu kennen ist eine sehr hilfreiche Sache. Daher hier eine Übersicht, was wann wie in einer WPF-Applikation abläuft:



Wer darauf Rücksicht nimmt, sollte gerade bei der Frage, was in welchen Events zu erledigen ist, keine Probleme mehr haben.

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


Weiter muss es gehen ...

25.05.08 - Blog-Intern
Beitrag von Norbert Eder
 Unter diesem Motto wurde die Sektion WPF wieder um die neuesten Artikel von mir erweitert. Da die Liste nun doch schon etwas länger ist, sollte für die meisten etwas dabei sein.

Sollte ein Artikel/Tutorial fehlen, kann man hier seinen Wunsch abgeben. Mit etwas Glück folgt tatsächlich das Gewünschte.
  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


XAML: Eigenen XML-Namespace erstellen

23.05.08 - .NET, WPF
Beitrag von Norbert Eder
 Wer bereits etwas mit WPF gemacht hat, wird den WPF und den XAML Namespace kennen. Beide werden automatisch beim Erstellen eines Elementes in das vordefinierte XAML eingetragen.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Zum Einen stehen uns darüber alle möglichen WPF-Elemente zur Verfügung, als auch ein paar XAML-Erweiterungen (Präfix x:) für das Erstellen von Arrays, Inline-Code, Typenangaben usw.

Wer nun eigene Elemente einbinden möchte, greift für gewöhnlich auf einen CLR-Namespace zurück:
xmlns:demo="clr-namespace:WpfNamespaceDemo.Lib;assembly=WpfNamespace.Lib"


Wurden nun jedoch zahlreiche Elemente entwickelt, liegen diese in unterschiedlichen Namespaces und sollen viele davon in einem Window verwendet werden, entsteht eine nette Liste von CLR-Namespace-Definitionen. Viel einfacher geht dies über die Erstellung eines eigenen XML-Namespaces.

Hierfür kann das Attribute XmlnDefinition verwendet werden. Dieses wird in der AssemblyInfo.cs definiert und sieht so aus:
[assembly: XmlnsDefinition(
    "http://www.norberteder.com/2008/wpf", 
    "WpfNamespaceDemo")]

Was wird hier gemacht? Der erste Parameter definiert den Wert des eigenen XML-Namespaces, der zweite Parameter gibt an, welcher CLR-Namespace in zum XML-Namespace hinzugefügt werden soll. Dies kann nun für mehere CLR-Namespaces gemacht werden.

Schlussendlich kann darauf nun folgendermaßen zugegriffen werden:
xmlns:local="http://www.norberteder.com/2008/wpf"

Es werden nun sämtliche CLR-Namespaces eingebunden, welche unter dem XML-Namespace zusammengefasst wurden. Dies fördert die Übersichtlichkeit und vermindert Fehler. Allerdings muss dies auch entsprechend gewartet werden und kann aufwendiger werden, wenn zig unterschiedliche Assemblies ins Spiel kommen.

Hinweis: Wird in der aktuellen Assembly ein XML-Namespace definiert, kann dieser nicht verwendet werden. Dies funktioniert nur, wenn eine Assembly mit einem definierten XML-Namespace eingebunden wird.

  1 Kommentar - 1981 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Nervig hoch 2: FxCop + WPF

14.05.08 - Entwicklung, Qualitätsmgmt., .NET, WPF
Beitrag von Norbert Eder
 Ein Großteil des FxCop Ruleset ist bei meinen Projekten ständig aktiviert und hilft so, den Code sauberer, sicherer und performanter zu halten.

Aber gerade in Kombination mit WPF ergeben sich daraus natürlich einige Probleme oder besser gesagt, Ärgernisse. Nehmen wir die Regel CA1823. Diese besagt, dass ein Feld nicht verwendet wird, oder ihm nie ein Wert zugewiesen wurde. Derartige Regeln werden bei mir grundsätzlich als Fehler und nicht als Warnung behandelt.

Wie kommt man nun dazu, sich über diesen Fehler zu ärgern? Ganz einfach. Man vergebe einem Element einen x:Name. Dadurch wird es im generierten File (.g.cs) angelegt, damit aus der Codebehind-Datei darauf zugegriffen werden kann. Eventuell möchte man dies jedoch nicht, sondern vergibt dem Element bloß einen Namen, um per Binding darauf zuzugreifen.

Und schon taucht dieser Fehler auf und schreit nahezu danach, suppressed zu werden - was ja eigentlich vermieden werden sollte.

Wäre schön, wenn sich diesbezüglich zukünftig etwas tun würde ..

  8 Kommentare - 15666 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Gewinnspiel auf .NET GUI verlängert

13.05.08 - .NET, WPF, ASP.NET, Silverlight, Visual Studio, Allerlei, Internet, Community
Beitrag von Norbert Eder
 Der Annahmeschluss für das aktuell laufende Gewinnspiel auf .NET GUI wurde bis 16. Mai 2008 verlängert. Alle Artikel, die bis Mitternacht eingehen, werden für das Gewinnspiel berücksichtigt.

Noch ein kleiner Hinweis: Die Artikel müssen sich nicht zwangsweise um WPF und XAML drehen. Alles rund um .NET und GUI kann als Grundlage dienen (Windows Forms, GDI+, ASP.NET etc.)

  3 Kommentare - 884 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Visual Studio 2008 SP1: Was bringt es für WPF?

08.05.08 - .NET, WPF, Visual Studio
Beitrag von Norbert Eder
 Im Service Pack 1 zu Visual Studio 2008 wird es einige Änderungen bzw. Erweiterungen zum Thema WPF geben. Eine genaue Übersicht gibt diese Veröffentlichung von Microsoft.

Hier eine Liste der neuen Funktionalitäten:
  • The Properties window now contains the Events tab. The Events tab lets you create events, assign events, and review events.
  • The Properties window now includes a category sort option and an alphabetical sort option to allow for faster property location.
  • Code changes have been made to the XAML Refactor/Rename definition and to the Go to definition. These changes allow XAML rename operations to occur automatically. Additionally, you can navigate the XAML definition by pressing F12.
  • You can now drag controls or create controls from the toolbox in XAML view or in Design view. You can do this even if you use a split view configuration.
  • Snaplines are now implemented for control margins. This lets the designer control a fixed distance from other controls, from container edges, or from gridlines.
  • Tab controls now support TabItem activation and TabItem design. To do this, click the tab that you want to design.
  • The Expander control now expands conditionally based on what is selected. You can design the contents of the Expander control at design time with affecting the IsExpanded attribute of the runtime.

Im Paket sind also durchaus Features, die bereits zu Beginn dabei hätten sollen. Vor allem Umbenennungen waren bisher ein wahrer Graus.

Einiges dürfte mit diesem SP1 zukünftig leichter fallen, dennoch fehlen mir immer noch ein paar Punkte, die hauptsächlich nur Bug-Fixes behoben werden können. Dieses SP bietet jedoch nur Erweiterungen und Verbesserungen an, keine Bug-Fixes ...

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


WPF und Master Pages

07.05.08 - .NET, WPF, ASP.NET
Beitrag von Norbert Eder
 Wer bereits mit ASP.NET in Berührung kam, der kennt eventuell die Master Pages. Also eine Art Vorlage, die das grundsätzliche Aussehen aller darauf basierenden Seiten beschreibt. Vorhandene Platzhalter können je nach Seite mit dem gewünschten Inhalt befüllt werden.

Dieses Verhalten wäre in einigen Fällen auch für WPF sehr hilfreich. Leider gibt es diese in dieser Form nicht. Wie ein derartiges Verhalten jedoch trotzdem simuliert werden kann, zeigt der Artikel WPF "Master Page" like functionality von Brad Cunningham

Empfehlenswert!

Edit: Ebenfalls sehr empfehlenswert ist der Artikel von Karin Huber auf CodeProject zu diesem Thema: WPF Master Pages.

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


Deaktivierte Buttons und Margin-Verhalten

06.05.08 - .NET, WPF
Beitrag von Norbert Eder
 Wer ein StackPanel mit Buttons á la Visual Studio Toolbox entwickelt, der möchte eventuell diese contextsensitiv anzeigen. Eine Variante ist, alle Elemente zu laden und je nach Bedarf aus- bzw. einzublenden.

Dies in einem Window nachgestellt, könnte in etwa wie folgt per XAML definiert sein:
<Window.Resources>
    <Style TargetType="Button">
        <Setter Property="SnapsToDevicePixels" Value="true"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="MinHeight" Value="0"/>
        <Setter Property="MinWidth" Value="75"/>
        <Setter Property="Margin" Value="10"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="Border" 
                            Background="Beige"  
                            CornerRadius="2" 
                            BorderThickness="1" 
                            BorderBrush="Brown">
                        <ContentPresenter 
                            Margin="2" 
                            HorizontalAlignment="Center" 
                            VerticalAlignment="Center" 
                            RecognizesAccessKey="True"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsVisible" Value="false">
                            <Setter Property="Height" Value="0"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<StackPanel>
    <Button x:Name="Button1" 
            Content="Button1"/>
    <Button x:Name="Button2" 
            Content="Button2"/>
    <Button x:Name="Button3" 
            Content="Button3"/>
    <Button x:Name="SetButton" 
            Content="Toggle Button1 Un/Visible" 
            Click="SetButton_Click" />
    <Button x:Name="CheckButton" 
            Content="Check Height" 
            Click="CheckButton_Click"/>
</StackPanel>

Und so sieht es aus:



Damit die Buttons nicht aneinander kleben, wurde ein entsprechender Margin gesetzt. Nun soll (in diesem Beispiel) ein bestimmter Button ausgeblendet werden. Dies wird mit Hilfe eines anderen Buttons erledigt:
private void SetButton_Click(object sender, RoutedEventArgs e)
{
    if (Button2.Visibility == Visibility.Visible)
        Button2.Visibility = Visibility.Hidden;
    else
        Button2.Visibility = Visibility.Visible;
}

Soweit auch noch keine Tragik.

Wird nun der Button ausgeblendet, dann erhält man folgendes Ergebnis:



Eigentlich nicht ganz das, was man sich erwartet. Es wurde zwar der Button ausgeblendet, aber der definierte Margin ist nach wie vor vorhanden. Meiner Meinung nach, sollte der Margin ebenfalls ausgeblendet werden, so er denn logisch zum Button gehört.

Zu beachten ist der Trigger auf IsVisible im ContentTemplate, der die Höhe des Buttons auf 0 setzt, damit nicht nur der Button ausgeblendet wird, sondern der Zwischenraum durch die restlichen Buttons aufgefüllt wird.

Damit auch der Margin ausgeblendet wird, muss dieser im Trigger explizit auf 0 gestellt werden:
<Trigger Property="IsVisible" Value="false">
    <Setter Property="Height" Value="0"/>
    <Setter Property="Margin" Value="0"/>
</Trigger>

Nun erhält man das gewünschte Ergebnis:



PS: Schelm, wer Böses denkt und ein WrapPanel empfiehlt. Ist auch hier dasselbe.

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


Events unter .NET

05.05.08 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Nachdem immer wieder die Frage auftaucht, wie denn Events unter .NET funktionieren, wie man eigene Events definieren kann usw. habe ich ein kleines Tutorial dafür geschrieben. Zu finden ist es hier.

Auf dass es dem einen oder anderen helfen möge.

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



Zurück Weiter