Introduzione

In questo nuovo articolo della serie su come dare quel tocco in più alle nostre applicazioni in WPF, parliamo del Outlook 2010 like Navigation Pane WPF Control, libreria disponibile gratuitamente su Codeplex al seguente indirizzo: http://navigationpane.codeplex.com/

Ecco alcuni Screenshot di quello che andremo ad analizzare prima, e realizzare dopo.

Implementazione

Apriamo Visual Studio 2015 e creiamo un nuovo progetto WPF in C#. Lo chiamiamo WPFNavigationPane.

Salviamo il progetto.

L’esempio usa il controllo Ribbon della Fluent. Faremo anche noi altrettanto.

La libreria Fluent la troviamo nel progetto scaricandola da http://navigationpane.codeplex.com/downloads/get/603078#

E all'interno della cartella \Release_1.0.4764.30675\Release 1.0\Bin\NavigationPaneDemo

In questa cartella si trova anche la libreria NavigationPane.dll. Anche questa la importeremo nel progetto, perché è il cuore dell’applicazione.

Le aggiungiamo quindi tra le Reference del progetto, come possiamo vedere nelle seguenti figure e come abbiamo fatto in casi simili nei precedenti articoli.

A questo punto siamo pronti per aggiungere le classi, il codice necessario e l’interfaccia utente.

Dovremo anche andare a cambiare qualcosa nelle impostazioni dell’applicazione.

Creiamo una nuova cartella, la rinominiamo NavigationPaneItems e al suo interno creiamo una nuova finestra e la chiamiamo Themes.xaml.

Sostituiamo tutto lo XAML con questo:

<s:NavigationPaneItem

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

  xmlns:s="NavigationPane"

  mc:Ignorable="d"

  x:Class="WpfNavigationPane.Themes"

  Header="Themes" Image="/WpfNavigationPane;component/Resources/Theme.png">

  <s:NavigationPaneItem.CommandBindings>

  <CommandBinding x:Name="ChangeTheme" Command="Open" Executed="ChangeTheme_Executed" CanExecute="ChangeTheme_CanExecute" />

  </s:NavigationPaneItem.CommandBindings>

  <StackPanel Margin="4,0">

  <TextBlock Text="Select a theme :" FontWeight="Bold" />

  <StackPanel Margin="8,0,0,0">

   <RadioButton Content="Office 2007 Blue" Margin="0,8,0,1" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2007Blue}"/>

  <RadioButton Content="Office 2007 Silver" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2007Silver}" Margin="0,0,0,1"/>

  <RadioButton Content="Office 2007 Black" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2007Black}" Margin="0,0,0,1"/>

  <RadioButton Content="Office 2010 Blue" Margin="0,8,0,1" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2010Blue}"/>

  <RadioButton Content="Office 2010 Silver" IsChecked="True" FontWeight="Bold" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2010Silver}" Margin="0,0,0,1"/>

  <RadioButton Content="Office 2010 Black" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.Office2010Black}" Margin="0,0,0,1"/>

  <RadioButton Content="Windows Live" Margin="0,8,0,1" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.WindowsLive}" />

  <RadioButton Content="Metro Blue" Margin="0,8,0,1" Command="ApplicationCommands.Open" CommandParameter="{x:Static s:NavigationPaneTheme.MetroBlue}" />

  </StackPanel>

  <TextBlock TextWrapping="Wrap" FontSize="10.667" Margin="0,10,0,0"><Run Language="it-it" Text="If you are using some other control wich also have office styles, you should implement the style change for those too !!"/></TextBlock>

  </StackPanel>

</s:NavigationPaneItem >

E il code-behind sarà così:

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using Stema.Controls;

namespace WpfNavigationPane

{

  /// <summary>

  /// Interaction logic for UserControl1.xaml

  /// </summary>

  public partial class Themes : NavigationPaneItem

  {

  public Themes()

  {

  this.InitializeComponent();

  }

  private void ChangeTheme_Executed(object sender, ExecutedRoutedEventArgs e)

  {

  ThemeManager.SetActiveTheme((NavigationPaneTheme)e.Parameter);

  }

  private void ChangeTheme_CanExecute(object sender, CanExecuteRoutedEventArgs e)

  {

  e.CanExecute = e.Parameter != null;

  }

  }

}

Salviamo e compiliamo.

Se segnala errori, per ora ignoriamoli, verifichiamo che comunque compila e il progetto venga eseguito.

