Опубликован: 05.08.2010 | Уровень: специалист | Доступ: платный
Лекция 2:

Привязка WPF к таблице данных ADO.NET

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >

Некоторые дополнительные модификации привязки во вкладке Page2

С последним примером можно немного поэкспериментировать, перенеся привязку списка ListBox из кода в разметку.

  • Добавьте к разметке элемента ListBox вкладки Page2 в файле Window1.xaml следующую строку привязки
<ListBox 
                        Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                        Margin="0,0,0,3"
                        ScrollViewer.VerticalScrollBarVisibility="Auto"
                        Name="listEmployees2"
                        SelectionChanged="listEmployees2_SelectionChanged"
                        ItemsSource="{Binding}" DisplayMemberPath="FullName"
                        />
  • Модифицируйте в классе Window1 файла Window1.xaml.cs функцию Page2() следующим образом
private void Page2()
        {
            // Загружаем данные и назначаем источник привязки
            employees2 = App.StoreNorthwindDB.ReadTableEmployees();
            listEmployees2.SelectedIndex = 0;
            listEmployees2.Focus();
            gridEmployees2.DataContext = employees2[0];
            //listEmployees2.ItemsSource = employees2;
            //listEmployees2.DisplayMemberPath = "FullName";
    
            listEmployees2.DataContext = employees2;
        }

В представлении XAML элемента списка свойство ItemsSource мы задали для объекта Binding без указания атрибутов. Поскольку свойство Source объекта Binding не задано, WPF начнет искать источник в свойстве DataContext текущего элемента, а при неудаче - далее будет искать его в родительских элементах вверх по визуальному дереву в направлении его корня. В процедурном коде мы присваиваем свойству DataContext значение объекта-коллекции employees2, тем самым указываем источник связывания в самом элементе списка listEmployees2. Свойство DisplayMemberPath="FullName" списка определяет столбец коллекции-источника, который будет отображаться на экране. В нашем случае - это вычислимый столбец таблицы ADO.NET.

  • Запустите приложение и испытайте работу вкладки Page2 - ее функциональность осталась прежней

Можно пойти еще дальше в привязке на стороне разметки. Учитывая, что привязанные к элементу ListBox данные синхронно позиционирует свой внутренний курсор построчно в соответсвии с выделенным элементом SelectedItem списка, к этому элементу мы и привяжем свойство Grid.DataContext как к общему источнику данных для текстовых полей TextBox. Получится, что список (элемент управления элементами) привязан к коллекции, а элементы управления содержимым привязаны не к элементам коллекции, а к элементам списка.

  • Выполните в открывающем дескрипторе элемента Grid вкладки Page2 следующие изменения
Модификация сетки Grid вкладки Page2 файла Window1.xaml
Было
<Grid
                    Name="gridEmployees2"
                    >
Стало
<Grid
                    DataContext="{Binding ElementName=listEmployees2, Path=SelectedItem}"
                    >
  • Удалите, за ненадобностью, из дескриптора элемента ListBox подписку обработчика на событие SelectionChanged
Модификация элемента ListBox вкладки Page2 файла Window1.xaml
Было
<ListBox 
                        Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                        Margin="0,0,0,3"
                        ScrollViewer.VerticalScrollBarVisibility="Auto"
                        Name="listEmployees2"
                        SelectionChanged="listEmployees2_SelectionChanged"
                        ItemsSource="{Binding}" DisplayMemberPath="FullName"
                        />
Стало
<ListBox 
                        Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                        Margin="0,0,0,3"
                        ScrollViewer.VerticalScrollBarVisibility="Auto"
                        Name="listEmployees2"
                        ItemsSource="{Binding}" DisplayMemberPath="FullName"
                        />
  • Удалите полностью, за ненадобностью, из класса Window1 файла Window1.xaml обработчик listEmployees2_SelectionChanged() или закомментируйте содержимое его тела
  • Закомментируйте в функции Page2() файла Window1.xaml.cs строку кода присвоения свойству DataContext начального элемента коллекции данных
private void Page2()
        {
            // Загружаем данные и назначаем источник привязки
            employees2 = App.StoreNorthwindDB.ReadTableEmployees();
            listEmployees2.SelectedIndex = 0;
            listEmployees2.Focus();
            //gridEmployees2.DataContext = employees2[0];
            //listEmployees2.ItemsSource = employees2;
            //listEmployees2.DisplayMemberPath = "FullName";
    
            listEmployees2.DataContext = employees2;
        }
  • Запустите приложение и испытайте работу вкладки Page2 - она продолжает работать как ни в чем небывало

Что здесь получилось. Коллекцию Employees объектов Employee, которая инкапсулирует извлеченные из БД данные, мы оставили подключенной к DataContext списка ListBox и ее найдет свойство ItemsSource списка. А вот источником привязки для текстовых полей мы назначили свойство SelectedItem списка, которое ассоциируется с элементом коллекции, и разместили эту информацию в свойстве DataContext сетки Grid. Ее найдут привязанные текстовые поля. Фактически мы сделали то же самое, что выполнял ранее процедурный код в обработчике события SelectionChanged списка.

Вдоль дороги лес густой - с Бабами-Ягами!

А в конце дороги той - плаха с топорами!

(В.С. Высоцкий)

Вкладка Page3. Привязка к таблице Employees через объект DataTable инфраструктуры ADO.NET

Здесь побочной работы будет мало, поскольку у нас уже есть метод LoadTableEmployees() в классе StoreNorthwindDB, возвращающий заполненный объект DataTable. Только ранее мы его применяли в объекте-оболочке Employees1, а потом этот объект Employees1 использовали в классе Window1 файла Window1.xaml.cs. Теперь метод LoadTableEmployees() вызовем в классе Window1 и возвращенный им объект-коллекцию DataTable используем в привязке того же самого набора интерфейсных элементов WPF.

Есть одна тонкость в намерении применить уже готовый метод LoadTableEmployees(). Мы сгоряча в нем сделали проверку, чтобы объект DataTable создавался только один раз, из благих намерений - желая разгрузить наш компьютер. Но это значит, что к каким бы ссылкам мы этот метод не применяли, все они будут адресовать один и тот же физически существующий объект DataTable. Пока что это не страшно, поскольку извлеченные из таблицы БД данные мы только просматриваем, а не редактируем. И неважно, через какие замочные скважины (вкладки Pages) мы за этими данными будем подглядывать.

  • Создайте в файле Window1.xaml из копии вкладки Page2 (в ее последней версии после проведенных модификаций) новую вкладку Page3 и сделайте в ней необходимые переименования элементов
<!-- Привязка к таблице Employees через объект DataTable из ADO.NET -->
            <TabItem Header="Page3">
                <Grid
                    DataContext="{Binding ElementName=listEmployees3, Path=SelectedItem}"
                    >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    
                    <ListBox 
                        Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                        Margin="0,0,0,3"
                        ScrollViewer.VerticalScrollBarVisibility="Auto"
                        Name="listEmployees3"
                        ItemsSource="{Binding}" DisplayMemberPath="FullName"
                        />
                    
                    <TextBlock Grid.Row="1" Margin="0,0,5,0">EmployeeID:</TextBlock>
                    <TextBox Grid.Row="1" Grid.Column="1" 
                        Text="{Binding Path=EmployeeID, Mode=OneWay}"
                        Focusable="False"
                        />
                    
                    <TextBlock Grid.Row="2">FullName:</TextBlock>
                    <TextBox Grid.Row="2" Grid.Column="1" 
                        Text="{Binding Path=FullName, Mode=OneWay}"
                        Focusable="False"
                        />
                    
                    <TextBlock Grid.Row="3">Address:</TextBlock>
                    <TextBox Grid.Row="3" Grid.Column="1" 
                        Text="{Binding Path=Address, Mode=OneWay}"
                        Focusable="False"
                        />
                    
                    <TextBlock Grid.Row="4">BirthDate:</TextBlock>
                    <TextBox Grid.Row="4" Grid.Column="1" 
                        Text="{Binding Path=BirthDate, Mode=OneWay}"
                        Focusable="False"
                        />
                    
                    <TextBlock Grid.Row="5">Region:</TextBlock>
                    <TextBox Grid.Row="5" Grid.Column="1" 
                        Text="{Binding Path=Region, Mode=OneWay}"
                        Focusable="False"
                       />
                </Grid>
            </TabItem>
  • Добавьте в класс Window1 файла Window1.xaml.cs код присоединения коллекции DataTable к интерфейсным элементам вкладки Page3
#region Вкладка Page3
        private void Page3()
        {
            // Настраиваем списковый элемент ListBox
            listEmployees3.SelectedIndex = 0;
            listEmployees3.Focus();
    
            // Назначаем источником объект-коллекцию данных DataTable
            listEmployees3.DataContext = 
                App.StoreNorthwindDB.LoadTableEmployees();
        }
        #endregion

Опять для удобства мы применили секцию #region.

  • Поместите в обработчик Window_Loaded() класса Window1 вызов функции Page3() для инициализации списка listEmployees3 вкладки Page3
private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Page1();
            Page2();
            Page3();
        }
  • Запустите приложение и испытайте работу вкладки Page3 - получим точно такую же функциональность, что и для двух предыдущих вкладок

Разницы нет между чистою правдой и ложью,

Если вначале и ту и другую раздеть!

(В.С. Высоцкий)

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000