מדריך Windows Phone – שימוש ב Data Binding: חיבור ל Collection
עד כה ראינו כיצד לחבר בין פקד אחד לפריט מידע אחד. בפרק זה נראה כיצד נוכל לחבר בין פקד שיודע להציג רשימות כמו ListBox לבין רשימה של אובייקטים.
התכונה ItemsSource
התכונה ItemsSource משותפת לכל הפקדים שמסוגלים להתחבר לרשימה של אובייקטים. תכונה זו מקבלת את אובייקט הרשימה, ישירות או ע"י שימוש ב Binding. לאחר מכן, הפקד שבשימוש יוצר אלמנט גרפי עבור כל איבר ברשימה.
לדוגמא, נראה חיבור של ListBox לרשימה של אובייקטים.
ראשית נוסיף מחלקה חדשה בשם MyData שתייצג ישות מידע בודדת ברשימה:
namespace PhoneDemo
{
public class MyData
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsLecturer { get; set; }
}
}
כעת ניצור פקד שיודע להציג רשימות, ונחבר אותו לרשימה שניצור ב code-behind. בנוסף נוסיף כפתור שתפקידו יהיה להוסיף איבר חדש לרשימה:
<phone:PhoneApplicationPage
x:Class="PhoneDemo.MainPage"
>="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
>:x="http://schemas.microsoft.com/winfx/2006/xaml"
>:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
>:d="http://schemas.microsoft.com/expression/blend/2008"
>:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
>:local="clr-namespace:PhoneDemo"
mc:Ignorable="d"
d:DesignWidth="480"
d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
Orientation="Portrait"
SupportedOrientations="Portrait">
<StackPanel>
<ListBox
ItemsSource="{Binding}" />
<Button
Content="Add"
Click="Button_Click" />
</StackPanel>
</phone:PhoneApplicationPage>
נשים לב לשימוש המיוחד ב Binding ללא פרמטרים. מאחר ואין מקור מפורש (ElementName, Source, RelativeSource) אזי ברירת המחדל תהיה לחפש את מקור הנתונים ב DataContext של האובייקט ListBox. בנוסף לא הוגדר Path לכן במקום להתחבר תכונה מסוימת של אובייקט המקור, החיבור יהיה לכל האובייקט.
ההצבה של אובייקט ל DataContext נעשית בקוד #C באופן הבא:
using System.Collections.Generic;
using System.Windows;
using Microsoft.Phone.Controls;
namespace PhoneDemo
{
public partial class MainPage : PhoneApplicationPage
{
private List<MyData> _myCollection = new List<MyData>();
// Constructor
public MainPage()
{
InitializeComponent();
DataContext = _myCollection;
_myCollection.Add(
new MyData
{
FirstName = "Arik",
LastName = "Poznanski",
IsLecturer = true
});
_myCollection.Add(
new MyData
{
FirstName = "John",
LastName = "Smith",
IsLecturer = false
});
}
private int counter = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
++counter;
_myCollection.Add(
new MyData()
{
FirstName = "item " + counter,
LastName = "item " + counter,
IsLecturer = counter % 3 == 0
});
}
}
}
הרצה של תוכנית זו תציג את הפלט הבא:
הבעיה הראשונה שעולה מקוד זה היא שהאלמנטים מטיפוס MyData לא מוצגים בצורה טובה. מאחר והמחלקה MyData איננה אלמנט גרפי, מנגנון הציור של Silverlight קורא לפונקציה ToString של האובייקט ומציג את התוצאה בתוך TextBlock. נראה בהמשך המדריך כיצד לשפר משמעותית את ההצגה הגרפית של אובייקטים מטיפוס MyData. בינתיים נסתפר בהעמסה של האופרטור ToString של MyData:
public override string ToString()
{
return string.Format("First name: {0}, Last name: {1}, Is lecturer: {2}",
FirstName, LastName, IsLecturer);
}
כעת התוצאה נראית כך:
הבעיה השנייה נגלית רק כאשר לוחצים על כפתור Add ומגלים ששום דבר לא קורה. כלומר, הפונקציה אכן נקראת ומוסיפה איבר לרשימה, אבל ה ListBox לא מתעדכן עם המידע החדש!
הבעיה דומה לבעיה שכבר נתקלנו בה בפרק קודם. ה ListBox אינו יודע שה Collection שאליו אנו מחוברים השתנה ולכן אינו יודע ליצור אלמנט חדש עבור האיבר החדש שהצטרך לרשימה. הפתרון לבעיה זו הוא שה Collection שאיתו אנו עובדים יממש ממשק בשם INotifyCollectionChange. שימו לב, זהו לא אותו ממשק כמו שהיה מקודם INotifyPropertyChanged. המטרה פה היא לדווח על שינויים ב Collection ולא בתכונה כזו או אחרת.
שינוי Collection בצורה דינמית
כדי לגרום לכך ששינויים ב Collection שאליו אנו מחוברים יגיעו לפקד הרשימה יש לדאוג שה Collection יממש את הממשק INotifyCollectionChange. למזלנו, לא צריך לממש מחלקות של רשימות משלנו. מיקרוסופט מספקת לנו מימוש כזה בצורת המחלקה הגנרית: ObservableCollection. מחלקה זו מממשת כבר את הממשק הנ"ל ומדווחת על שינויים. כל שנותר לעשות הוא להשתמש במחלקה הזו במקום השימוש שלנו במחלקה הגנרית List.
להלן הקוד המתוקן:
using System.Collections.ObjectModel;
using System.Windows;
using Microsoft.Phone.Controls;
namespace PhoneDemo
{
public partial class MainPage : PhoneApplicationPage
{
private ObservableCollection<MyData> _myCollection = new ObservableCollection<MyData>();
// Constructor
public MainPage()
{
InitializeComponent();
DataContext = _myCollection;
_myCollection.Add(
new MyData
{
FirstName = "Arik",
LastName = "Poznanski",
IsLecturer = true
});
_myCollection.Add(
new MyData
{
FirstName = "John",
LastName = "Smith",
IsLecturer = false
});
}
private int counter = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
++counter;
_myCollection.Add(
new MyData()
{
FirstName = "item " + counter,
LastName = "item " + counter,
IsLecturer = counter % 3 == 0
});
}
}
}
כעת לחיצה על כפתור Add עובדת והתוצאה לאחר מספר לחיצות היא:
תגובות בפייסבוק