Creiamo ora una nuova cartella e la chiamiamo SampleData

Al suo interno creiamo una nuova cartella chiamata SampleDataSource1

Creiamo ora una nuova pagina chiamata SampleDataSource1.

Lo Xaml sarà così:

<!--

  *********  DO NOT MODIFY THIS FILE  *********

  This file is regenerated by a design tool. Making

  changes to this file can cause errors.

-->

<SampleData:SampleDataSource1 xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.SampleDataSource1">

  <SampleData:SampleDataSource1.Collection>

  <SampleData:Item Header="Nam class" CanResize="True"/>

  <SampleData:Item Header="Aenean sed curae" CanResize="False"/>

  <SampleData:Item Header="Donec maecenas praesent" CanResize="True"/>

  <SampleData:Item Header="Cras etiam" CanResize="False"/>

  <SampleData:Item Header="Fusce accumsan aliquam" CanResize="True"/>

  <SampleData:Item Header="Dis duis mauris" CanResize="False"/>

  <SampleData:Item Header="Bibendum est nullam aptent" CanResize="True"/>

  <SampleData:Item Header="Hac integer leo dictumst" CanResize="False"/>

  <SampleData:Item Header="Auctor nunc" CanResize="True"/>

  <SampleData:Item Header="Amet quisque congue" CanResize="False"/>

  </SampleData:SampleDataSource1.Collection>

</SampleData:SampleDataSource1>

E il code-behind:

//  *********  DO NOT MODIFY THIS FILE  *********

//  This file is regenerated by a design tool. Making

//  changes to this file can cause errors.

namespace Expression.Blend.SampleData.SampleDataSource1

{

  using System;

// To significantly reduce the sample data footprint in your production application, you can set

// the DISABLE_SAMPLE_DATA conditional compilation constant and disable sample data at runtime.

#if DISABLE_SAMPLE_DATA

  internal class SampleDataSource1 { }

#else

  public class SampleDataSource1 : System.ComponentModel.INotifyPropertyChanged

  {

  public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged(string propertyName)

  {

  if (this.PropertyChanged != null)

  {

  this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));

  }

  }

  public SampleDataSource1()

  {

  try

  {

  System.Uri resourceUri = new System.Uri("/WpfNavigationPane;component/SampleData/SampleDataSource1/SampleDataSource1.xaml", System.UriKind.Relative);

  if (System.Windows.Application.GetResourceStream(resourceUri) != null)

  {

  System.Windows.Application.LoadComponent(this, resourceUri);

  }

  }

  catch (System.Exception)

  {

  }

  }

  private ItemCollection _Collection = new ItemCollection();

  public ItemCollection Collection

  {

  get

  {

  return this._Collection;

  }

    }

  }

  public class ItemCollection : System.Collections.ObjectModel.ObservableCollection<Item>

  {

  }

  public class Item : System.ComponentModel.INotifyPropertyChanged

  {

  public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged(string propertyName)

  {

  if (this.PropertyChanged != null)

  {

  this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));

  }

  }

  private string _Header = string.Empty;

  public string Header

  {

  get

  {

  return this._Header;

  }

  set

  {

  if (this._Header != value)

  {

  this._Header = value;

  this.OnPropertyChanged("Header");

  }

  }

  }

  private bool _CanResize = false;

  public bool CanResize

  {

  get

  {

  return this._CanResize;

  }

  set

  {

  if (this._CanResize != value)

  {

  this._CanResize = value;

  this.OnPropertyChanged("CanResize");

  }

  }

  }

  }

#endif

}

Salviamo e compiliamo e verifichiamo che il progetto venga eseguito.

Apriamo ora il file app.config e andiamo a sostituire tutto il codice che c’è con questo:

<?xml version="1.0"?>

<configuration>

  <configSections>

  <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

  <section name="WpfNavigationPane.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>

  </sectionGroup>

  </configSections>

  <userSettings>

  <WpfNavigationPane.Properties.Settings>

  <setting name="NavigationPaneSettings" serializeAs="String">

  <value/>

  </setting>

  </WpfNavigationPane.Properties.Settings>

  </userSettings>

  <startup>

  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>

  </startup>

</configuration>

Salviamo, compiliamo e verifichiamo che il progetto venga ancora eseguito.

Modifichiamo ora l’App.xaml con questo codice:

