DataBinding (часть 2 - метод вынесения контрола)
В прошлом уроке, я показывал проблемы Data Binding и одно из решений, этой проблемы. Сегодня мы будем решать эту же задачу. Но совершенно другим способ. Зачем? Просто каждый способ имеет свои достоинства и недостатки. Поэтому иногда будет быстрей и удобней работать с одним методом, а иногда с другим. Тем более, когда у нас есть несколько решений - это говорит о гибкости языка и технологии.
И так, для начала советую прочесть предыдущую статью. Для тех, кто этого делать не хочет, все таки попрошу себя пересилить и прочитать ;)
А кто не помнит, что было в ней напоминаю. Решаем следующую задачу. Мы получается коллекцию классов, которую мы выводим в виде элементов. Затем надо сделать необходимые действия. В нашем примере мы выделяем один из элементов.
И так посмотрим, представление в XAML:
<Grid x:Name="LayoutRoot" Background="White">
<ItemsControl x:Name="FilmList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Magenta" Margin="0,5,0,5" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown" >
<Image Source="{Binding Image}" Width="30" Height="30" Margin="5" MouseLeftButtonDown="Image_MouseLeftButtonDown" />
<TextBlock Text="{Binding Title}" Margin="5" />
<TextBlock Text="{Binding Time}" Margin="5" />
<TextBlock Text="{Binding FileSize}" Margin="5" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Вынесем повторяющиеся элементы в отдельный контрол, назовем его Item. И так создайте новый UserControl и вынесем в него следующий код:
<UserControl x:Class="DataBindingExamples.Item" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600"> <StackPanel x:Name="LayoutRoot"> <!— НАШ ЭЛЕМЕНТ --> <StackPanel x:Name="ItemLayout" Orientation="Horizontal" Background="Magenta" Margin="0,5,0,5" MouseLeftButtonDown="ItemLayout_MouseLeftButtonDown"> <Image x:Name="FilmImage" Width="30" Height="30" Margin="5" /> <TextBlock x:Name="TextTitle" Margin="5" /> <TextBlock x:Name="TextTime" Margin="5" /> <TextBlock x:Name="TextFileSize" Margin="5" /> </StackPanel> <!— НАШ ЭЛЕМЕНТ --> </StackPanel> </UserControl>
Я убрал все бинд выражения, также изменилось событие MouseLeftButtonDown. Теперь этот элемент мы будем размножать, но нам как-то необходимо устанавливайте свойство наших внутренних элементов. Для этого воспользуемся конструктором и будем в него передавать наши параметры. Еще нам понадобиться событие, которое будет происходить при клике на этот элемент, и его мы в последствии будем вытаскивать наверх, чтобы знать, что данные элемент кликнут. Также мы создадим метод устанавливающий цвет заднего фона для удобства.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace DataBindingExamples
{
public partial class Item : UserControl
{
//событие клика на элемент
public event EventHandler ItemClick;
//храним текущий ID записи
public int CurrentId;
//Конструтор нашего Item
public Item( int id, string title, int time, string fileSize, string imageSource )
{
//Устанавливаем свойства внутренних контролов и инициализируем переменные
InitializeComponent();
ItemLayout.Tag = id;
TextTitle.Text = title;
TextTime.Text = time.ToString();
TextFileSize.Text = fileSize;
FilmImage.Source = new BitmapImage(new Uri(imageSource));
CurrentId = id;
}
//Метод меняет фон элемента
public void SetBackground(Color color)
{
ItemLayout.Background = new SolidColorBrush(color);
}
private void ItemLayout_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//вызваем наше событие клика на элемент
if (ItemClick != null)
ItemClick(this, new ItemEventArgs(Convert.ToInt32(((StackPanel)sender).Tag)));
}
}
//Создадим свой класс, чтобы передавать в параметрах ID кликнутого элемента
public class ItemEventArgs : EventArgs
{
public ItemEventArgs(int id)
{
ID = id;
}
public int ID { get; set; }
}
}
И так элемент, готов он умеет делать все, что нам надо и теперь его можно использовать.
Создадим на нашей странице StackPanel в коллекцию, которого мы добавим наши Item.
XAML:
<UserControl x:Class="DataBindingExamples.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="800"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel x:Name="FilmsItems" /> </Grid> </UserControl>
Теперь нам необходимо, получить коллекцию классов от нашего вебсервиса, потом пробежать по ней получить коллекцию Item. И ее в свою очередь добавить в коллекцию FilmsItems.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DataBindingExamples.WebSrv;
namespace DataBindingExamples
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
//получаем нашу коллекцию фильмов
var connector = new MyWebServiceSoapClient();
connector.GetFimlsCompleted += connector_GetFimlsCompleted;
connector.GetFimlsAsync();
}
void connector_GetFimlsCompleted(object sender, GetFimlsCompletedEventArgs e)
{
if (e.Error != null)
return;
if (e.Result.Count > 0)
{
List list = new List(e.Result);
//Создаем наши Item и добавляем в коллекцию FilmsItems
foreach (Film current in list)
{
Item item = new Item(current.Id, current.Title, current.Time, current.FileSize, current.Image);
//Подписываем на событие
item.ItemClick += item_ItemClick;
FilmsItems.Children.Add(item);
}
}
}
void item_ItemClick(object sender, ItemEventArgs e)
{
//бежим по коллекции StackPanel (FilmsItems)
foreach (UIElement current in FilmsItems.Children)
{
//Выделяем текцщий элемент
if (Convert.ToInt32(((Item)current).CurrentId) == e.ID)
{
((Item)current).SetBackground(Colors.Red);
}
else
{
((Item)current).SetBackground(Colors.Magenta);
}
}
}
}
}
И так проверяем, как видим наш элементы правильно отрабатывают, на события клика, и мы можем получать доступ к любым свойствам любых контролов нашего Item. Изменив, идентификатор доступа, либо добавив новый метод.
Удобно или нет, решать вам.
Этот способ дает нам намного больше гибкости и свободы, и не дает никаких ограничений.
Но в тоже время значительно трудоемок, и требует написания большего количества, двух отдельных контролов. Хотя если контрол используется во многих местах, вам все равно лучше его вынести.
Я надеюсь, эта статья помогла вам, более глубже, окунуться в DataBinding и пути решения проблем при работе с ним. Жду ваших вопросов.
Popularity: 91% [?]



Декабрь 11th, 2008 at 15:00
[...] DataBinding (часть 2 - метод вынесения контрола) Posted дек 08 2008, 08:50 by СильверРобот Помечено как: Блог, [...]
Декабрь 15th, 2008 at 02:52
Привет!
Почему не используете подсветку для кода??
Материал хороший, но не читабельный :(
Декабрь 15th, 2008 at 04:07
так будет удобней??