Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2009 / 47 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Лекция 2:

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

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

Вкладка Page1. Привязка к таблице Employees через пользовательский объект

Теперь нам нужно создать промежуточный класс, который бы инкапсулировал поля загруженного данными объекта DataTable в общедоступные свойства. К общедоступным свойствам мы будем привязывать интерфейсные элементы пока для просмотра данных. Именно, только для общедоступных свойств привязка к пользовательскому классу будет работать. Вспомогательный класс разместим в отдельном файле.

  • В панели Solution Explorer для узла проекта DataBindingTable вызовите контекстное меню и командой Add/Class создайте файл Employees1.cs

  • Заполните файл Employees1.cs так
using System;
using System.Collections.Generic;
using System.Text;
    
// Подключение пространства имен для DataTable
using System.Data;
    
namespace DataBindingTable
{
    // Класс свойств доступа к данным таблицы Employees
    class Employees1
    {
        //********************************************************
        // Cвойства доступа для привязки и базовые поля  
        //********************************************************
        // Для списка надо массив
        string[] listFullName = null;
        public string[] ListFullName
        {
            get
            {
                if (listFullName == null)
                {
                    listFullName = new string[dt.Rows.Count];
                    int i = 0;
                    // Перебираем записи и заполняем массив для списка
                    foreach (DataRow row in dt.Rows)
                    {
                        listFullName[i] = (string)dt.Rows[i]["FullName"];
                        i++;
                    }
                }
                return listFullName;
            }
        }
        int employeeID;
        public int EmployeeID
        {
            get { return employeeID; }
        }
        string fullName;
        public string FullName
        {
            get { return fullName; }
        }
        string address;
        public string Address
        {
            get { return address; }
        }
        string birthDate;
        public string BirthDate
        {
            get { return birthDate; }
        }
        string region;
        public string Region
        {
            get { return region; }
        }
    
        // Навигация по таблице ADO.NET
        public Employees1 GetEmployee(int ID)
        {
            // Проверяем границы массива
            if (ID < 0 || ID >= dt.Rows.Count)
                return null;
    
            // Наполняем свойства полями записи ID
            // для последующего их извлечения свойствами
            // в привязанные элементы интерфейса.
            // Входные параметры приводятся явно 
            // к тому типу, который ожидает метод
            return new Employees1(
                (int)dt.Rows[ID]["EmployeeID"],
                (string)dt.Rows[ID]["FullName"],
                (string)dt.Rows[ID]["Address"],
                dt.Rows[ID]["BirthDate"].ToString(),
                dt.Rows[ID]["Region"].ToString()
                );
        }
    
        // Конструктор с параметрами
        public Employees1(int employeeID,
            string fullName, string address,
            string birthDate, string region)
        {
            this.employeeID = employeeID;
            this.fullName = fullName;
            this.address = address;
            this.birthDate = birthDate;
            this.region = region;
        }
    
        // Конструктор по умолчанию 
        public Employees1() { }
    
        // Ссылка на исходную таблицу-объект ADO.NET
        DataTable dt = App.StoreNorthwindDB.LoadTableEmployees();
    }
}

Обратите внимание, что в классе Employees1 мы предусмотрели свойства доступа только с аксессором get, значит инкапсулированные данные пока можно будет только просматривать и тип привязки интерфейсных элементов-приемников должен быть только OneWay. Позже мы применим и двухстороннюю (двунаправленную) привязку, когда данные можно будет еще и редактировать.

  • Добавьте к разметке файла Window1.xaml контейнер TabControl с вкладкой Page1, чтобы файл стал таким
