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

Работа с потоками данных

< Лекция 5 || Лекция 6: 12345678910111213

Пример 5. Совместное применение файловой библиотеки рисунков и базы данных

Для отображения упакованных в предыдущем примере рисунков применим отдельное окно WPF, подобное Window3.xaml, но отличающееся процедурной частью.

  • Закройте все текущие файлы командой Window/Close All Documents
  • В панели проводнике решений Solution Explorer вызовите контекстное меню для файла Window3.xaml и выполните команду Copy
  • Там же, вызовите контекстное меню для узла App7 самого проекта и выполните команду Paste
  • Там же, командой Rename переименуйте копию Copy of Window3.xaml в Window5.xaml
  • Откройте файл Window5.xaml, замените в нем заголовок окна и индекс 3 на 5, чтобы разметка стала такой
<Window x:Class="App7.Window5"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Использование БД + файловой библиотеки" 
    Height="300"
    Width="470"
    MinHeight="300"
    MinWidth="450" 
    Name="_Window5" 
    Closing="Window_Closing"
    >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <Border Background="Black">
            <Image Name="image" Stretch="Uniform" />
        </Border>
        <ListBox Name="listBox" Grid.Column="1" Padding="5,0"
                 ScrollViewer.VerticalScrollBarVisibility="Visible"
                 SelectionChanged="listBox_SelectionChanged">
        </ListBox>
    </Grid>
</Window>
  • Удалите из файла Window5.xaml.cs ненужный пока процедурный код и добавьте в начало подключение пространств имен ADO.NET, чтобы осталась следующая заготовка, которую мы дальше и будем наполнять
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.Shapes;
    
// Дополнительные пространства имен
using FORMS = System.Windows.Forms; // Псевдоним
using System.IO;
using System.Configuration;         // Для SettingsProperty
using IO = System.IO;               // Псевдоним для адресации Path
    
// Дополнительные пространства имен для ADO.NET
using System.Data;
using System.Data.OleDb;
using System.Data.Common;
    
namespace App7
{
    public partial class Window5 : Window
    {
        FileStream fs = null;   // Поле файлового потока для видимости в классе
        String nameLibrary;     // Опорное поле для свойства с именем библиотеки
        int count;              // Поле под число рисунков
        string[] names;         // Поле под имена рисунков
        Properties.Settings settings; // Параметры
    
        // Конструктор
        public Window5()
        {
            InitializeComponent();
    
            // Запускаем диалог выбора библиотеки
            nameLibrary = SelectLibrary();
            // При отказе от выбора ничего не запускаем,
            // а в главном окне Window1 закрываем это окно 
            if (nameLibrary != String.Empty)
                ExecuteWindow();
        }
    
        // Извлекаем рисунки и управляем показом
        private void ExecuteWindow()
        {
        }
    
        // При смене индекса списка показывает выбранный рисунок
        private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
        }
    
        // Свойство доступа, проверяется в Window1
        public String NameLibrary   
        {
            get { return nameLibrary; }
        }
    
        // Диалог выбора библиотеки. Возвращает
        // пусто, если библиотека не выбрана
        private String SelectLibrary()
        {
            settings = new App7.Properties.Settings();
            String path = settings.dialogOpen;
            String fileName = IO.Path.Combine(path, "Pictures.my1.lib");
              
            // Создаем и настраиваем диалог выбора файла
            FORMS.OpenFileDialog openFileDialog = new FORMS.OpenFileDialog();
            openFileDialog.InitialDirectory = path;
            openFileDialog.FileName = "";
            openFileDialog.Filter = "Library Files(*.my1.lib)|*.my1.lib";
            FORMS.DialogResult result = openFileDialog.ShowDialog();
            if (result != FORMS.DialogResult.Cancel)
                fileName = openFileDialog.FileName; // Полное имя
            else
                fileName = String.Empty;
    
            return fileName;
        }
    
        // Обработчик события Closing, срабатывает перед закрытием приложения
        private void Window_Closing(object sender, 
            System.ComponentModel.CancelEventArgs e)
        {
            // Закрываем библиотечный поток
            if (fs != null)
                fs.Close(); 
    
            // Сохраняем параметры 
            if (nameLibrary != String.Empty)
            {
                settings.dialogOpen = 
                    nameLibrary.Substring(0, nameLibrary.LastIndexOf('\\'));
                settings.Save();
            }
        }
    }
}
  • В файле Window1.xaml измените заголовок списка для ' Пример 5 ' на ' Пример 5. Использование БД + файловой библиотеки '
  • Заполните в файле Window1.xaml.cs функцию Example5() следующим кодом (окончательный, приводится полностью)