<Application

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.SampleDataSource1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"

   StartupUri="MainWindow.xaml">

  <Application.Resources>

  <ResourceDictionary>

  <ResourceDictionary.MergedDictionaries>

  <ResourceDictionary Source="pack://application:,,,/NavigationPane;Component\Themes\NavigationPane\Office2010\Silver.xaml" />

  <!-- Fluent Ribbon Staff - Fluent.Codeplex.com -->

  <ResourceDictionary Source="pack://application:,,,/Fluent;Component\Themes\Office2010\Silver.xaml" />

  </ResourceDictionary.MergedDictionaries>

  <SampleData:SampleDataSource1 x:Key="SampleDataSource1" d:IsDataSource="True"/>

  </ResourceDictionary>

  </Application.Resources>

</Application>

Creiamo ora una nuova cartella chiamata Resources e ci mettiamo questi file (basta anche rinominati così, o prenderli da progetto scaricato da Codeplex):

-  Bar.png

-  folderopen.ico

-  mail.ico

-  NavigationPane.png

-  Theme.png

Proviamo ancora una volta che compila ed esegue.

Siamo ora pronti a creare una versione “base”.

Nel MainWindow mettiamo il seguente codice:

<Window x:Class="WPFNavigationPane.MainWindow"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:s="NavigationPane"

   x:Name="window"

    Title="TestWindow"

   Width="520"

   Height="494"

   WindowStartupLocation="CenterScreen"

   mc:Ignorable="d">

  <Window.Resources>

  <SolidColorBrush x:Key="Brush1" Color="Black" />

  <DataTemplate x:Key="DataTemplate1">

  <Grid>

  <TextBlock Text="TextBlock"

   TextWrapping="Wrap"

   d:LayoutOverrides="Height" />

  <Image x:Name="image"

   Width="16"

   Height="16"

   HorizontalAlignment="Left"

   Source="Resources/mail.ico"

   Stretch="Fill" />

  </Grid>

  <DataTemplate.Triggers />

  </DataTemplate>

  <s:BooleanNegateConverter x:Key="BooleanNegateConverter" />

  <Style x:Key="NavigationPaneItemStyle1" TargetType="{x:Type s:NavigationPaneItem}">

  <Setter Property="BorderThickness" Value="1" />

  <Setter Property="Template">

  <Setter.Value>

  <ControlTemplate TargetType="{x:Type s:NavigationPaneItem}">

  <DockPanel>

  <s:NavigationPaneButton x:Name="PART_ItemButton"

    Margin="{DynamicResource {ComponentResourceKey ResourceId=LargeItemsMargin,

   TypeInTargetAssembly={x:Type s:NavigationPane}}}"

   Anchor="Top"

   CheckMode="Check"

   Content="{TemplateBinding Header}"

    ContentStringFormat="{TemplateBinding HeaderStringFormat}"

   ContentTemplate="{TemplateBinding HeaderTemplate}"

   ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"

   DockPanel.Dock="Top"

   FontWeight="Bold"

    Foreground="{DynamicResource {ComponentResourceKey ResourceId=ForeColorInactive,

   TypeInTargetAssembly={x:Type s:NavigationPane}}}"

    Image="{TemplateBinding Image}"

   ImageSmall="{TemplateBinding ImageSmall}"

   ImageType="Large"

    IsChecked="{Binding IsSelected,

   Mode=TwoWay,

   RelativeSource={RelativeSource TemplatedParent}}"

   IsContentVisible="{Binding IsMinimized,

   Converter={StaticResource BooleanNegateConverter},

   RelativeSource={RelativeSource FindAncestor,

   AncestorType={x:Type s:NavigationPane}}}"

   Padding="{DynamicResource {ComponentResourceKey ResourceId=LargeItemsPadding,

   TypeInTargetAssembly={x:Type s:NavigationPane}}}"

   ToolTip="{TemplateBinding ButtonToolTipGesture}" />

  <ContentPresenter x:Name="contentPresenter"

    Content="{TemplateBinding Content}"

   ContentStringFormat="{TemplateBinding ContentStringFormat}"

   ContentTemplate="{TemplateBinding ContentTemplate}"

   ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"

   DockPanel.Dock="Top" />

  </DockPanel>

  <ControlTemplate.Triggers>

  <Trigger Property="Selector.IsSelected" Value="True">

  <Setter TargetName="PART_ItemButton" Property="Foreground" Value="{DynamicResource {ComponentResourceKey ResourceId=ForeColorActive, TypeInTargetAssembly={x:Type s:NavigationPane}}}" />

  </Trigger>

  <Trigger Property="IsMouseOver" Value="True">

  <Setter TargetName="PART_ItemButton" Property="Foreground" Value="{DynamicResource {ComponentResourceKey ResourceId=ForeColorActive, TypeInTargetAssembly={x:Type s:NavigationPane}}}" />

  </Trigger>

  <Trigger Property="IsInsideNavigationPane" Value="True">

  <Setter TargetName="contentPresenter" Property="Visibility" Value="Collapsed" />

  </Trigger>

  <Trigger Property="s:NavigationPanePanel.ItemDisplayType" Value="Small">

  <Setter TargetName="PART_ItemButton" Property="IsContentVisible" Value="False" />

  <Setter TargetName="PART_ItemButton" Property="Margin" Value="-1,0,0,0" />

   <Setter TargetName="PART_ItemButton" Property="DockPanel.Dock" Value="Right" />

  <Setter TargetName="PART_ItemButton" Property="ImageType" Value="Small" />

  </Trigger>

  </ControlTemplate.Triggers>

  </ControlTemplate>

  </Setter.Value>

  </Setter>

  </Style>

  <DataTemplate x:Key="DataTemplate2">

  <Grid>

  <Rectangle Fill="#FF2323D2" Stroke="Black" />

  </Grid>

  </DataTemplate>

  </Window.Resources>

  <Grid Background="{DynamicResource Brush1}">

  <s:NavigationPane Width="176"

   HorizontalAlignment="Left"

   ContentTemplate="{DynamicResource DataTemplate2}"

   ItemsSource="{Binding Resources.Keys,

   ElementName=window}"

   ItemTemplate="{DynamicResource DataTemplate1}"

    SelectedIndex="0" />

  </Grid>

