Gerade eben habe ich eine E-Mail vom AzureNow Gewinnspiel erhalten, mit der Folgenden Mitteilung
‘wir bedanken uns noch einmal für Ihre Teilnahme am AzureNow Gewinnspiel. In der letzten Woche wurden die Gewinner ermittelt und wir freuen uns Ihnen mitteilen zu können, dass Sie den folgenden Preis gewonnen haben:
Das neue Microsoft Visual Studio Professional 2010 als Downloadversion!’
…
Für diesen Gewinn möchte ich mich Herzlichst bedanken
In einer unserer Anwendungen haben wir die Anforderung, dass sich jeder einzelne Window Title, aus einem Namen für das jeweilige Fenster und dem jeweiligen variablen Firmen Namen zusammengesetzt wird. Eigentlich wäre für diesen Sachverhalt alleine kein Blogeintrag notwendig, schließlich gibt es für dieses Vorhaben ja auch genug Möglichkeiten. Jedoch wie ich erst kürzlich wieder lesen konnte, sieht so manch einer aufgrund der Vielzahl an Möglichkeiten den Wald vor lauter Bäumen nicht.
So möchte ich an dieser Stelle, mal zwei Lösungsmöglichkeiten, der Öffentlichkeit etwas näher bringen.
Für diesen Anwendungsfall gibt es eine Vielzahl von Lösungsmöglichkeiten, sei es mit einem AttachedProperty, Implementierung eines eigenen Windows, ein im Backend Definiertes Propperty, dass per Binding an die Oberfläche gebunden wird, … alles Möglichkeiten die mir so auf die schnelle einfallen, doch wie so oft es gibt noch weitere.
Wie Z.B. über einen Converter, wie diesen hier
public class AddUnternehmen : IValueConverter
{
#region IValueConverter Member
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.Format("{0} - {1}", value, GlobaleDaten.AllgemeineEinstellungen.Singleton.AuthUnternehmen);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Nachdem dieser den Application.Resources hinzugefügt wurde,
<Application.Resources>
<conv:AddUnternehmen x:Key="AddFirma"/>
</Application.Resources>
kann er nun zum zusammensetzen, des Window Title benutzt werden.
<Window.Title>
<Binding Converter=”{StaticResource AddFirma}”>
<Binding.Source>
<!--xmlns:clr="clr-namespace:System;assembly=mscorlib"-->
<clr:String>Globale Suche</clr:String>
</Binding.Source>
</Binding>
</Window.Title>
Und zum Ende noch die zweite versprochene Möglichkeit, welches diesen Anwendungsfall per MultiBinding zu Lösen versucht.
<Window.Title>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding>
<Binding.Source>
<!--xmlns:clr="clr-namespace:System;assembly=mscorlib"-->
<clr:String>Globale Suche</clr:String>
</Binding.Source>
</Binding>
<!—xmlns:clr="clr-namespace:…"-->
<Binding Path="AuthUnternehmen" Source="{x:Static Glob:AllgemeineEinstellungen.Singleton}"/>
</MultiBinding>
</Window.Title>
Als erstes ein Beispiel, wie man es so oder in etwas anderer Form leider immer noch des Öfteren sehen kann.
<Grid>
<Button Name="button1">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<!—Warum bindet man das Content Propperty ein weiteres mal? -->
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
Doch bei den beiden Presenter Objekten (ItemsPresenter und ContentPresenter) ist dieses gar nicht von Nöten, denn diese beiden Objekte bringen doch diese Bindung bereits von Haus aus mit. Das einzige was an dieser Stelle also wirklich gebraucht wird, ist eigentlich nur das der TargetType des ControlTemplates, auf das richtige Control oder zumindest auf den richtigen ControlType (ContentControl oder ItemsControl) gesetzt wird.
Vor einigen Tagen wurde ich von einem Entwickler gefragt, wie er es einem Anwender, in einer WPF Anwendung, am besten ermöglichen könnte, festgelegte ListView Spalten über einen Menü Punkt ein und wieder auszublenden. Kurzerhand erstellten wir, diesen einfachen XAML Ausschnitt.
Eine einfaches ListView mit 4 Spalten.
<Window.Resources>
<XmlDataProvider Source="Contact.xml" x:Key="data" XPath="contacts/*"/>
</Window.Resources>
<Grid>
<ListView DataContext="{StaticResource data}" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding XPath=FirstName}">
<GridViewColumnHeader Content="Vorname"/>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding XPath=LastName}">
<GridViewColumnHeader Content="Nachname"/>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding XPath=Phone}">
<GridViewColumnHeader Content="Telefon"/>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding XPath=EmailAddress}">
<GridViewColumnHeader Content="E-Mail"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
Das Dummy Programm erhält ein Checkable MenuItem, welches wir an ein Boolsches Property Binden. Damit der Anwender die Spalten ein und ausblenden kann.
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Extras">
<MenuItem IsCheckable="True" Header="ShowAll" IsChecked="{Binding Path=ShowAll}"/>
</MenuItem>
</Menu>
<Grid>
<ListView DataContext="{StaticResource data}" ItemsSource="{Binding}">
<!—Wie oben-->
</ListView>
</Grid>
</DockPanel>
Um nun unserem Ziel ein Stück näher zu kommen, benötigen wir zusätzlich einen DataTrigger, der auf Veränderungen, des am MenuItem gebundenen Boolschen Proerty wartet. Diesem in einem Style verpackten DataTrigger, hängen wir nun an den GridViewColumnHeader, der sobald der Anwender auf das MenuItem Klickt, ausgeblendet werden soll.
…
<GridViewColumn DisplayMemberBinding="{Binding XPath=Phone}">
<GridViewColumnHeader Content="Telefon">
<GridViewColumnHeader.Style>
<Style>
<Setter Property="GridViewColumnHeader.Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataContext.ShowAll, ElementName=main}" Value="false">
<Setter Property="GridViewColumnHeader.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GridViewColumnHeader.Style>
</GridViewColumnHeader>
</GridViewColumn>
…
Was haben wir bisher erreicht?
Bei einem Klick auf den Menüpunkt, wird derzeit aufgrund des DataTriggers,leider nur der Spalten Kopf ausgeblendet. Hmm, dass ist noch nicht das was wir wollen
Aber auch dieses kleine Problem konnten wir schnell Lösen, wir hingen uns schnell an das Event IsVisibleChanged des GridViewColumnHeadeer und Implementierten kurzerhand diese paar Code Zeilen.
private void GridViewColumnHeader_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
GridViewColumnHeader header = (sender as GridViewColumnHeader);
if (header != null)
if (header.Visibility == Visibility.Collapsed)
header.Column.Width = 0;
else
//ClearValue(GridViewColumn.WidthProperty) ist an dieser Stelle identisch mit Width="Auto" in XAML
header.Column.ClearValue(GridViewColumn.WidthProperty);
}
Und zu guterletzt wieder an die Datenschützer: Diese Daten sind keine Realdaten sondern stammen aus einer von Microsoft erstellten Beispiel Datenbank. Ähnlichkeiten mit real existierenden Personen sind eher zufälliger Natur und nicht beabsichtigt.
Man sieht es leider immer noch häufig, dass der normale Anwender, mit den von uns Entwicklern erstellten Masken so manches mal ein wenig überfordert ist. Ein Grund für diese Überforderung ist ganz klar, die Masse an Informationen oder Eingabe Möglichkeiten, die wir versuchen in einer Maske unterzubringen (Sei es mit Absicht oder weil unser Auftraggeber es so verlangt). Ganz klar, Informationen die Vorhanden sind, sollte man auch anzeigen, aber muss es ZB. bei einem ListView immer so weit treiben, so das man der Horizontale Scroll Balken, schon fast nicht mehr sichtbar ist?
Ich denke nein!
Ich bin mittlerweile dazu übergegangen, die in einem default mäßig angezeigten Spalten zu minimieren. Ja ich höre so manch einen jetzt schon aufschreien, unsere Anwender brauchen alle Informationen in der ListView. Das stimmt, die Daten wäre ja auch sonst nicht erfasst worden und Ich sage, die Anwender brauchen auf keine einzige Information verzichten, denn diese Daten werde ja angezeigt, nur halt nicht zu Beginn, sondern erst dann wenn das betreffende Item Selektiert wurde.
<ListView>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumnHeader Content="Vorname" />
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Content="Nachname" />
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Content="Strasse" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In diesem kurzen XAML-Ausschnitt, sind zwei Spalten (PLZ, Telefonnummer) nicht vorhanden. Doch wie bekommt der Anwender nun, diese beiden Fehlenden Spalten angezeigt? Nein keine Sorge, weder über eine Message Box noch über einen weiteren Dialog oder Tooltip, dieses alle wäre zwar möglich, jedoch aufgrund der Gesundheit der Anwender sollte man dieses lieber lassen. Um die Daten anzuzeigen brauche ich nicht viel mehr als einen Style, das Property IsSelected und ein ControlTemplate.
<Window.Resources>
<ControlTemplate x:Key="detailTeamplate">
<UniformGrid Columns="2">
<Label>Vorname</Label>
<TextBlock Text="{Binding Path=Vorname}"/>
<Label>Nachname</Label>
<TextBlock Text="{Binding Path=Nachname}"/>
<Label>PLZ</Label>
<TextBlock Text="{Binding Path=PLZ}"/>
<Label>Ort</Label>
<TextBlock Text="{Binding Path=Ort}"/>
<Label>Telefonnummer</Label>
<TextBlock Text="{Binding Path=Telefonnummer}"/>
</UniformGrid>
</ControlTemplate>
</Window.Resources>
<Grid>
<ListView>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Template" Value="{StaticResource detailTeamplate}" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumnHeader Content="Vorname" />
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Content="Nachname" />
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Content="Strasse" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
In diesem Bild kann man nun erkennen, was passiert wenn ein Item in der ListView Selektiert wird, und somit kann der Anwender, nun alle Daten solange bewundern wie das Item selektiert ist. Natürlich könnte man an dieser Stelle auch andere Controls im ControlTemplate verwenden.
Zb um dem Anwender die Möglichkeit zu geben, die Daten an dieser Stelle zu bearbeiten und natürlich auch wieder zu speichern.
Und zuguterletzt wieder an die Datenschützer: Diese Daten sind keine Realdaten sondern stammen aus einer von Microsoft erstellten Beispiel Datenbank. Ähnlichkeiten mit real existierenden Personen sind eher zufälliger Natur und nicht beabsichtigt.
Heute möchte ich mal etwas über eine Funktionalität berichten, die so manch einem Entwickler, die Arbeit etwas erleichtern oder zu mindestens dem XAML-Code zu etwas mehr Übersichtlichkeit verhelfen könnte, wenn diese Funktionalität doch nur jedem bekannt wäre. Obwohl ich eigentlich sicher das diese Attached Events schon des Öfteren benutzt oder zumindest in der IntelliSense beispielsweise bei der ListView gesehen wurden.
Ja, dieses sind Attached Events, Events die nicht von dem betreffendem Control bereitgestellt werden, jedoch genutzt werden können.
Da jedoch viele dieser Events, auch vom ListView bereitgestellt werden, bringt das natürlich an dieser Stelle nicht allzu viel.
Wie das Attached bereits vermuten lässt, ist es die selbe Funktionalität wie auch bei den Attached Properties.
Es wird eigentlich erst interessant, wenn man Beispielsweise folgenden XAML-Code Implementiert, auch wenn die IntelliSense dieses nicht anbietet, macht dieser Code, dass wonach er aussieht. Bei einem Doppelklick auf ein ListViewItem, behandelt die Methode ‘ListView_MouseDoubleClick_1’ diese Aktion.
<ListView ListViewItem.MouseDoubleClick="ListView_MouseDoubleClick_1">
<ListView.View>
<GridView>
</GridView>
</ListView.View>
</ListView>
Tja, scheinbar wird sich der Release Termin von Visual Studio 2010, aufgrund Performance Probleme, um ein paar Wochen Verschieben.
Stattdessen so laut Planung, soll im Februar ein RC erscheinen, der von jedem getestet werden darf, natürlich erscheint dieser RC wieder mit einer GO-Live Lizenz.
http://weblogs.asp.net/scottgu/archive/2009/12/17/visual-studio-2010-and-net-4-0-update.aspx
Da es mir beim Experimentieren, mit den Navigation Applikationen zu lästig wurde, immer wieder eine WPF-Anwendung zu erstellen, nur um das automatisch erzeugte Window gegen eine Page auszutauschen, habe ich mir Kurzerhand, mal eine Visual Studio 2008 Projekt Vorlage gebastelt. Ja ich weiß, SharpDevelop bietet diese Projektvorlage per Default, jedoch benutze ich VS 2008 Standart und dort gibt es kein Template für diesen Anwendungstyp.
Möglicherweise kann noch irgendwer, etwas damit anfangen. Doch wenn ihr diese Vorlage benutzt, seid so nett und hinterlasst einen kleinen Komentar.
Installation:
Das unten angebotene Zip-Archive einfach unter
%homepath%\Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\Windows
abspeichern, ggf. Pfad auf das eigene System anpassen.
Visual Studio 2008 neu starten, und schon steht euch der Projekttyp, NavigationApplication unter 'Eigene Vorlagen' zur Verfügung.

Die Vorlage ist diesem Post angehangen.
Mehr Beiträge
Nächste Seite »