WPF – Data-Template Selector

10 בAugust 2013

תגיות: , , ,
2 תגובות
DateTemplate הוא אחד החלקים היעילים שיש לWPF להציע ורובינו לא מודעים ליכולות שאפשר לקבל ממנו.
Data template Selector זאת דוגמא לחוסר מודעות. בואו נראה דוגמא.
יש לנו אובייקט Person ויש לו 3 פרופרטיז , שם, מין, ומספר זיהוי. איך יוצג כל אלמנט כזה בתוך רשימה של Persons ? בוא נניח שיש לי קוד בסיסי שנראה כך :
public enum Gender

    {

        male, 

        female

    }

 

    public class Person

    {

        public int ID { get; set; }

        public string  Name { get; set; }

        public Gender PersonGender { get; set; }

 

        public Person(int _id, string __name , Gender _gender)

        {

            Name = __name;

            ID = _id;

            PersonGender = _gender;

        }

    }

 

    public partial class MainWindow : Window

    {

 

        public MainWindow()

        {

            InitializeComponent();

 

            List<Person> persons = new List<Person>();

            persons.Add(new Person(123,"Tom",Gender.male));

            persons.Add(new Person(456,"Jack",Gender.female));

            persons.Add(new Person(789,"Ron",Gender.male));

            listBox.ItemsSource = persons;

        }

    }      

הדרך הראשונה תהיה לראות משהו כזה:
 
image
 
הדרך שניה שתסביר לנו למה הראשונה נראית כך תהיה לממש Tostring ואז נראה בהתאם למימוש את הערך כי זה מה שעושה ListBox כברירת מחדל אז נעשה דבר כזה:
 
 
 
public override string ToString()

        {

            return string.Format( "{0} {1} {2}  ", Name , ID , PersonGender );

        }                         

עכשיו נקבל משהו יותר ברור.
 
image
מה הלאה במקרה שלא נממש ToString ?
שתי אופציות , הראשונה לפנות ל DisplayMemberPath של ListBox ולא כ”כ רלוונטי בד”כ והאופציה השניה להגדיר DataTemplate שזה יעבוד נפלא.
 
איך מגדירים DataTemplate? עושים משהו כזה פחות או יותר ברמת הXaml.
<Window x:Class="WPFTemplateSelector.MainWindow"

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

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

        xmlns:local="clr-namespace:WPFTemplateSelector"

        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <DataTemplate DataType="{x:Type local:Person}" x:Key="personTemplate">

            <Border BorderBrush="Red" BorderThickness="1" CornerRadius="1" Margin="2">

                <StackPanel Orientation="Horizontal" >

                <TextBlock Text="{Binding ID}" Margin="2"/>

                <TextBlock Text="{Binding Name}" Margin="2"/>

                <TextBlock Text="{Binding PersonGender}" Margin="2"/>

            </StackPanel>

            </Border>

        </DataTemplate>

    </Window.Resources>

    

    <Grid>

        <ListBox Name="listBox"  Margin="100" 

                 ItemTemplate="{StaticResource ResourceKey=personTemplate}"/>

    </Grid>

</Window>

 
עכשיו נקבל תוצאה כזאת שהיא הרבה יותר הגיונית, כי הView אחראי למבנה של של עצמו.
 
image
אוקיי, ולדרישה הבאה:
אנו רוצים שני Templates אחד עבור הצגת אנשים ממין זכר והשני עבור הצגת אנשים ממין נקבה.
אז ברור שאני יכול להעתיק את הDataTemplate שהגדרנו קודם ולתת להם מזהה יחודי דרך Key כמו גם לשנות את צבע הBorder שהם מציגים, רק הבעיה איך נקרא לTemplate המתאים?
 
כאן נכנס השימוש ב Template Selector. דבר ראשון נשכפל את הTemplates שלנו וניתן להם מפתח מתאים. והבדל בסיסי בצבע הבורדר:
 
<Window.Resources>

        <DataTemplate DataType="{x:Type local:Person}" x:Key="personGirlTemplate">

            <Border BorderBrush="Blue" BorderThickness="1" CornerRadius="1" Margin="2">

                <StackPanel Orientation="Horizontal" >

                <TextBlock Text="{Binding ID}" Margin="2"/>

                <TextBlock Text="{Binding Name}" Margin="2"/>

                <TextBlock Text="{Binding PersonGender}" Margin="2"/>

            </StackPanel>

            </Border>

        </DataTemplate>

        <DataTemplate DataType="{x:Type local:Person}" x:Key="personBoyTemplate">

            <Border BorderBrush="Pink" BorderThickness="1" CornerRadius="1" Margin="2">

                <StackPanel Orientation="Horizontal" >

                    <TextBlock Text="{Binding ID}" Margin="2"/>

                    <TextBlock Text="{Binding Name}" Margin="2"/>

                    <TextBlock Text="{Binding PersonGender}" Margin="2"/>

                </StackPanel>

            </Border>

        </DataTemplate>

                                                            </Window.Resources>    

 

עכשיו למנה העיקרית, נממש את הקוד הבא פחות או יותר,
 
namespace WPFTemplateSelector

{

  public  class PersonTemplateSelector : DataTemplateSelector

        

    {

        public override DataTemplate SelectTemplate(object item, DependencyObject container)

        {

            ContentPresenter presenter = (ContentPresenter)container;

            Person pers = item as Person;

            if (pers.PersonGender == Gender.male)

            {

                return (DataTemplate)presenter.FindResource("personGirlTemplate");

            }

 

            else

            {

                return (DataTemplate)presenter.FindResource("personBoyTemplate");

            }

        }

    }

}

 
מהקוד הזה ניתן להסיק איך עובד dataTemplate לפני שהתערבנו בו,
ועכשיו אנו פשוט עושים Override לפונקציה SelectTemplate שזה פשוט מאוד.
 
ניתן פה לממש כל מיני צורות של לוגיקה. כל שנשאר זה לקרוא לקוד הזה בListBox שלנו. וזה יהיה כך:
 
<ListBox Name="listBox"  Margin="100"  >

            <ListBox.ItemTemplateSelector>

                <local:PersonTemplateSelector/>

            </ListBox.ItemTemplateSelector>

                                                                     </ListBox>

 

התוצאה תראה עכשיו כך:
 
image
הוסף תגובה
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

2 תגובות

  1. מוטי אברמוב11 בAugust 2013 ב 1:57

    נהדר ! עכשיו יש לי רעיון לבעיה שלי .

    Reply
  2. Pingback: Few rules about how to decorate an Items Control in WPF | Until The Next Exception