</Window>

E non tocchiamo nulla nel code-behind.

Compiliamo ed eseguiamo (ignoriamo i messaggi di errore, se presenti):

Ecco il risultato:

Giochiamoci un po' tanto per vedere che il NavigationPane funzioni.

Ora andremo a modificare MainWindow.xaml mettendo il seguente codice:

<Fluent:RibbonWindow x:Class="WpfNavigationPane.MainWindow"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:demo="clr-namespace:WpfNavigationPane"

   xmlns:Fluent="clr-namespace:Fluent;assembly=Fluent"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:s="NavigationPane"

   Title="Navigation Pane v1.0"

   Background="{Binding Background,

   ElementName=navigationPaneExpander}"

   Icon="Resources/folderopen.ico"

   Loaded="RibbonWindow_Loaded"

   ResizeMode="CanResizeWithGrip"

   WindowStartupLocation="CenterScreen"

   mc:Ignorable="d">

  <Fluent:RibbonWindow.Resources>

  <!--

  THEMES

 

  The theme can be canged in two ways

  By statically merging the theme Dictionary resource in the app.xaml o by code behind

  - to see the exact dictionary path for each theme and have futher informations, see ths application app.xaml file

  - to see how to change the theme in code behind see the implementation in the "Themes" item

  -->

  <ResourceDictionary>

  <s:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter1" />

  <s:BooleanNegateConverter x:Key="BooleanNegateConverter" />

  <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />

  </ResourceDictionary>

  </Fluent:RibbonWindow.Resources>

  <DockPanel DataContext="{Binding Source={StaticResource SampleDataSource1}}">

  <Fluent:Ribbon DockPanel.Dock="Top">

  <Fluent:Ribbon.Menu>

  <Fluent:Backstage Background="#FF7777A1" />

  </Fluent:Ribbon.Menu>

  <Fluent:RibbonTabItem Header="View">

  <Fluent:RibbonGroupBox Header="Layout">

  <Fluent:DropDownButton Header="Navigation Pane">

  <Fluent:DropDownButton.LargeIcon>

  <Image Source="Resources/NavigationPane.png" />

  </Fluent:DropDownButton.LargeIcon>

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Normal"

   IsCheckable="True"

    IsChecked="{Binding IsMinimized,

   ConverterParameter=Normal,

   Converter={StaticResource BooleanNegateConverter},

   ElementName=navigationPane}" />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Minimized"

    IsCheckable="True"

   IsChecked="{Binding IsMinimized,

   ElementName=navigationPane}" />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Off"

   IsCheckable="True"

   IsChecked="{Binding NavigatioPaneOff,

    ElementName=ribbonWindow}" />

  <Separator />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Command="s:NavigationPane.ConfigureCommand"

   CommandParameter="Options"

   CommandTarget="{Binding ElementName=navigationPane,

   Mode=OneWay}"

    Header="Options..." />

  </Fluent:DropDownButton>

  <Fluent:DropDownButton />

  <Fluent:DropDownButton Header="Expander">

  <Fluent:DropDownButton.LargeIcon>

  <Image Source="/WpfNavigationPane;component/Resources/Bar.png" />

  </Fluent:DropDownButton.LargeIcon>

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Normal"

   IsCheckable="True"

   IsChecked="{Binding IsMinimized,

   Converter={StaticResource BooleanNegateConverter},

   ElementName=navigationPaneExpander}" />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Minimized"

   IsCheckable="True"

   IsChecked="{Binding IsMinimized,

   ElementName=navigationPaneExpander}" />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Header="Off"

   IsCheckable="True"

    IsChecked="{Binding ExpanderPaneOff,

   ElementName=ribbonWindow}" />

  <Separator />

  <Fluent:MenuItem CanAddToQuickAccessToolBar="False"

   Command="s:NavigationPane.ConfigureCommand"

   CommandParameter="Options"

   CommandTarget="{Binding ElementName=Sections}"

   Header="Options..." />

  </Fluent:DropDownButton>

  </Fluent:RibbonGroupBox>

  <Fluent:RibbonGroupBox Header="State">

  <Fluent:Button Click="Button_Click_1" Header="Save State" />

  <Fluent:Button Click="Button_Click_2" Header="Load State" />

  </Fluent:RibbonGroupBox>

  </Fluent:RibbonTabItem>

  </Fluent:Ribbon>

  <Fluent:StatusBar VerticalAlignment="Bottom" DockPanel.Dock="Bottom" />

  <s:NavigationPane x:Name="navigationPane"

   Width="162"

   Margin="2,0,0,1"

   BarTitle="lsdajfls"

   HasResizeThumb="True"

   SelectedIndex="0"

   SelectionChanged="navigationPane_SelectionChanged">

  <s:NavigationPane.ItemsButtonsContextMenu>

  <ContextMenu>

  <s:ConfigureMenuItem MenuType="Options" />

  </ContextMenu>

  </s:NavigationPane.ItemsButtonsContextMenu>

  <s:NavigationPaneItem Name="intro"

   Header="Intro"

   Image="pack://application:,,,/NavigationPane;Component\Resources\Images\WindowsHS.png">

  <s:NavigationPaneItem.SubItems>

  <s:NavigationPaneButton Content="prova"

   Image="Resources/mail.ico"

   ImageSmall="Resources/folderopen.ico" />

  </s:NavigationPaneItem.SubItems>

  <StackPanel>

  <TextBlock Margin="0,0,0,8"

   HorizontalAlignment="Left"

   FontSize="10.667"

   TextWrapping="Wrap"><Run Language="it-it" Text="This is an Item created directly in the window with xaml." />

  <LineBreak /><Run Language="it-it" />

  <LineBreak /><Run Language="it-it" Text="To see an example of an item created in its own xaml file, see the &quot;Theme&quot; item below how it was implemented" />

  <LineBreak /><Run Language="it-it" />

  <LineBreak /><Run Language="it-it" Text="Adding items programatically. See window code behind if needed." />

  <LineBreak /><Run Language="it-it" Text="Hit the Button" />

  </TextBlock>

  <TextBlock Margin="8,0,8,2" Text="New item name:" />

  <TextBox x:Name="newItemName"

   Margin="8,0,8,4"

   Text="NewItem" />

  <TextBlock Margin="8,0,8,2" Text="New item contents:" />

  <TextBox x:Name="newItemContents"

   Margin="8,0,8,4"

   MinLines="4"

   Text="New Item Contents" />

  <CheckBox x:Name="newItemExcluded"

   Margin="8,0,8,4"

   Content="Create a Disabled Item " />

  <Button Margin="8,0"

   Click="Button_Click"

   Content="Create New Item" />

  </StackPanel>

  </s:NavigationPaneItem>

  <demo:Themes />

  </s:NavigationPane>

  <s:NavigationPaneExpander x:Name="navigationPaneExpander2"

   Width="200"

   Margin="0,0,2,1"

   CloseButtonClick="navigationPaneExpander_CloseButtonClick"

   DockPanel.Dock="Right"

    FontSize="9.333"

   Header="ItemsSource Example"

   IsHeaderVisible="True"

   ItemsSource="{Binding Collection}"

   Orientation="Right" />

  <s:NavigationPaneExpander x:Name="navigationPaneExpander"

   Width="200"

   Margin="0,0,2,1"

   CloseButtonClick="navigationPaneExpander_CloseButtonClick"

   DockPanel.Dock="Right"

   Orientation="Right">

  <s:NavigationPaneExpander.Header>

  <TextBlock Foreground="Red" Text="Expander Header" />

  </s:NavigationPaneExpander.Header>

  <Grid x:Name="CanResizeContent" s:NavigationPaneExpander.CanResize="False">

  <Grid.RowDefinitions>

  <RowDefinition />

   <RowDefinition Height="Auto" />

  <RowDefinition Height="Auto" />

  <RowDefinition Height="Auto" />

  <RowDefinition Height="Auto" />

  <RowDefinition Height="Auto" />

   </Grid.RowDefinitions>

  <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">

  <TextBlock FontSize="10.667"

   TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="Wrap"><Run Text="You can put any control in a " /><Run FontWeight="Bold" Text="NavigationPaneExpander" />

  <LineBreak /><Run Text="But only " /><Run FontStyle="Italic"

   FontWeight="Bold"

   Text="HeaderedItemsControls" /><Run Language="it-it" Text=" " /><Run Text="will show in the bar when minimized." />

  <LineBreak /><Run Text="Try to minimize me to see the bar." />

  </TextBlock>

  </ScrollViewer>

  <Separator Grid.Row="1" />

  <TextBlock Grid.Row="2"

   FontSize="10.667"

   Text="You can hide the resize thumb by setting the attached property NavigationPaneExpander.CanResize"

   TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="WrapWithOverflow" />

  <s:NavigationPaneButton Grid.Row="3"

   Margin="0,2,0,0"

   HorizontalContentAlignment="Center"

   CheckMode="CheckUncheck"

    FontSize="10.667"

   FontWeight="Bold"

   IsChecked="{Binding (s:NavigationPaneExpander.CanResize),

    ElementName=CanResizeContent,

   Mode=TwoWay}"

   Padding="2"

   ToolTip="Click me to change the Property CanResize">

  <!--  Button content is in a TextBlock because buttons in WPf seems to have some problem with StringFormat proerty of Binding  -->

  <!--

  In VisualStudio you probably will not see the contents of the button ( vs doesn't supports binding on attached properties !! ) !

  But at runtime or in Blend will be shown correctly.

  -->

  <TextBlock Text="{Binding (s:NavigationPaneExpander.CanResize), ElementName=CanResizeContent, StringFormat=Can Resize: \{0\}}" />

  </s:NavigationPaneButton>

  <Separator Grid.Row="4" />

  <TextBlock Grid.Row="5"

   FontSize="10.667"

   FontStyle="Italic"

   TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="WrapWithOverflow"

   Visibility="{Binding (s:NavigationPaneExpander.CanResize),

   Converter={StaticResource BooleanToVisibilityConverter},

   ElementName=CanResizeContent}"><Run Text="When visible you can double click the resize thumb to auto size the control." />

  <LineBreak /><Run Text="You can also use MinHeight and MaxHeight to affect the way the element is resized." />

  </TextBlock>

  </Grid>

  <HeaderedContentControl Name="BarItem1" Header="BarItem1">

  <TextBlock FontSize="10.667"

   TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="Wrap">

  <Run FontWeight="Bold" Text="BarItem1" />

  <LineBreak />

  <Run Text="Being a HeaderedContentControl this one will be shown in the bar." />

  </TextBlock>

  </HeaderedContentControl>

  <HeaderedContentControl>

  <HeaderedContentControl.Header>

  <StackPanel Orientation="Horizontal">

  <Image Width="16"

   Margin="0,0,4,0"

   VerticalAlignment="Center"

   Source="Resources/mail.ico" />

  <TextBlock VerticalAlignment="Center"><Run Text="BarItem2" />

  </TextBlock>

   </StackPanel>

  </HeaderedContentControl.Header>

  <TextBlock Name="BarItem2"

   FontSize="10.667"

   TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="Wrap">

  <Run FontWeight="Bold" Text="BarItem2" />

  <LineBreak />

  <Run Text="This one too will be shown in the bar. But will have an image, since the Header property is not set to a simple string." />

  <Hyperlink>

  <Hyperlink.ToolTip>

  <Fluent:ScreenTip Title="..However.."

   Width="200"

   Text="Since this is not a NavigationPaneItem, you will notice that image is rotated as the text does. This could be useful if you need to rotate the Header contents. But if you would like to have the image shown properly, you should use a NavigationPaneItem instead of a HeaderedContentControl. Since the control knows how handle NavigationPaneItem image property" />

  </Hyperlink.ToolTip><Run Text="more..." />

  </Hyperlink>

  </TextBlock>

  </HeaderedContentControl>

  <s:NavigationPaneItem Name="BarItem3"

   Header="BarItem3"

   ImageSmall="Resources/mail.ico">

  <TextBlock TextAlignment="Right"

   TextTrimming="WordEllipsis"

   TextWrapping="Wrap"><Run Text="This is the native control to put in there !!" />

  </TextBlock>

  </s:NavigationPaneItem>

  <Calendar s:NavigationPaneExpander.CanResize="False" />

  </s:NavigationPaneExpander>

  <Border Margin="2,2,4,4"

   Background="White"

   BorderBrush="{Binding BorderBrush,

   ElementName=navigationPane}"

   BorderThickness="1"

   Padding="6">

  <Border.Effect>

  <DropShadowEffect BlurRadius="4"

   Opacity="0.3"

   ShadowDepth="0"

   Color="#AC000000" />

  </Border.Effect>

  </Border>

  </DockPanel>