void Example5()
        {
            // Предотвращение повторного создания дочернего окна
            bool existsWindow = false;
            foreach (Window window in Application.Current.Windows)// Перебираем коллекцию
            {
                if (window.Name == "_Window5")
                {
                    // Нашли среди существующих 
                    existsWindow = true;
                    window.Activate();// Сдвинуть на передний план
                    break;// Прервать перебор
                }
            }
    
            if (!existsWindow)// Если не существует, то создать и показать
            {
                Window5 wnd = new Window5();
                // Перед показом проверяем, выбрана ли библиотека
                if (wnd.NameLibrary != String.Empty)
                    wnd.Show();    // Показываем окно Window5
                else
                    wnd.Close();   // Закрываем окно Window5
            }
        }
  • Запустите приложение - окно Window5 запускается, но пока не функционирует
  • Добавьте в файл Window5.xaml.cs к членам класса Window5 функцию, возвращающую строку соединения с БД
public partial class Window5 : Window
    {
        ........................................................
        // Строка соединения с БД 
        private String ConnectionString(String fileName)
        {
            //string pathToFile = Application.StartupPath.ToString();
            string JetEngineString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
                "Jet OLEDB:Engine Type=5;Data Source=";
            return JetEngineString + fileName;
        }
        ........................................................
    }
  • Заполните функцию ExecuteWindow() следующим кодом
// Извлекаем рисунки и управляем показом 
        private void ExecuteWindow()
        {
            // Формируем имя БД из имени файловой библиотеки
            string nameDB = nameLibrary.Substring(0, nameLibrary.LastIndexOf('.')) + ".mdb";
    
            // Читаем некоторые данные из БД
            OleDbConnection connection = new OleDbConnection(ConnectionString(nameDB));
            OleDbCommand command = new OleDbCommand("SELECT COUNT(*) FROM MyTable");
            command.Connection = connection;
            connection.Open();
            // Извлекаем число рисунков
            count = (int)command.ExecuteScalar(); 
            // Меняем команду и извлекаем имена рисунков
            command.CommandText = "SELECT FileName FROM MyTable";
            OleDbDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
            names = new string[count];
            int i = 0;
            foreach (DbDataRecord rec in reader)// Равносильно while(dataReader.Read())
                names[i++] = ((string)rec[0]).Trim();// Сразу убираем пробелы
            // Соединение здесь закроет сам объект DataReader после прочтения всех данных
            // в соответствии с соглашением при его создании CommandBehavior.CloseConnection
    
            // Привязываем массив имен рисунков к списку
            listBox.ItemsSource = names;
            // Выделяем первый элемент списка, чтобы вызвать SelectionChanged
            listBox.SelectedIndex = 0;
            listBox.Focus();
        }
  • Разберитесь с кодом метода ExecuteWindow() и запустите пример - результат для ранее созданной БД Pictures.my1.mdb пока будет таким

Список с именами, полученными из БД Pictures.my1.mdb, функционирует нормально, но сами рисунки еще нужно извлечь из библиотеки Pictures.my1.lib и присоединить к элементу отображения Image.

  • Заполните заготовку обработчика listBox_SelectionChanged() следующим кодом
// При смене индекса списка показывает выбранный рисунок
        private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Формируем имя БД из имени файловой библиотеки
            string nameDB = nameLibrary.Substring(0, nameLibrary.LastIndexOf('.')) + ".mdb";
    
            // Создаем и настраиваем объект соединения с БД
            OleDbConnection connection = new OleDbConnection();
            connection.ConnectionString = ConnectionString(nameDB);
    
            // Создаем и настраиваем объект команды, параметризованной по имени рисунка
            OleDbCommand command = new OleDbCommand();
            command.Connection = connection;
            command.CommandType = CommandType.Text; // Необязательно! Установлено по умолчанию
            command.CommandText = "SELECT Offset, Length FROM MyTable WHERE FileName=?";
            command.Parameters.Add(new OleDbParameter());
            command.Parameters[0].Value = ((ListBox)sender).SelectedValue.ToString();// Имя рисунка
    
            // Извлекаем данные из БД 
            connection.Open();
            OleDbDataReader reader = command.ExecuteReader();
            reader.Read();  // Читаем только одну строку (она и будет всего одна)
            long offset = (int)reader["Offset"];
            int length = (int)reader["Length"];
            connection.Close(); // Раньше этого места закрывать нельзя!
    
            // Создаем и открываем один раз файловый поток библиотеки с рисункам
            if (fs == null)
                fs = new FileStream(
                    nameLibrary, FileMode.Open, FileAccess.Read, FileShare.Read);
    
            // Извлекаем рисунок из потока
            byte[] bytes = new byte[length];
            fs.Seek(offset, SeekOrigin.Begin);
            for (int i = 0; i < length; i++)
                bytes[i] = (byte)fs.ReadByte();
    
            // Отображаем рисунок пользователю
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.StreamSource = new MemoryStream(bytes);
            bi.EndInit();
            image.Source = bi;
        }
  • Разберитесь с кодом обработчика и запустите пример - результат для ранее созданной БД Pictures.my1.mdb и библиотеки Pictures.my1.lib соответствует ожидаемому

