WPF adresář - 3. díl
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

WPF adresář - 3. dílWPF adresář - 3. díl

 

WPF adresář - 3. díl

Google       Google       27. 2. 2008       18 741×

V závěrečném dílu této trilogie doděláme Adresář, připravený na doplnění dalších funkcí podle vaší fantazie.

Dnes dostaneme Adresář do finální podoby. Jak jsem slíbil, program nebude umět ukládat změny v kontaktech, importovat je, ani exportovat, ale bude kompletní po WPF stránce.

Minule vytvořené okno OknoBezOkna bude sloužit pouze jako takové spojení mezi okny na přidávání kontaktů a zbytkem programu. Teď si vytvoříme už tolikrát zmiňované dvě stránky s políčky na údaje o novém kontaktu. První stránku pojmenujeme třeba KontaktStr1, bude obsahovat pole pro křestní jméno, příjmení, e-mail adresu a webovou adresu. Popis, jak založit nový XAML soubor, už přeskočím (viz minulý díl), jen zmíním, že bude opět podle šablony Page Function a nezapomeňte opět změnit TypeArguments na Object!

<PageFunction
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    x:Class="Adresar.KontaktStr1"
    x:TypeArguments="sys:Object"
    Title="Nový kontakt - 1">
    <Grid Name ="HlavniMrizka" 
        VerticalAlignment="Center"
        HorizontalAlignment="Center">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="60"/>
        </Grid.RowDefinitions>

        <!-- Popisky jednotlivých polí -->
        <TextBlock Width="200" Height="30" Grid.Column="0" Grid.Row="1" 
                   Text=" Křestní jméno" /> 
        <TextBlock Width="200" Height="30" Grid.Column="0" Grid.Row="2" 
                   Text=" Příjmení" />  
        <TextBlock Width="200" Height="30" Grid.Column="0" Grid.Row="3" 
                   Text=" E-mail adresa" />
        <TextBlock Width="200" Height="30" Grid.Column="0" Grid.Row="4" 
                   Text=" WWW adresa" />

        <!-- Vstupní pole -->
        <TextBox Name="txtJmenoKrestni" Width="200" Height="30" 
             Grid.Column="1" Grid.Row="1" 
             Text="{Binding Path=JmenoKrestni, Mode=TwoWay}"/>
        <TextBox Name="txtJmenoPrijmeni" Width="200" Height="30" 
             Grid.Column="1" Grid.Row="2" 
             Text="{Binding Path=JmenoPrijmeni, Mode=TwoWay}"/>
        <TextBox Name="txtEmail" Width="200" Height="30" 
             Grid.Column="1" Grid.Row="3" 
             Text="{Binding Path=Email, Mode=TwoWay}"/>
        <TextBox Name="txtHomePage" Width="200" Height="30" 
             Grid.Column="1" Grid.Row="4" 
             Text="{Binding Path=HomePage, Mode=TwoWay}"/>
        <Button Name="tlHomePage" Width="200" Height="30" 
            Grid.Column="1" Grid.Row="4" 
            Content="{Binding Path=HomePage, Mode=TwoWay}" 
            Click="Jdi_WWW"/>
        <Button Name="tlEmail" Width="200" Height="30" 
            Grid.Column="1" Grid.Row="3" 
            Content="{Binding Path=Email, Mode=TwoWay}" 
            Click="PoslatEmail"/>

        <!-- Dolní navigační tlačítka -->
        <DockPanel Name="Panel1" Grid.Column="0" Grid.Row="5" >
            <Button Name="tlDalsi" Width="100" Height="30" 
              Click="Dalsi_Klik" Content="Další" />
            <Button Name="tlZrusit" Width="100" Height="30" 
              Click="Zrusit_Klik" Content="Zrušit" />
        </DockPanel>
        <DockPanel Name="Panel2" Grid.Column="1" Grid.Row="5">
            <Button Name="tlHotovo" Width="100" Height="30" 
              Click="Hotovo_Klik" Content="Hotovo"/>
        </DockPanel>
    </Grid>

</PageFunction>