</Fluent:RibbonWindow>

E il code-behind:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using Stema.Controls;

using Fluent;

namespace WpfNavigationPane

{

  /// <summary>

  /// Interaction logic for MainWindow.xaml

  /// </summary>

  public partial class MainWindow : RibbonWindow

  {

  public MainWindow()

  {

  InitializeComponent();

  }

  public bool NavigatioPaneOff

  {

  get { return navigationPane.Visibility == System.Windows.Visibility.Collapsed; }

  set

  {

  navigationPane.Visibility = value ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible;

  }

  }

  public bool ExpanderPaneOff

  {

  get { return navigationPaneExpander.Visibility == System.Windows.Visibility.Collapsed; }

  set

  {

  navigationPaneExpander.Visibility = value ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible;

   }

  }

  private void navigationPaneExpander_CloseButtonClick(object sender, RoutedEventArgs e)

  {

  }

  private void Button_Click(object sender, RoutedEventArgs e)

  {

  NavigationPaneItem item = new NavigationPaneItem();

  item.Header = newItemName.Text;

  item.Content = newItemContents.Text;

  item.Image = new BitmapImage(new Uri(@"pack://application:,,,/WpfNavigationPane;component/Resources/folderopen.ico"));

  navigationPane.Items.Add(item);

  item.IsExcluded = newItemExcluded.IsChecked.Value;

  }

  private void button1_Click(object sender, RoutedEventArgs e)

  {

  System.IO.MemoryStream ms = new System.IO.MemoryStream();

  navigationPane.SaveState(ms);

  ms.Position = 0;

  WpfNavigationPane.Properties.Settings.Default.NavigationPaneSettings = new System.IO.StreamReader(ms).ReadToEnd();

  // Load settings

  navigationPane.LoadState(new System.IO.MemoryStream(Encoding.UTF8.GetBytes(WpfNavigationPane.Properties.Settings.Default.NavigationPaneSettings)));

  }

  private void Button_Click_1(object sender, RoutedEventArgs e)

  {

  System.IO.MemoryStream ms = new System.IO.MemoryStream();

  navigationPane.SaveState(ms);

  ms.Position = 0;

  WpfNavigationPane.Properties.Settings.Default.NavigationPaneSettings = new System.IO.StreamReader(ms).ReadToEnd();

  // settings are correctly saved

  //NavigationPaneDemo.Properties.Settings.Default.Reset();

  }

  private void Button_Click_2(object sender, RoutedEventArgs e)

  {

  // Load settings

  navigationPane.LoadState();

  }

  private void RibbonWindow_Loaded(object sender, RoutedEventArgs e)

  {

  //Button_Click_2(this, null);

  navigationPane.IsMinimized = true;

  }

  private void navigationPane_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)

  {

  // TODO: Add event handler implementation here.

  }

  }

}

Ultima cosa da fare è quella di andare nei Settings.Designer.cs e sostituire il codice esistente con questo:

//------------------------------------------------------------------------------

// <auto-generated>

//  Il codice è stato generato da uno strumento.

//  Versione runtime:4.0.30319.42000

//

//  Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se

//  il codice viene rigenerato.

// </auto-generated>

//------------------------------------------------------------------------------

namespace WpfNavigationPane.Properties

{

  [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]

  [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]

  internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase

  {

  private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

  public static Settings Default

  {

  get

  {

  return defaultInstance;

  }

  }

  [global::System.Configuration.UserScopedSettingAttribute()]

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]

  [global::System.Configuration.DefaultSettingValueAttribute("")]

  public string NavigationPaneSettings

  {

  get

  {

  return ((string)(this["NavigationPaneSettings"]));

  }

  set

  {

  this["NavigationPaneSettings"] = value;

  }

  }

  }

}

Ora lanciamo l’applicazione. Se ci sono errori, chiudere Visual Studio 2015 e quindi ricaricare il progetto.

Vediamo qualche personalizzazione:

nella MainWindow:

<s:NavigationPane x:Name="navigationPane"

   Width="162"

   Margin="2,0,0,1"

   BarTitle="lsdajfls"

Nel BarTitle mettere quello che si vuole.

  <s:NavigationPaneButton Content="prova"

   Image="Resources/mail.ico"

   ImageSmall="Resources/folderopen.ico" />

Mettere quello che si vuole al posto di prova e al posto dell’icona mail.

Le voci in basso a sinistra:

  <s:NavigationPaneItem Name="intro"

   Header="Intro"

   Image="pack://application:,,,/NavigationPane;Component\Resources\Images\WindowsHS.png">

  <s:NavigationPaneItem.SubItems>

  <s:NavigationPaneButton Content="prova"

   Image="Resources/mail.ico"

   ImageSmall="Resources/folderopen.ico" />

   </s:NavigationPaneItem.SubItems>

  <StackPanel>

  <TextBlock Margin="0,0,0,8"

   HorizontalAlignment="Left"

   FontSize="10.667"

   TextWrapping="Wrap"><Run Language="it-it" Text="This is an Item created directly in the window with xaml." />

  <LineBreak /><Run Language="it-it" />

  <LineBreak /><Run Language="it-it" Text="To see an example of an item created in its own xaml file, see the &quot;Theme&quot; item below how it was implemented" />

  <LineBreak /><Run Language="it-it" />

  <LineBreak /><Run Language="it-it" Text="Adding items programatically. See window code behind if needed." />

  <LineBreak /><Run Language="it-it" Text="Hit the Button" />

  </TextBlock>

  <TextBlock Margin="8,0,8,2" Text="New item name:" />

  <TextBox x:Name="newItemName"

   Margin="8,0,8,4"

   Text="NewItem" />

  <TextBlock Margin="8,0,8,2" Text="New item contents:" />

  <TextBox x:Name="newItemContents"

   Margin="8,0,8,4"

   MinLines="4"

   Text="New Item Contents" />

  <CheckBox x:Name="newItemExcluded"

   Margin="8,0,8,4"

   Content="Create a Disabled Item " />

  <Button Margin="8,0"

   Click="Button_Click"

   Content="Create New Item" />

  </StackPanel>

  </s:NavigationPaneItem>

Per Intro

Mentre per Themes viene caricato il tema Themes.xaml:

  <demo:Themes />

Per la parte destra:

  <s:NavigationPaneExpander x:Name="navigationPaneExpander2"

   Width="200"

   Margin="0,0,2,1"

   CloseButtonClick="navigationPaneExpander_CloseButtonClick"

   DockPanel.Dock="Right"

   FontSize="9.333"

    Header="ItemsSource Example"

   IsHeaderVisible="True"

   ItemsSource="{Binding Collection}"

   Orientation="Right" />

  <s:NavigationPaneExpander x:Name="navigationPaneExpander"

   Width="200"

   Margin="0,0,2,1"

   CloseButtonClick="navigationPaneExpander_CloseButtonClick"

    DockPanel.Dock="Right"

   Orientation="Right">

E’ comunque tutto in MainWindow. Basterà giocarci per capire le potenzialità del pannello di navigazione.

Conclusioni

In questo articolo abbiamo quanto sia semplice creare schermate accattivanti anche per soluzioni Business. Basta referenziare una DLL e poi possiamo fare con con l'XAML tutto quello che vogliamo. Anche qua l'unico limite è la fantasia.