Пример 6. Создание базы данных OLE DB и заполнение ее рисунками

Если уж мы ранее решили использовать базу данных для управления рисунками, то более конструктивным будет подход, когда сами рисунки тоже хранятся в базе данных. Чтобы его реализовать, по прежнему нужно разработать две утилиты: одна создает БД и заполняет ее рисунками из выбранного каталога; вторая извлекает эти рисунки из БД и показывает пользователю. В данном примере мы создадим первую утилиту (правда, без потоков), а в следующем - вторую (с потоком). Итак, приступим...

Начнем с создания реляционной БД программным способом. База данных будет иметь имя Pictures.my2.md b и содержать одну таблицу с именем MyTable, структура которой в типах OLE D B и объектной модели C # будет такой

Таблица 19.6. Структура таблицы MyTable
Имя поля Тип OLE DB Тип объектной модели C# Размер
Name Type Type DefinedSize
FileName (уникальное) adWChar string 20 (определим сами, с запасом)
Picture adLongVarBinary (BLOB) byte[] 0 (неопределено)
  • В файле Window1.xaml измените заголовок списка для элемента ' Пример 6 ' на ' Пример 6. Создание базы данных с рисунками '
  • В панели Solution Explorer добавьте к узлу App7 командой контекстного меню Add/Class новый файл с именем CreateDB.cs и заполните его следующим кодом (приводится полностью)
using System;
using System.Windows.Forms;
using System.IO;
    
// Пространства имен для ADO.NET
using System.Data;
using System.Data.OleDb;
using System.Data.Common;
    
namespace App7
{
    class CreateDB
    {
        // Локальные поля
        String nameDB = "Pictures.my2.mdb";
        string path, fileName,
            tableName = "MyTable";// Нельзя давать имя "Local"!!!
        String extensionPictures = "jpg";
    
        // Параметризованный конструктор
        public CreateDB(string path)
        {
            // Инициализируем поля
            this.path = path;
            fileName = Path.Combine(path, nameDB);
    
            // Удалим предыдущую базу данных, если она есть
            if (new FileInfo(fileName).Exists)
                File.Delete(fileName);
        }
    
        // Строка соединения с БД
        private String ConnectionString(String fileName)
        {
            //string pathToFile = Application.StartupPath.ToString();
            string JetEngineString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
                "Jet OLEDB:Engine Type=5;Data Source=";
            return JetEngineString + fileName;
        }
    