V kódu není nic, co bychom už neznali. Jako základ nám poslouží mřížka s dvěma sloupci a šesti řádky. V levém sloupci v každém řádku je popisek ve formě TextBlocku a k  němu odpovídající TextBox, resp. tlačítko (Button). Ještě si všimněte, jak je každý prvek z druhého sloupce hezky provázán se svojí vlastností, využíváme tzv. TwoWay Binding – pokud se změní obsah TextBoxu, automaticky se na stejnou hodnotu přepíše i jeho vlastnost. To samé by se stalo s TextBoxem, kdybychom nějak externě změnili obsah vlastnosti.

Přesuneme se do „logické“ části tohoto souboru, do KontaktStr1.xaml.cs. Pokud jste už tak neučinili automaticky, změňte opět typový argument ze String na Object.

Toto okno budeme chtít zobrazovat ve dvou módech, které rozlišíme podle booleanovské hodnoty. Jedním módem bude mód Úprav, druhý mód bude Čtení. První ze jmenovaných využijeme v tom, co teď děláme (přidávač kontaktů), a Čtení aplikujeme pro pravou část hlavního okna aplikace, kde se objeví detaily o kontaktu, který si uživatel zvolí v ListBoxu vlevo. Tam zobrazené informace totiž budou pouze pro čtení, aby je uživatel mohl upravit, bude muset kliknout na některé tlačítko z nabídky.

        // Vytvoří první stránku přidávače, argument mod_uprav
        // určí mód použití
         
        public KontaktStr1(bool mod_uprav, int cisloPredmetu)
        {
            InitializeComponent();
            this.KeepAlive = true;

            // pokud je v módu čtení... 
            if (mod_uprav == false)
            {
                SeznamKontaktu sk = 
                    Application.Current.Properties["SeznamKontaktu"] 
                           as SeznamKontaktu;

                // pokud obsahuje seznam kontaktů alespoň jeden zápis, pomocí
                // DataContextu vyplní jednotlivé TextBoxy a...
                if (sk != null && sk.Count > 0)
                {
                    Kontakt k = sk[cisloPredmetu];
                    this.HlavniMrizka.DataContext = k;
                
                    // ... a nastaví je jen pro čtení (ReadOnly) 
                    this.txtEmail.IsEnabled = false;
                    this.txtJmenoKrestni.IsEnabled = false;
                    this.txtJmenoPrijmeni.IsEnabled = false;

                    this.Panel1.Visibility = Visibility.Hidden;
                    this.Panel2.Visibility = Visibility.Hidden;
                }
                
            }
            else
            {
                this.tlHomePage.Visibility = Visibility.Hidden;
                this.tlEmail.Visibility = Visibility.Hidden;
            }

        }

Pokud se teď budete pokoušet aplikaci zkompilovat, mělo by vám Visual Studio vyhodit 5 chyb, jejich důvod je nad slunce jasný :-). Máme totiž v KontaktStr1 pět tlačítek a u každého Click událost – při kliknutí na dané tlačítko se zavolá určitá metoda. A my ty metody zatím nemáme. U těchto metod není moc co řešit, snad jen u jedné. Tou je Hotovo_Klik(), která má za úkol sesbírat zadané informace z TextBoxů a předat je „return handleru“ (uděláme ho za chvíli).

private void Zrusit_Klik(object sender, RoutedEventArgs e)   
{   
    // zavře okno   
    ((NavigationWindow)(this.Parent)).Close();   
}   

private void Hotovo_Klik(object sender, RoutedEventArgs e)   
{   
    SeznamKontaktu sk = Application.Current.Properties["SeznamKontaktu"]   
                         as SeznamKontaktu;   
    Kontakt k = new Kontakt();   
    k.JmenoKrestni = this.txtJmenoKrestni.Text;   
    k.JmenoPrijmeni = this.txtJmenoPrijmeni.Text;   
    k.HomePage = new Uri(this.txtHomePage.Text);   
    k.Email = this.txtEmail.Text;   
    OnReturn(new ReturnEventArgs<object>(k));   
} 

Naším dalším krokem bude udělání výše zmíněného return handleru. Dává se do volající třídy, v našem případě tedy bude v souboru OknoBezOkna.xaml.cs. Ještě navíc přidáme instanciaci třídy KontaktStr1 v metodě Nacteno. Jak už jsem kdysi dávno řekl, typový argument Object třídy PageFunction, od které dědí OknoBezOkna, naznačuje jakého typu budou vrácená data. Kompletní soubor OknoBezOkna.xaml.cs by mohl vypadat takhle:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Navigation;

