martedì 15 marzo 2011

ListView Riordinabile

Una delle esigenze più frequenti durante lo sviluppo di applicazioni con Windows Presentation Foundation è la rappresentazione di dati nel classico formato Grid. In Windows Presentation Foundation, almeno fino alla versione 3.5 del framework, viene utilizzato il controllo ListView.

Il controllo ListView di WPF, infatti, mette a disposizione un tipo di visualizzazione di tipo, appunto, GridView che permette la gestione di più colonne. Nell’esempio seguente viene definito un controllo ListView con modalità di visualizzazione GridView composta da 4 colonne in binding con alcune proprietà dell’entità Person.

<ListView x:Name="listPersons" ItemsSource="{StaticResource persons}"
          BorderThickness="0" Margin="5"
          GridViewColumnHeader.Click="GridViewColumnHeader_Click" >
    <ListView.View>
        <GridView AllowsColumnReorder="True">
            <GridViewColumn Header="ID" 
                            DisplayMemberBinding="{Binding Path=ID}" 
                            Width="50" />
            <GridViewColumn Header="FirstName" 
                            DisplayMemberBinding="{Binding Path=FirstName}" 
                            Width="100"/>
            <GridViewColumn Header="LastName" 
                            DisplayMemberBinding="{Binding Path=LastName}" 
                            Width="100"/>
            <GridViewColumn Header="City" 
                            DisplayMemberBinding="{Binding Path=City}" 
                            Width="80"  />
        </GridView>
    </ListView.View>
</ListView>

Nel listato, come noterete, viene definito l’handler dell’evento Click di GridViewColumnHeader dove verrà gestito, appunto, il riordinamento della colonna cliccata.

Per ottenere l’ordinamento della collection utilizzeremo un metodo chiamato Sort che, attraverso l’uso di una CollectionViewSource effettua l’ordinamento per il campo passato come parametro al metodo (sortBy).

private void Sort(string sortBy, ListSortDirection direction)
{
    ICollectionView dataView = CollectionViewSource.GetDefaultView(listPersons.ItemsSource);

    dataView.SortDescriptions.Clear();
    SortDescription sd = new SortDescription(sortBy, direction);
    dataView.SortDescriptions.Add(sd);
    dataView.Refresh();
}

Passiamo ora alla gestione dell’evento di click sull’header di una colonna della ListView.

GridViewColumnHeader _lastSelectedHeader = null;
ListSortDirection _lastDirection = ListSortDirection.Ascending;

void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader selectedHeader = e.OriginalSource as GridViewColumnHeader;
    ListSortDirection direction;

    if (selectedHeader != null)
    {
        if (selectedHeader.Role != GridViewColumnHeaderRole.Padding)
        {
            if (selectedHeader != _lastSelectedHeader)
            {
                direction = ListSortDirection.Ascending;
            }
            else
            {
                if (_lastDirection == ListSortDirection.Ascending)
                {
                    direction = ListSortDirection.Descending;
                }
                else
                {
                    direction = ListSortDirection.Ascending;
                }
            }

            string header = string.Empty;
            if (selectedHeader.Column.CellTemplateSelector != null)
            {
                header = selectedHeader.Column.Header.ToString();
            }
            else if (selectedHeader.Column.DisplayMemberBinding != null)
            {
                header = ((Binding)selectedHeader.Column.DisplayMemberBinding).Path.Path;
            }
            else
            {
                return;
            }

            Sort(header, direction);

            if (direction == ListSortDirection.Ascending)
            {
                selectedHeader.Column.HeaderTemplate =
                  FindResource("HeaderTemplateArrowUp") as DataTemplate;
            }
            else
            {
                selectedHeader.Column.HeaderTemplate =
                  FindResource("HeaderTemplateArrowDown") as DataTemplate;
            }

            // Remove arrow from previously sorted header
            if (_lastSelectedHeader != null && _lastSelectedHeader != selectedHeader)
            {
                _lastSelectedHeader.Column.HeaderTemplate = null;
            }

            _lastSelectedHeader = selectedHeader;
            _lastDirection = direction;
        }
    }
}