        // Создание БД
        public bool CreateDatabase()
        {
            Object adoConnection = null;
            ADOX.CatalogClass catalog = new ADOX.CatalogClass();
    
            try
            {
                catalog.Create(ConnectionString(fileName));
                adoConnection = catalog.ActiveConnection;
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Ошибка в создании БД\n{0}", ex.Message),
                    "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            finally
            {
                if (catalog != null && adoConnection != null)
                {
                    ((ADODB.Connection)adoConnection).Close();// Приводим к интерфейсу
                    /***********  Вариант  *********
                    adoConnection.GetType().InvokeMember(
                        "Close", System.Reflection.BindingFlags.InvokeMethod,
                        null, adoConnection, new object[0]);
                    //*****************************/
    
                    catalog = null;
                    adoConnection = null;
                }
            }
    
            return true;// Успех, если дошли до этого места
        }
    
        // Создание таблицы
        public bool CreateTable()
        {
            ADODB.Connection conn = new ADODB.ConnectionClass();
            conn.Open(ConnectionString(fileName), null, null, 0);
            ADOX.Catalog catalog = new ADOX.CatalogClass();
            catalog.ActiveConnection = conn;
    
            try
            {
                ADOX.TableClass table = new ADOX.TableClass();// Объект таблицы
                table.ParentCatalog = catalog;  // Указали родителя для таблицы
                table.Name = tableName;         // Имя таблицы
                catalog.Tables.Append(table);   // Добавили в коллекцию таблиц
    
                // Задаем параметры настройки таблицы
                string[] columnNames =
                {
                    "FileName",
                    "Picture"
                };
                // Неопределенный размер заменяем нулем
                int[] columnSizes = new int[] { 20, 0 };
                ADOX.DataTypeEnum[] columnTypes = new ADOX.DataTypeEnum[] 
                    {
                        ADOX.DataTypeEnum.adWChar,          // До 255 символов fixed
                        ADOX.DataTypeEnum.adLongVarBinary   // BLOB
                    };
    
                // Настраиваем структуру таблицы 
                ADOX.ColumnClass column;
                for (int i = 0; i < columnSizes.Length; i++)
                {
                    column = new ADOX.ColumnClass();
                    column.ParentCatalog = catalog;  // Указали родителя для столбца
                    column.Name = columnNames[i];
                    column.DefinedSize = columnSizes[i];
                    column.Type = columnTypes[i];
                    column.Attributes = ADOX.ColumnAttributesEnum.adColNullable;// Позволить пусто
                    //column.Attributes = ADOX.ColumnAttributesEnum.adColFixed;// Фиксированная длина
                    table.Columns.Append(column, column.Type, column.DefinedSize);
                }
    
                // Делаем первый столбец уникальным (совпадения не допускаются)
                // http://www.sqldev.org/sql-server-data-access/
                // multi-column-primary-keys-in-access-using-adox-c-60766.shtml
                ADOX.Table tbl = catalog.Tables[tableName];
                tbl.Keys.Append(
                    "UniqueKeyLocal", ADOX.KeyTypeEnum.adKeyUnique, "FileName", null, null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
                return false;
            }
            finally
            {
                conn.Close();// Приводим к интерфейсу
            }
    
            return true;// Успех, если дошли до этого места
        }
    
        // Наполняем файловую БД данными
        public bool CreateData()
        {
            // Читаем информацию о всех файлах выбранного каталога
            FileInfo[] filesInfo = new DirectoryInfo(path).
                GetFiles("*." + extensionPictures);
            if (filesInfo.Length == 0)
            {
                MessageBox.Show(
                    "В выбранном каталоге нет файлов для упаковки в БД",
                    "Предупреждение",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
                return false;
            }
    
            // Сортируем объекты массива FileInfo по именам файлов
            Array.Sort<FileInfo>(filesInfo, 
                delegate(FileInfo x, FileInfo y)// Анонимный делегат вместо функции обратного вызова
                {
                    return String.Compare(x.Name, y.Name);
                });
    
            // Создаем и настраиваем инфраструктуру ADO.NET
            OleDbConnection conn = new OleDbConnection(ConnectionString(fileName));
            OleDbCommand cmd = new OleDbCommand();
            cmd.CommandType = CommandType.Text;  // Необязательно!
            cmd.CommandText = "SELECT * FROM " + tableName;
            cmd.Connection = conn;
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            adapter.SelectCommand = cmd;
            new OleDbCommandBuilder(adapter);   // Донастраиваем адаптер на запись
    
            // Пишем построчно в объектную таблицу и затем сразу в БД,
            // чтобы экономить оперативную память, если рисунков много
            DataTable table = null;
            conn.Open();// Метод FillSchema() теперь уже не закроет!!!
            for (int i = 0; i < filesInfo.Length; i++)
            {
                // Создаем и настраиваем объектную модель таблицы
                if (table == null)
                {
                    // Только один раз
                    table = new DataTable(tableName);
                    adapter.FillSchema(table, SchemaType.Source);
                }
                else   
                    table.Clear(); // Теперь только чистим, структура таблицы остается
    
                // Получаем сокращенное имя файла без пути и расширения
                String shortName = filesInfo[i].Name; // Уже без пути и есть!!!
                int len = shortName.LastIndexOf('.');
                shortName = shortName.Substring(0, len);// Убрали расширение
    
                // Добавляем в строку имя рисунка (и порядковый номер, чтобы було!)
                DataRow row = table.NewRow();
                row["FileName"] = (i + 1).ToString() + ") " + shortName;
    
                // Читаем файл с рисунком
                byte[] bytes = File.ReadAllBytes(
                    Path.Combine(filesInfo[i].DirectoryName, filesInfo[i].Name));
                /***********  Вариант  *********
                FileStream fileStream = filesInfo[i].OpenRead();
                byte[] bytes = new byte[fileStream.Length];
                int readByte, count = 0;
                while ((readByte = fileStream.ReadByte()) != -1)
                    bytes[count++] = (byte)readByte;
                fileStream.Close();
                //*****************************/
    
                // Добавляем в строку сам рисунок, адресуясь по имени столбца
                row["Picture"] = bytes;
                table.Rows.Add(row);    // Скидываем в объектную таблицу
                adapter.Update(table);  // Записываем эту одну строку в БД
            }
            // Удаляем объектную таблицу (Необязательно!)
            table.Dispose();
            // Закрываем соединение
            conn.Close();
    
            return true;// Успех, если дошли до этого места
        }
    }
}

Учитывая, что открытие соединения с БД является очень медленной операцией, в методе CreateData() перед вхождением в цикл заполнения БД рисунками мы открываем соединение только один раз. Когда соединение открыто, то методы адаптера FillSchema() и Fill() его не закрывают, поэтому после цикла нужно его закрыть самим. Экземпляр объекта построителя команд OleDbCommandBuilder нам нужен только для настройки адаптера на обновление данных в БД (по умолчанию последний настроен только на чтение), для этого нет необходимости создавать на него ссылку.

Желательно, чтобы рисунки попадали в БД уже отсортированными по именам. Поэтому после получения из выбранного каталога всех объектов FileInfo, мы их предварительно сортируем и только потом считываем с диска файлы в установленном порядке. Для сортировки используем перегрузку типизированного статического метода с делегатом, чтобы не выносить отдельно другую статическую функцию - обратного вызова (компаратор). В ходе сортировки метод Sort() автоматически будет обращаться к этой функции (анонимному делегату) при оценке весов Name очередных сравниваемых пар элементов массива.

  • В файле Window1.xaml.cs найдите функцию Example6() и заполните ее следующим вызывающим кодом (приводится полностью)
void Example6()
        {
            // Диалог выбора каталога
            dialogFolder =
                new System.Windows.Forms.FolderBrowserDialog();
            dialogFolder.Description = "Выберите каталог для создания БД";
            dialogFolder.ShowNewFolderButton = false;// Отключить кнопку создания новой папки
            dialogFolder.RootFolder = Environment.SpecialFolder.MyComputer;// Компьютер
            dialogFolder.SelectedPath = settings.dialogFolder;
            System.Windows.Forms.DialogResult result = dialogFolder.ShowDialog();
            // Если был отказ или диалог закрыт системной кнопкой
            if (result == System.Windows.Forms.DialogResult.Cancel)
                return;
    
            // Извлекаем новый каталог
            String path = dialogFolder.SelectedPath;// Полный путь
            // Создаем структуру БД
            CreateDB create = new CreateDB(path);
            bool success;
            if (success = create.CreateDatabase())
                success = create.CreateTable();
            if (!success)
            {
                MessageBox.Show("Структура БД не создана");
                return;
            }
    
            success = create.CreateData();
            if (success)
                MessageBox.Show("База данных создана");
            else
                MessageBox.Show("База данных не создана");
    
            // Принудительная перерисовка окна WPF
            this.Height = this.ActualHeight + 1;
            this.Height = this.ActualHeight - 1;
        }
  • Запустите пример и зайдите в папку Images, расположенную в прилагаемом к работе каталоге Source

Мы видим, что файловая БД Pictures.my2.mdb создается и наполняется данными. Если открыть эту БД в Office Access, то она (с учетом автоматической сортировки Office Access ) будет такой


Если проверить разработанную утилиту на создании БД с большим количеством рисунков (1000), то в сравнении с формированием файловой библиотеки она работает ничуть не медленнее. Основная выгода заключается в том, что при записи каждого рисунка мы пользуемся уже открытым соединением. Точно также для библиотечного файла поток создается только один раз. Мы дальше убедимся, что при чтении файловой библиотеки и БД скорость тоже мало различима (и это хорошо), поскольку там и там извлекается только один рисунок и скорость открытия примерно равна.

Можно было бы, конечно, сначала прочитать все рисунки с диска, а потом сразу записать их в БД, и это было бы еще быстрее. Но рисунков может оказаться много и большого размера. В этом случае оперативной памяти компьютера просто нехватит и он вынужден будет создавать на жестком диске временные файлы промежуточного хранения данных (такой механизм называется спуллинг - Simultaneous Peripherial Operation Off Line ). Это тоже существенно замедлит работу.

Базы данных - это большое достижение 'всего прогрессивного человечества' (и нас с вами!): они универсальны, надежны, элегантны, незаменимы, а программировать их просто приятно и 'просто просто' (это элементарно, Ватсон).

< Лекция 5 || Лекция 6: 12345678910111213
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл.

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