<Window x:Class="DataBindingTable.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300"
    Title="Привязка элементов к БД" 
    MinHeight="300" 
    MinWidth="300"
    WindowStartupLocation="CenterScreen" 
    Loaded="Window_Loaded"
    >
    <Window.Resources>
        <SolidColorBrush x:Key="ControlColorBrush" 
            Color="{x:Static SystemColors.ControlColor}" />
    </Window.Resources>
    <Grid Background="{StaticResource ResourceKey=ControlColorBrush}">
        <TabControl>
            <!-- Привязка к таблице Employees через объект -->
            <TabItem Header="Page1">
                <Grid 
                    Name="gridEmployees1"
                    >
                    <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="listEmployees1"
                        SelectionChanged="listEmployeeslab72_SelectionChanged"
                        />
                    
                    <TextBlock Grid.Row="1" Margin="0,0,5,0">EmployeeID:</TextBlock>
                    <TextBox Grid.Row="1" Grid.Column="1" 
                        Text="{Binding Path=EmployeeID, Mode=OneWay}"
                        />
    
                    <TextBlock Grid.Row="2">FullName:</TextBlock>
                    <TextBox Grid.Row="2" Grid.Column="1" 
                        Text="{Binding Path=FullName, Mode=OneWay}"
                        />
    
                    <TextBlock Grid.Row="3"></TextBlock>
                    <TextBox Grid.Row="3" Grid.Column="1" 
                        Text="{Binding Path=Address, Mode=OneWay}"
                        />
    
                    <TextBlock Grid.Row="4">BirthDate:</TextBlock>
                    <TextBox Grid.Row="4" Grid.Column="1" 
                        Text="{Binding Path=BirthDate, Mode=OneWay}"
                        />
    
                    <TextBlock Grid.Row="5">Region:</TextBlock>
                    <TextBox Grid.Row="5" Grid.Column="1" 
                        Text="{Binding Path=Region, Mode=OneWay}"
                        />
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Для отображения данных пользователю мы применили интерфейсные элементы TextBox так будет 'красивше'. Мы явно установили для них тип привязки OneWay, чтобы не было разногласий со свойствами доступа промежуточного объекта Employees1. Свойства оболочки Employees1 у нас работают только для чтения, а элементы TextBox по умолчанию имеют двунаправленный тип привязки TwoWay. Но для отображения данных в привязке можно было бы использовать и элементы TextBlock, тогда тип привязки OneWay указывать было бы необязательно, поскольку у TextBlock иной привязки и не существует - они могут только отображать содержимое.

  • В файле Window1.xaml вызовите контекстное меню для записей событий Loaded окна и SelectionChanged списка, чтобы создать обработчики командой Navigate to Event Handler
  • Заполните созданные в файле Window1.xaml.cs обработчики так
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
    
namespace DataBindingTable
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Page1();
        }
    
        #region Вкладка Page1
        Employees1 employees1;
        private void Page1()
        {
            // Загружаем данные и настраиваем источник привязки
            employees1 = new Employees1();
            listEmployees1.SelectedIndex = 0;
            listEmployees1.Focus();
            gridEmployees1.DataContext = employees1.GetEmployee(0);
            listEmployees1.ItemsSource = employees1.ListFullName;
            listEmployees1.DisplayMemberPath = employees1.FullName;
        }
    
        private void listEmployeeslab72_SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            gridEmployees1.DataContext = 
                employees1.GetEmployee(listEmployees1.SelectedIndex);
        }
        #endregion
    }
}

Приведенный код мы упаковали в секцию #region для удобства, чтобы как-то структурировать код отдельных вкладок на тот случай, если их количество станет большим в процессе выполнения упражнения.

  • Запустите приложение - должен получиться такой результат

При выборе элемента списка текстовые поля заполняются новыми значениями привязанных свойств объекта Employees1. Здесь есть один недостаток: при прямом редактировании текстовых полей значения в них перестают меняться - срабатывает внутренний механизм элемента TextBox. На данном этапе этот недостаток можно устранить, если просто запретить пользователю их редактировать, что согласуется с принятой нами концепцией только отображения данных.

  • Добавьте в дескрипторы элементов TextBox атрибут Focusable="False" следующим образом
<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"
                       /<
  • Запустите приложение, испытайте работу вкладки Page1, разберитесь с кодом

Выполним еще одно незначительное действие: поместим уже созданные файлы с процедурным кодом в отдельный каталог.

  • В панели Solution Explorer вызовите контекстное меню для корневого узла DataBindingTable проекта и командой Add/New Folder добавьте папку с именем Code
  • В панели Solution Explorer, удерживая клавишу Ctrl, выделите в корне проекта файлы StoreNorthwindDB.cs и Employees1.cs, затем перетащите их мышью в папку Code
  • Запустите приложение - все продолжает нормально работать, компилятор находит перемещенные файлы
< Лекция 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" или один из зависимых от них компонентов. Не удается найти указанный файл.

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