Come potete vedere, la logica presente nell’evento è abbastanza semplice. Qui, infatti, viene, innanzitutto, intercettato l’intestazione cliccata, e, in base alla direzione di ordinamento (Ascending o Descending) viene applicato un template diverso per visualizzare una freccetta nell’intestazione per identificarnet, appunto, l’orientamento.
Ovviemente, in questo evento, viene richiamata il metodo Sort dichiarato in precedenza. Il codice XAML per la definizione dei template da utilizzare per la visualizzazione delle freccetta di indicazione nelle intestazioni è il seguente.

<DataTemplate x:Key="HeaderTemplateArrowUp">
    <DockPanel>
        <TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
        <Path x:Name="arrow"
    StrokeThickness = "1" Fill="Black"
    Data="M 5,10 L 15,10 L 10,5 L 5,10"/>
    </DockPanel>
</DataTemplate>

<DataTemplate x:Key="HeaderTemplateArrowDown">
    <DockPanel>
        <TextBlock HorizontalAlignment="Center" Text="{Binding }"/>
        <Path x:Name="arrow"
    StrokeThickness="1" Fill="Black" 
    Data= "M 5,5 L 10,10 L 15,5 L 5,5"/>
    </DockPanel>
</DataTemplate>

Concludendo, quindi, ad un click su qualsiasi intestazione di colonna, viene effettuato l’ordinamento per la colonna in oggetto e sostituito il template dell’intestazione stessa affinchè venga in essa visualizzata una freccetta per identificarne la direzione dell’ordinamento effettuato.

martedì 8 febbraio 2011

WPF Ribbon

Ribbon Control Updates
Straight from the update details document, here's what was updated in this version:
  • Ribbon Split Button is only half-highlighted when users mouse over the button
  • Ribbon Title is bottom-aligned, should be centered
  • Ribbon Quick Access Toolbar icons are clipped and top-aligned
  • Ribbon Contextual Tab header text is getting truncated if too long
  • Ribbon Gallery Item does not stretch to fit its Parent Panel
  • Initial enabled state of Ribbon Split Menu Items can be incorrect if they have children
  • Ribbon Split Menu Item with sub-items is disabled if CanExecute=false
  • WPF Ribbon Dropdown does not close when CanAddToQuickAccessToolBarDirectly="False" was set at various level within the Ribbon
  • InvalidOperationException may occur when switching themes and the WPF Ribbon is Minimized
  • Ribbon Tab Header content may not appear when Ribbon starts out collapsed
  • RibbonTab.TabHeaderLeft & RibbonTab.TabHeaderRight are incorrect when Ribbon starts out hosted in a Collapsed control
  • Ribbon Tool Tip: Title and Footer Title gets clipped if the stringis too long
  • Vertical and horizontal alignments for the standard Ribbon controls should be centered, they were not.
  • After removing all items from the Quick Access Toolbar, phantom items remain visible
  • Right clicking on the System icon will not place the Context Menu properly
  • System Icon, Title and Quick Access Toolbar are not displayed correctly when Ribbon Windows is maximized
  • A minimized Ribbon will render on top of the window when a Popup is opened.
  • RibbonWindow.Icon does not pick appropriate small size icon from *.ico Icon file.
  • IndexOutofRange Exception would pop when removing a Tab from an Observable Collection.
  • WPF Ribbon can use ClearType when targeting .NET Framework 4.0 control.
The two most important fixes in here for me are the cleartype fix, and the support for the Express SKUs. You know I go nuts overproper ClearType rendering.
Note that the ClearType fix is in the .NET 4 version of the DLL, not in the 3.5sp1 version. That's due to it using ClearType enhancements that came about only in .NET 4. One interesting thing to note here is that we do actually have two different DLLs now, so you can have your .NET 4 project and use a version compiled specifically for .NET 4.

Download the WPF Ribbon

Samples

This release includes several samples, including a nice MVVM sample.
RibbonWindow Wordpad Sample
This sample illustrates a Ribbon control hosted within a RibbonWindow that emulates the Wordpad appearance.
RibbonWindow MVVM Sample
This sample illustrates a Ribbon control hosted within a RibbonWindow that is completely populated from a view-model collection.

RibbonBrowser Wordpad sample
This sample illustrates a Ribbon control hosted within a browser window that emulates the Wordpad appearance.

RibbonBrowser MVVM sample
This sample illustrates a Ribbon control hosted within a browser window that is completely populated from a view model collection.

martedì 18 gennaio 2011

ToolKit

Se volete un toolkit per WPF, gratuito e affidabile lo potete trovare al sequente indirizzo : http://wpf.codeplex.com/