namespace Adresar
{
    public partial class OknoBezOkna : PageFunction<Object>
    {
        public OknoBezOkna()
        {
        }     
       
       // Handler "Nacteno" se zavola automaticky po vytvoření okna
        private void Nacteno(object sender, RoutedEventArgs e) 
        {
            // "Nacteno" nasměruje toto okno na dvě "přidávací" stránky
            KontaktStr1 pageFunction = 
                                  new KontaktStr1(true, 0); // pageFunction bude v módu úprav (mod_uprav==true)
            pageFunction.Return += 
                     new ReturnEventHandler<object>(pageFunction1_VratitHodnoty);
            NavigationService.GetNavigationService(this).
                                           Navigate(pageFunction);
        }

       // Return handler pro KontaktStr1
        void pageFunction1_VratitHodnoty(object sender, ReturnEventArgs<object> e)
        {
            SeznamKontaktu sk = 
                Application.Current.Properties["SeznamKontaktu"] 
                               as SeznamKontaktu;
            Kontakt k = e.Result as Kontakt; //nastaví to, co dostane (Result), jako Kontakt
            // nakonec to nejdůležitější - přidání kontaktu do seznamu
            sk.Add(k);
        }
    }
}

Pomocí známého Loaded teď už jen přidáme do XAML části OknaBezOkna event handler Nacteno:

<PageFunction
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    x:Class="Adresar.OknoBezOkna"
    x:TypeArguments="sys:Object"
    Loaded="Nacteno"
    Title="OknoBezOkna">
</PageFunction>

Když budeme mít informace o kontaktu v módu Čtení, budeme chtít, aby e-mail a WWW adresa vypadaly jako tlačítka. Kliknutí na e-mail bude mít za následek otevření výchozího e-mail klienta, WWW adresa neotevře prohlížeč, jak byste asi čekali, ale vykreslí stránku do pravé části hlavního okna (kde budou i zmíněné detaily o kontaktu, pomocí navigačních šipek se ale budete moci mezi „prohlížečem“ a detaily přesunovat). V obou případech ale uděláme URI a pak na něj odlišným způsobem odkážeme. Následující kód přidáme do KontaktStr1.xaml.cs.

private void Jdi_WWW(object sender, RoutedEventArgs e)   
{   
    if (this.txtHomePage != null) // Pokud v TextBoxu něco je...   
    {   
        NavigationService ns =   
                NavigationService.GetNavigationService(this);   
        // bude navigovat na zadaný odkaz, pokud bude   
        // ve tvaru http://, inteligentní WPF vytvoří "prohlížeč",   
        // ve kterém otevře zadaný odkaz   
        ns.Navigate(new Uri(this.txtHomePage.Text));    
    }   
}   

private void PoslatEmail(object sender, RoutedEventArgs e)   
{   
    if (this.txtEmail != null)   
    {   
        NavigationService ns =   
                    NavigationService.GetNavigationService(this);   
        ns.Navigate(new Uri("mailto:" + this.txtEmail.Text));   
    }   
} 

Tak jako jsme udělali KontaktStr1, teď uděláme KontaktStr2, bude obsahovat pouze dva TextBoxy na domovní a pracovní adresu a tlačítka Zpět, Zrušit, Hotovo.

