BlackCoin's Corner

In diesem Blog dreht es sich zu 90 % um den Themenbereich C# .Net

Dezember 2009 - Einträge

ListView Spalten Aus und wieder Einblenden

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

ListNotFinished

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); 
} 

listfertig

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.

Posted: Dez 30 2009, 06:39 von Lars Schmitt | mit 1 comment(s)
Abgelegt unter: ,
Die Übersicht in einer ListView behalten

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>
list

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.

Posted: Dez 28 2009, 10:49 von Lars Schmitt | mit 1 comment(s)
Abgelegt unter: ,
Attached Events

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.

Attached

 

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>

Posted: Dez 19 2009, 02:54 von Lars Schmitt | mit 1 comment(s)
Abgelegt unter:
Release Termin von VS 2010 verschoben

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

Posted: Dez 18 2009, 05:38 von Lars Schmitt | mit no comments
Abgelegt unter:
Navigation Applikation

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.

NavApp

Die Vorlage ist diesem Post angehangen.

 

Posted: Dez 16 2009, 07:03 von Lars Schmitt | mit no comments
Abgelegt unter:
Der Jährliche Weihnachts-Webcast

Am Mittwoch dem 16 Dezember 2009 ist es nun wieder soweit, der MSDN Weihnachts-Webcast erinnert nun auch den letzten Entwickler wieder daran, das Weihnachten vor der Tür steht.

Bernd Marquardt und Neno Loje werfen wie jedes Jahr ein Blick auf die Technologie Highlights des nun fast abgelaufenen Jahres.

 

Natürlich gibt es auch dieses Jahr wieder etwas zu Gewinnen, aber dafür muss man auch etwas leisten.

Es geht dabei um Schnelligkeit, denn nur wer die gestellten Fragen Live beantworten kann, hat eine Chance auf eine der Vielen Gewinne.

 

http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032437099

Der ObjectDataProvider

Die Anwendungsgebiete dieser Klasse unter WPF sind recht vielseitig, ZB. kann mithilfe dieser Klasse, ein Objekt Instanziiert werden, natürlich kann man in WPF auch einzelne Objekte auf andere Art und weise, über Ihren Default mäßig Parameterlosen Constructor erstellen, jedoch funktioniert die Instanziierung des jeweiligen Objektes nicht, sobald die jeweilige Klassen keine Parameterlosen Constuctor bereitstellt. Da es im XAML Code keine direkte Möglichkeit gibt, der Klasse eine Parameter zu übergeben kommt genau an dieser stelle, nun der ObjectDataProvider aus dem Namespace System.Windows.Data ins Spiel.

<ObjectDataProvider x:Key="CustomerDataSource" ObjectType="{x:Type data:Customer}"> 
  <ObjectDataProvider.ConstructorParameters> 
    <system:String>Lars</system:String>


    <system:String>Schmitt</system:String> 
  </ObjectDataProvider.ConstructorParameters> 
</ObjectDataProvider>

Dank dieses einfachen XAML Codes können wir nun, das Objekt vom Typ Customer mit zwei Parametern unter XAML erstellen und auch als Bindungs Datenquelle verwenden.

 

Eine weitere Funktion wäre, dass mit dessen Hilfe auch auf Methoden eines einzelnen Objektes zugegriffen werden, um ZB. deren Rückgabe als Datenquelle zu verwenden.

Wie es ZB. bei dieser Implantation geschieht:

           <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="SampleData"> 
                <ObjectDataProvider.MethodParameters> 
                      <x:Type TypeName="local:TestEnum" /> 
                </ObjectDataProvider.MethodParameters>


            </ObjectDataProvider>

Den meistens, wird es schon aufgefallen sein, was dieser ausschnitt macht, richtig dieser XAML ausschnitt ermöglicht es unter XAML, die einzelnen Konstanten einer Enumeration innerhalb eines Arrays auszulesen und diese als Datenquelle, ZB, für eine Selelektion in einer ComboBox bereitzustellen.

Posted: Dez 13 2009, 06:39 von Lars Schmitt | mit 2 comment(s)
Abgelegt unter:
Warum funktioniert <TextBox Text=”{Binding Path=Data.[PropertyName]}”/> nicht wenn Data eine Collection nicht?

In WPF existieren zwei große Steuerelementgruppen, zum einem die Controls die Steuerelemente die eine Collection Visualisieren können, und die Steuerelemente die einzelnen Daten Visualisieren können.

Das ist auch der Grund warum dieser Einfache XAML Code funktioniert

<StackPanel> 
    <ListBox ItemsSource="{Binding}" SelectedValuePath="id" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True"/> 
    <StackPanel Orientation="Horizontal"> 
        <TextBlock Text="{Binding Path=id}" /> 
        <TextBox Text="{Binding Path=Name}"/> 
    </StackPanel> 
</StackPanel>

Was macht diese XAML ausschnitt, die Antwort ist recht einfach: Mit Hilfe der ListView wird ein Element ausgewählt, und mit der TextBox kann der jeweilige Name verändert werden. Da man an dieser stelle in keinem der Controls eine Datenquelle definiert, wird die Datenquelle automatisch ausgewählt und passiert, an dieser Stelle nach einem ganz einfachen Prinzip:

Es wird der erste, im VisualTree darüber liegende DataContext benutzt, der definiert wurde.

Sobald die einzigste darüber liegende Datenquelle eine Collection ist passiert folgendes

Ist das Control selbst ein ItemsControl, wie ZB. eine ListView oder ComboBox wird die Collection selbst als VIew eingebunden, ist das Control selbst kein ItemsControl wird von der View das Property CurrentItem als DatenQuelle benutzt.

 

Die abschließende Frage ist nun.

Was kann man machen, um eine Spalte aus ZB. einer DataTable an eine TextBox zu binden?

Bevor man jetzt darüber nachdenkt, NEIN!  im Hintergrund einfach CurrentItem des jeweiligen Views zu setzen, ist definitiv nicht die Lösung sein.

 

Der Weg ist aber nur ein kleinen wenig komplizierter, man muß halt den kompletten Pfad im Binding mit aufnehmen.

<TextBox Text="{Binding Path=Data.Rows[0][Name]}"/> 

wobei Data an dieser Stelle das Property für die DataTable ist.

Posted: Dez 06 2009, 09:48 von Lars Schmitt | mit no comments
Abgelegt unter:
SelectedItem aus einem anderen DataContext Binden

Gegeben sein folgende Datenstruktur

public class DataSource : INotifyPropertyChanged {


       public PlzOrtClass[] PlzOrt{get;set;}


       public PlzOrtClass SelectedObj {get{…;}set{…;}}


      …


}

 

Nachdem eine Instance dieses Objektes, dem Property DataContext eines Windows zugewiesen wurde, soll diese Datenstruktur in einer ComboBox Visualisiert werden.

Das reine anzeigen sollte an dieser stelle ja noch kein Problem verursachen.

<Window x:Class="WpfApplication2.Window1" 
    xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>" 
    xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel>


… 
        <ComboBox DataContext="{Binding Path=PlzOrt}" ItemsSource="{Binding}" DisplayMemberPath="Ort" SelectedValuePath="Plz"/>


… 
    </StackPanel> 
</Window>

 

Jedoch das Problem, vor dem so manch einer steht, ist nun wie bindet man, dass in der ComboBox Selektierte Element, nun wieder an die Datenstruktur an das Property SelectedObj?

 

Die schnellste Idee die dabei zu tage Tritt, wäre zb

<Window x:Class="WpfApplication2.Window1" 
    xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>" 
    xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel>


… 
        <ComboBox DataContext="{Binding Path=PlzOrt}" ItemsSource="{Binding}" DisplayMemberPath="Ort" SelectedValuePath="Plz" SelectedItem="{Binding Path=SelectedObj}"/>


… 
    </StackPanel> 
</Window>

 

Doch wer schon einmal vor dem Problem stand wird schnell erkennen das, dass so nicht funktioniert, denn das Binding an dem Property SelectedItem, benutzt an dieser Stelle den DataContext der ComboBox und der DataContext ist an dieser Stelle ja an das Property PlzOrt gebunden.

 

doch mit einer kleinen Veränderung kommen bekommet man auch dieses Problem wieder in den Griff

<Window x:Class="WpfApplication2.Window1" 
    xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>" 
    xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel>


… 
        <ComboBox DataContext="{Binding Path=PlzOrt}" ItemsSource="{Binding}" DisplayMemberPath="Ort" SelectedValuePath="Plz" SelectedItem="{Binding Path=DataContext.SelectedObj, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>


… 
    </StackPanel> 
</Window>

 

Durch die letzte Code Änderung geschieht nun folgendes:

Durch das angeben einer Relativen Quelle (RelativeSource), wird nun nicht mehr der DataContext der ComboBox als Datenquelle benutzt, sondern das erste im Visualtree darüberlegende Element vom Typ Window, und da das Window dann die Datenquelle ist, muss beim Pfad auch genau aus diesem Grund der Pfad um um das Property DataContext erweitert werden.

Posted: Dez 01 2009, 11:19 von Lars Schmitt | mit no comments
Abgelegt unter: