UX: semplificare la vita all’utente forse è uno task più complessi che ci siano e a mio modo di vedere a grandissimo valore aggiunto, pensiamo ad un sistema di ricerca, come nell’immagine qui sotto, che consente all’utente di cercare all’interno dell’anagrafica dei soggetti:
image
l’utente scrive qualcosa, tipo “maur*”, e trova quello che cerca:
image
Adesso immaginiamo che lo strumento sia un piccolo gestionale per veterinari e che quindi l’utente debba poter anche cercare gli “animali”, naturalmente un animale non è un “Subject” e sarebbe quindi naturale aspettarsi di avere un’altra RibbonTab “Pets” con la possibilità di cercare nell’anagrafica degli animali.
Ma… è comodo?
Secondo me neanche un po’ :-), perchè? perchè ad esempio la mia gatta si chiama Isotta, che, anche se raro, potrebbe essere tranquillamente il nome di una cliente presente in anagrafica.
Alla fine noi abbiamo un set di informazioni che sono decisamente strutturate, ma se ci pensiamo proabilmente sono strutturate solo per noi, in quanto tecnici che conoscono il sistema, per l’utente sono invece un blobbone di informazioni in cui ha senso poter cercare esattamente come fa con un motore di ricerca su internet.
Quindi?
Se il nostro veterinario volesse cercare “Isotta” a prescindere dal fatto che sia un cliente o un paziente? semplicemente non può…
Un parallelo
Q: come fa il sistema operativo ad indicizzare il contenuto di un file che non conosce a priori? (ad esempio di un docx o di un pdf)
A: IFilter, che altro non è che un bel sistema a plugin in cui una terza parte può pluggare il suo “indexer” e quando il sistema operativo deve indicizzare contenuti “gestiti” da un IFilter semplicemente passa i contenuti all’IFilter di turno e si aspetta in cambio ad esempio delle keyword;
ISearchProvider
Perchè non prendere spunto e creare una cosa del tipo:
image
image
cioè un sistema di ricerca pluggabile che consenta ad un modulo/plugin di fare ad esempio:
sealed class Module : ModuleBase, IPetsModule
{
    readonly ISearchServices searchServices;
    readonly ISearchProvider<Pet> searchProvider;

    public Module( ISearchServices searchServices, ISearchProvider<Pet> searchProvider )
        : base( PetsModuleConstants.ModuleKey, PetsModuleConstants.ModuleName )
    {
        Ensure.That( searchServices ).Named( "searchServices" ).IsNotNull();
        Ensure.That( searchProvider ).Named( "searchProvider" ).IsNotNull();

        this.searchServices = searchServices;
        this.searchProvider = searchProvider;
    }

    protected override void OnInitialize()
    {
        base.OnInitialize();

        //Register SearchProvider...
        this.searchServices.RegisterProvider( this.searchProvider );
    }
}
che in ultima battuta, grazie a questo:
<Grid Grid.Column="2" Margin="0,0,2,0" Width="100">
    <TextBlock VerticalAlignment="Center" ToolTip="{Binding SearchProviders.Selection}">
        <Hyperlink Command="{Binding ShowSearchLocationsCommand}">
            <TextBlock Text="{Binding SearchProviders.Selection}"
                       TextTrimming="CharacterEllipsis" />
        Hyperlink>
    TextBlock>
    <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding ShowSearchLocations}" Placement="Bottom">
        <dropShadow:SystemDropShadowChrome Margin="3" Color="#71000000" CornerRadius="3">
            <Border Padding="5" CornerRadius="3" MinWidth="100">
                <Border.Background>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFFFFFFF" Offset="0"/>
                        <GradientStop Color="#FFD7E6F9" Offset="0.09"/>
                        <GradientStop Color="#FFC7DCF8" Offset="0.4"/>
                        <GradientStop Color="#FFB3D0F5" Offset="0.4"/>
                        <GradientStop Color="#FFD7E5F7" Offset="0.9"/>
                        <GradientStop Color="#FFBAD4F7" Offset="1"/>
                    LinearGradientBrush>
                Border.Background>
                <ItemsControl ItemsSource="{Binding SearchProviders}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsSelected}" 
                                  Content="{Binding DisplayName}" />
                        DataTemplate>
                    ItemsControl.ItemTemplate>
                ItemsControl>
            Border>
        dropShadow:SystemDropShadowChrome>
    Popup>
Grid>
produce un sistema di ricerca integrato:
image
.m
P.S.
Giurin giuretta ho usato Blend stavolta :-), e la prova sono i Binding in cui non c’è esplicitato “Path=” che è tipico di Blend che in coppia con il supporto per i Design Time Data che mi sono costruito fa veramente faville.