<PageFunction
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    x:Class="Adresar.KontaktStr2"
    x:TypeArguments="sys:Object"
    Title="Nový kontakt - 2">

    <Grid
       Name="HlavniMrizka" 
      VerticalAlignment="Center"
      HorizontalAlignment="Center" >

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="110"/>
            <RowDefinition Height="110"/>
            <RowDefinition Height="60"/>
        </Grid.RowDefinitions>

        <!-- Popisky -->
        <TextBlock Width="100" Height="30" Grid.Column="0" Grid.Row="1" 
                   Text="Adresa do práce" />
        <TextBlock Width="100" Height="30" Grid.Column="0" Grid.Row="2" 
                   Text="Adresa domů" />

        <!-- Vstupní pole -->
        <TextBox Name="txtAdresaDomu" Width="200" Height="100" 
                 Grid.Column="1" Grid.Row="1" TextWrapping="Wrap"
                 Text="{Binding Path=AdresaDomu, Mode=TwoWay}"/>
        <TextBox Name="txtAdresaZamestnani" Width="200" Height="100" 
                 Grid.Column="1" Grid.Row="2" TextWrapping="Wrap"
                 Text="{Binding Path=AdresaZamestnani, Mode=TwoWay}"/>

        <DockPanel Name="Panel1" Grid.Column="0" Grid.Row="3" >
            <Button Name="tlZpet" Width="100" Height="30" 
                    Click="Zpet_Klik" Content="Zpět" />
            <Button Name="tlZrusit" Width="100" Height="30" 
                    Click="Zrusit_Klik" Content="Zrušit" />
        </DockPanel>
        <DockPanel Name="Panel2" Grid.Column="1" Grid.Row="3">
            <Button Name="tlHotovo" Width="100" Height="30" 
                    Click="Hotovo_Klik" Content="Hotovo" />
        </DockPanel>

    </Grid>
</PageFunction>

Kromě TextWrapping není v tomto kódu nic, co bychom už neznali. TextWrapping je jednoduše zalamování textu, pokud je nastaven na „Wrap“, text se zalamuje, pokud není nastaven, nebo je nastaven na „NoWrap“, nezalamuje se. Logická část tohoto souboru je vážně snadná, však se podívejte sami.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Adresar
{
    public partial class KontaktStr2 : PageFunction<Object>
    {
        public KontaktStr2()
        {
            InitializeComponent();
        }

               
        
        // Vytvoří KontaktStr2, podle zadaného módu, protože
        // ho nebudeme zobrazovat na hlavním okně, jako je tomu u první stránky,
        // druhý konstruktor nepřijímá jako parametr index kontaktu v seznamu
        public KontaktStr2(bool mod_uprav)
        {

            InitializeComponent();

            if (mod_uprav == false)
            {
                SeznamKontaktu sk =
                           Application.Current.Properties["SeznamKontaktu"]
                                       as SeznamKontaktu;
                Kontakt k = sk[0];
                this.HlavniMrizka.DataContext = k;

                this.HlavniMrizka.IsEnabled = false;
                this.Panel1.Visibility = Visibility.Hidden;
                this.Panel2.Visibility = Visibility.Hidden;
            }
        }

        
        // Vrátí uživatele na KontaktStr1
        private void Zpet_Klik(object sender, RoutedEventArgs e)
        {
            NavigationService ns =
                         NavigationService.GetNavigationService(this);
            ns.GoBack();

        }

        // Zavře okno
        private void Zrusit_Klik(object sender, RoutedEventArgs e)
        {
            ((NavigationWindow)(this.Parent)).Close();

        }

        
        // Když uživatel klikne na tlačítko Hotovo, program si vezme
        // zadaná data a vrátí je volajícímu - KontaktStr1. Toto
        // okno pak vezme i svoje data a všechno dohromady předá OknuBezOkna
        private void Hotovo_Klik(object sender, RoutedEventArgs e)
        {
            Kontakt k = new Kontakt();
            k.AdresaDomu = this.txtAdresaDomu.Text;
            k.AdresaZamestnani = this.txtAdresaZamestnani.Text;
            OnReturn(new ReturnEventArgs<object>(k));
            // zavře přidávač
            Window w = Application.Current.Properties["SpustitPruvodcePridani"]
                            as Window;
            w.Close();
        }
    }
}

Teď tedy už máme kompletně hotovou druhou stránku přidávače, už se k ní nebudeme vracet. Musíme ji spojit dohromady s první stránkou, ale o to se už postará ona. Nejdřív do ní přidáme metodu Dalsi_Klik, která slouží k přesunu na druhou stránku, a v zápětí i return handler.

// Když uživatel klikne na tlačítko Další, tato metoda   
// ho přesune na druhou stránku   
private void Dalsi_Klik(object sender, RoutedEventArgs e)   
{   

    NavigationService ns =   
                 NavigationService.GetNavigationService(this);   
    KontaktStr2 pageFunction = new KontaktStr2();   
    pageFunction.Return += new   
                 ReturnEventHandler<Object>(pageFunction2_VratitHodnoty);   
    ns.Navigate(pageFunction);   
}   

    
// Když druhá stránka pošle svoje data, tato   
// metoda je přidá k datům z první stránky. Nakonec všechno dohromady   
// pošle OknuBezOkna.   
void pageFunction2_VratitHodnoty(object sender, ReturnEventArgs<object> e)   
{   
    Kontakt k = e.Result as Kontakt;   
    k.JmenoKrestni = this.txtJmenoKrestni.Text;   
    k.JmenoPrijmeni = this.txtJmenoPrijmeni.Text;   
    k.HomePage = new Uri(this.txtHomePage.Text);   
    k.Email = this.txtEmail.Text;   
    OnReturn(new ReturnEventArgs<object>(k));   
} 

Stiskněte F5, klikněte někde na „Přidat kontakt“ a můžete se kochat. Součástí tohoto seriálu budou už pouze dvě věci, vše ostatní si už můžete dodělat sami, protože zbytek je už jen a jen C#.

Pamatujete, jak jsme si kdysi dávno předpřipravili metodu JeZvolenyKontakt() v souboru Window1.xaml.cs? Doděláme ji až teď, protože teprve nyní bude mít nějaký smysl. Když uživatel zvolí v ListBoxu vlevo nějaký kontakt, v pravé části okna se objeví detaily o něm. A tohle je docela zajímavá část, my totiž do té pravé části umístíme vlastně první okno přidávače v módu pro čtení (proto jsme dva módy vůbec definovali), který má nastavená tlačítka na Hidden (skryté). Takhle tedy metoda JeZvolenyKontakt() vypadá.

public void JeZvolenyKontakt(object sender, SelectionChangedEventArgs args)   
{   
    // zobrazí KontaktStr1 v pravé části hlavního okna, v módu pro Čtení   
    KontaktStr1 pageFunction =   
          new KontaktStr1(false, vsechnyKontakty.SelectedIndex);   
    pageFunction.Return += new   
           System.Windows.Navigation.ReturnEventHandler<object>   
                    (pageFunction0_VratitHodnoty);   
    this.Frame_Zbytek.Navigate(pageFunction);   

    // nastaví status lištu   
    SeznamKontaktu sk =   
          Application.Current.Properties["SeznamKontaktu"]   
                      as SeznamKontaktu;   
    Kontakt k = sk[vsechnyKontakty.SelectedIndex];   
    this.tb.Text = k.JmenoKrestni + " " + k.JmenoPrijmeni;   
} 

Zase jsem použil věc, kterou nemáme ještě definovanou. Je jí pageFunction0_VratitHodnoty(), která bude prázdná, protože KontaktStr1 bude zobrazeno v módu pro čtení, kde se neočekává, že metoda bude někdy něco vracet.

// Return handler pro KontaktStr1, je prázdný, protože není co vracet,   
// ale napsat ho musíme, protože je to povinný parametr   
void pageFunction0_VratitHodnoty(object sender,   
                 System.Windows.Navigation.ReturnEventArgs<object> e)   
{ 
} 

A máme hotovo. Zkuste si napsat fiktivní e-mail Ondrovi nebo otevřít jeho web. Ovšem pozor, pokud jste zadali nějakou nesmyslnou URL, jako jsem to udělal já, při kliknutí na tlačítko se vytvoří výjimka! Proto jsem adresu na doprovodném obrázku změnil na český Google. Další funkce, jako je ukládání seznamu kontaktů, dialogy pro import jinde uložených, editace kontaktů, propracovaný systém výjimek a další, jsou už jen na vás. My v tomto seriálu udělali to nejdůležitější – nakoukli jsme pod pokličku WPF a ukázali si některé zajímavé prvky.

Zdroj: http://windowsclient.net/downloads/folders/hands-on-labs/entry3719.aspx

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

3 názory  —  3 nové  
Hlasování bylo ukončeno    
0 hlasů
Google
Jakub studuje informatiku na FIT ČVUT, jeho oblíbenou platformou je .NET.
Web     Twitter     Facebook     LinkedIn    

Nové články

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý