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

Разработка компонента WPF и анализатора HTML-таблиц

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

Пример 3. Преобразование группы таблиц с текстами в наборы данных DataSet

Воспользуемся вторым способом извлечения информации из HTML -таблиц в DataSet и немного изменим задачу. Пусть у нас имеются HTML -файлы исключительно с таблицами текстов одинаковой структуры, например, пусть одна из таблиц будет такой

QueryID Query CorrectAnswer Comment Theme
1_4 Каким транспортным средствам в обозначенной знаком зоне запрещена стоянка в выходные и праздничные дни ? 1. Только грузовым автомобилям с разрешенной максимальной массой более 3,5 т. 2. Всем грузовым автомобилям. 3. Всем транспортным средствам. 1 Знак 5.27 "Зона с ограничением стоянки" относится к зональным знакам, требования которых действуют на всей территории (участке дороги), обозначенной такими знаками, вплоть до выезда из зоны, обозначенного в данном случае знаком 5.28 "Конец зоны с ограничением стоянки". Табличка 8.5.1, размещенная под знаком, распространяет его действие только на субботние, воскресные и праздничные дни. А изображение таблички 8.4.1 "Вид транспортного средства" в нижней части знака информирует о том, что в обозначенной зоне стоянка запрещена только грузовым автомобилям, у которых разрешенная максимальная масса превышает 3,5 т. 4
1_9 По какой траектории Вы имеете право выполнить разворот, управляя автопоездом, имеющим большую длину ? 1. Только по А. 2. Только по Б. 3. По любой. 1 При недостаточной для разворота ширине проезжей части Правила разрешают вне перекрестка выполнение маневра не из крайнего левого положения, а с обочины или от правого края проезжей части (п. 8.8), т.е. по траектории А. 8
1_10 С какой скоростью Вы можете продолжить движение вне населенного пункта по левой полосе на грузовом автомобиле с разрешенной максимальной массой более 3,5 т ? 1. Не более 50 км/ч. 2. Не менее 50 км/ч и не более 90 км/ч. 3. Не менее 50 км/ч и не более 70 км/ч. 3 Знак 4.6 "Ограничение минимальной скорости" и табличка 8.14 "Полоса движения" предписывают двигаться по левой полосе со скоростью не менее 50 км/ч. Однако при этом на дороге вне населенного пункта, не относящейся к автомагистрали, вы не имеете права развивать скорость на грузовом автомобиле более 70 км/ч (п. 10.3). 10

Для правильной работы утилиты таблица должна удовлетворять следующим условиям:

  1. HTML -файл должен содержать хотя бы одну таблицу
  2. Все ячейки таблицы должны содержать параграфы, включая каждый ответ
  3. Заголовки таблицы будут являться заголовками столбцов в DataTable
  4. Необходимо удалить управляющие символы &quot; (кавычки) и &nbsp; (пробел) из всей таблицы, иначе они перейдут в DataSet

Наша задача, разработать утилиту, которая бы заполнила ADO.NET -объект DataTable или DataSet содержимым одной таблицы <table> или группы таблиц. Утилита будет способна обрабатывать много таблиц, но применим ее только к одной таблице Ticket1.htm, которая приведена в каталоге Source. При желании, можно развить эту утилиту до функциональности, чтобы она создавала и заполняла данными, извлеченными из <table>, таблицу (или несколько таблиц) базы данных.

В процессе преобразования исходной таблицы HTML будем заполнять наборы данных для вопросов и отдельно для ответов, чтобы получить следующие представления (на примере одной исходной таблицы)

QueryID Query CorrectAnswer Comment Theme
4 Каким транспортным средствам в обозначенной знаком зоне запрещена стоянка в выходные и праздничные дни ? 1 Знак 5.27 "Зона с ограничением стоянки" относится к зональным знакам, требования которых действуют на всей территории (участке дороги), обозначенной такими знаками, вплоть до выезда из зоны, обозначенного в данном случае знаком 5.28 "Конец зоны с ограничением стоянки". Табличка 8.5.1, размещенная под знаком, распространяет его действие только на субботние, воскресные и праздничные дни. А изображение таблички 8.4.1 "Вид транспортного средства" в нижней части знака информирует о том, что в обозначенной зоне стоянка запрещена только грузовым автомобилям, у которых разрешенная максимальная масса превышает 3,5 т. 4
9 По какой траектории Вы имеете право выполнить разворот, управляя автопоездом, имеющим большую длину ? 1 При недостаточной для разворота ширине проезжей части Правила разрешают вне перекрестка выполнение маневра не из крайнего левого положения, а с обочины или от правого края проезжей части (п. 8.8), т.е. по траектории А. 8
10 С какой скоростью Вы можете продолжить движение вне населенного пункта по левой полосе на грузовом автомобиле с разрешенной максимальной массой более 3,5 т ? 3 Знак 4.6 "Ограничение минимальной скорости" и табличка 8.14 "Полоса движения" предписывают двигаться по левой полосе со скоростью не менее 50 км/ч. Однако при этом на дороге вне населенного пункта, не относящейся к автомагистрали, вы не имеете права развивать скорость на грузовом автомобиле более 70 км/ч (п. 10.3). 10

QueryID AnswerID Answer
4 1 Только грузовым автомобилям с разрешенной максимальной массой более 3,5 т.
4 2 Всем грузовым автомобилям.
4 3 Всем транспортным средствам.
9 1 Только по А.
9 2 Только по Б.
9 3 По любой.
10 1 Не более 50 км/ч.
10 2 Не менее 50 км/ч и не более 90 км/ч.
10 3 Не менее 50 км/ч и не более 70 км/ч.
  • Добавьте к решению новый проект консольного приложения с именем CreateDataSet и назначьте его стартовым в решении
  • Добавьте к проекту новый класс с именем CreateData в файле CreateData.cs и заполните его так
using System;
using System.Collections.Generic;
using System.Text;
    
using System.Data;
using System.Text.RegularExpressions;
    
namespace CreateDataSet
{
    public enum SelectTicket
    {
        AB,
        CD,
        ABCD
    }
    
    class CreateData
    {
        // Source: "http://www.dotnetfunda.com/articles/article51.aspx"
        void ConvertHTMLTablesToDataSet(
            String HTML, DataSet dsQuestions, DataSet dsAnswers)
        {
            // Локальные сылки
            DataTable dtQuestions;
            DataRow drQuestions;
            DataTable dtAnswers;
            DataRow drAnswers;
    
            bool HeadersExist = false;  // Флаг существования заголовка таблицы
            int iCurrentColumn = 0;     // Счетчик столбцов
            int iCurrentRow = 0;        // Счетчик строк
    
            // Регулярные выражения и опции
            String TableExpression = "<table[^>]*>(.*?)</table>";
            String HeaderExpression = "<th[^>]*>(.*?)</th>";
            String RowExpression = "<tr[^>]*>(.*?)</tr>";
            String ColumnExpression = "<td[^>]*>(.*?)</td>";
            String ParagraphExpression = "<p[^>]*>(.*?)</p>";
            RegexOptions options = RegexOptions.Multiline |
                                   RegexOptions.Singleline |
                                   RegexOptions.IgnoreCase;
    
            // Извлекаем коллекцию таблиц из содержимого HTML
            MatchCollection Tables = Regex.Matches(HTML, TableExpression, options);
    
            // Проходим по всем HTML-таблицам 
            foreach (Match Table in Tables)
            {
                // Сбрасываем счетчик строки и флаг заголовка
                HeadersExist = false;
                iCurrentRow = 0;
    
                // Создаем объект новой таблицы и наполняем его
                dtQuestions = new DataTable();
                dtAnswers = new DataTable();
    
                /* Создаем соответствующее количество столбцов 
                 * для текущей таблицы (используем заголовки, 
                 * если они существуют, иначе используем 
                 * заданные по умолчанию названия)                
                 */
                if (Table.Value.Contains("<th"))
                {
                    HeadersExist = true;// Таблица содержит заголовок
                    // Заполняем коллекцию соответствий для всех <th> в таблице
                    MatchCollection Headers = Regex.Matches(
                        Table.Value, HeaderExpression, options);
    
                    // Добавляем столбцы с именами из строки заголовков текущей таблицы
                    foreach (Match Header in Headers)
                    {
                        // Groups[0] - с дескрипторами <p>Содержимое</p>
                        // Groups[1] - только Содержимое
                        MatchCollection paragraphs = Regex.Matches(Header.Value, ParagraphExpression, options);
                        if (paragraphs.Count != 0)
                            dtQuestions.Columns.Add(paragraphs[0].Groups[1].ToString());
                        else
                            dtQuestions.Columns.Add(Header.Groups[1].ToString());
                    }
                }
                else
                {
                    Match tab = Regex.Matches(Table.Value, TableExpression, options)[0];
                    Match row = Regex.Matches(tab.ToString(), RowExpression, options)[0];
                    int count = Regex.Matches(row.ToString(), ColumnExpression, options).Count;
    
                    // Строки заголовков нет, добавляем дежурные имена
                    for (int iColumns = 0; iColumns < count; iColumns++)
                        dtQuestions.Columns.Add("Column" + iColumns);
                }
    
                String[] TableAnswerColumnsName = { "QueryID", "AnswerID", "Answer" };
                for (int iColumns = 0; iColumns < TableAnswerColumnsName.Length; iColumns++)
                    dtAnswers.Columns.Add(TableAnswerColumnsName[iColumns]);
    
                // Извлекаем коллекцию строк текущей таблицы
                MatchCollection Rows = Regex.Matches(Table.Value, RowExpression, options);
    
                // Добавляем строки в объект DataRow
                foreach (Match Row in Rows)
                {
                    // Игнорируем строку заголовка
                    if (iCurrentRow != 0 || HeadersExist != true)
                    {
                        drQuestions = dtQuestions.NewRow();
                        iCurrentColumn = 0;
                        // Извлекаем коллекцию столбцов текущей строки
                        MatchCollection Columns = Regex.Matches(Row.Value, ColumnExpression, options);
                        foreach (Match Column in Columns)
                        {
                            // Извлекаем коллекцию параграфов из текущего столбца
                            MatchCollection paragraphs = Regex.Matches(Column.Value, ParagraphExpression, options);
                            if (paragraphs.Count != 0)
                            {
                                int iAnswer = 0;
                                String line = String.Empty;
                                foreach (Match paragraph in paragraphs)
                                {
                                    line = paragraph.Groups[1].ToString();
    
                                    // Убираем все лишнее
                                    string[] split = line.Split(new Char[] { '\r', '\n', ' ' });
                                    StringBuilder strBuilder = new StringBuilder();
                                    foreach (string s in split)
                                    {
                                        string word = s.Trim();
                                        if (word != String.Empty)
                                            strBuilder.Append(" " + word);
                                    }
                                    line = strBuilder.ToString().Trim();
    
                                    // Убираем номера ответов
                                    int pos = line.IndexOf(".");
                                    if (pos > 0 && pos <= 2 && iCurrentColumn == 1)
                                    {
                                        // Ответы 
                                        drAnswers = dtAnswers.NewRow();
                                        drAnswers[0] = drQuestions[0];
                                        iAnswer++;
                                        drAnswers[1] = iAnswer.ToString();
                                        line = line.Substring(pos + 1).Trim();
                                        drAnswers[2] = line;
                                        dtAnswers.Rows.Add(drAnswers);
                                        continue;
                                    }
    
                                    if (iAnswer == 0)
                                        drQuestions[iCurrentColumn] = line;
                                }
                            }
                            else
                                drQuestions[iCurrentColumn] = Column.Groups[1].ToString();
    
                            iCurrentColumn++;
                        }
    
                        dtQuestions.Rows.Add(drQuestions);
                    }
    
                    iCurrentRow++;
                }
    
                dsQuestions.Tables.Add(dtQuestions);
                dsAnswers.Tables.Add(dtAnswers);
            }
        }
    
        void FillDataset(string path, DataSet dsQuestions, DataSet dsAnswers, int count)
        {
            for (int i = 1; i <= count; i++)
            {
                string file = path + "\\Ticket" + i.ToString() + ".htm";
                System.IO.StreamReader streamReader = new System.IO.StreamReader(
                    file, Encoding.GetEncoding(1251));
    
                String source = streamReader.ReadToEnd();
    
                DataSet dsQuestionsItem = new DataSet();
                DataSet dsAnswersItem = new DataSet();
                ConvertHTMLTablesToDataSet(source, dsQuestionsItem, dsAnswersItem);
    
                foreach (DataTable table in dsQuestionsItem.Tables)
                {
                    DataRow[] rows = new DataRow[table.Rows.Count];
                    for (int iRow = 0; iRow < rows.Length; iRow++)
                    {
                        rows[iRow] = table.Rows[iRow];
                        rows[iRow][0] = (rows[iRow][0]).ToString().Trim();
                    }
                    dsQuestions.Merge(rows);
                }
                foreach (DataTable table in dsAnswersItem.Tables)
                {
                    DataRow[] rows = new DataRow[table.Rows.Count];
                    for (int iRow = 0; iRow < rows.Length; iRow++)
                    {
                        rows[iRow] = table.Rows[iRow];
                        rows[iRow][0] = (rows[iRow][0]).ToString().Trim();
                    }
                    dsAnswers.Merge(rows);
                }
            }
        }
    
        // Поля
        DataSet dsQuestionsAB = new DataSet();
        DataSet dsAnswersAB = new DataSet();
        DataSet dsQuestionsCD = new DataSet();
        DataSet dsAnswersCD = new DataSet();
        int lenQuery = 0, lenComment = 0, lenAnswer = 0;
        int countTicket = 40; // Количество файлов-билетов
    
        // Свойства
        public DataSet QuestionsAB { get { return dsQuestionsAB; } }
        public DataSet AnswersAB { get { return dsAnswersAB; } }
        public DataSet QuestionsCD { get { return dsQuestionsCD; } }
        public DataSet AnswersCD { get { return dsAnswersCD; } }
        public int LenQuery { get { return lenQuery; } }
        public int LenComment { get { return lenComment; } }
        public int LenAnswer { get { return lenAnswer; } }
        public int CountTicket { set { countTicket = value; } }
    
        public void Execute(SelectTicket selectTicket)
        {
            string path = System.IO.Directory.GetCurrentDirectory();
    
            int len;
            switch (selectTicket)
            {
                case SelectTicket.AB:
                    // Заполняем DataSet
                    FillDataset(path + @"\AB", dsQuestionsAB, dsAnswersAB, countTicket);
    
                    // Считаем размеры полей для создания объектных таблиц
                    foreach (DataRow row in dsQuestionsAB.Tables[0].Rows)
                    {
                        len = row["Query"].ToString().Length;
                        if (len > lenQuery)
                            lenQuery = len;
    
                        len = row["Comment"].ToString().Length;
                        if (len > lenComment)
                            lenComment = len;
                    }
                    foreach (DataRow row in dsAnswersAB.Tables[0].Rows)
                    {
                        len = row["Answer"].ToString().Length;
                        if (len > lenAnswer)
                            lenAnswer = len;
                    }
                    break;
                case SelectTicket.CD:
                    // Заполняем DataSet
                    FillDataset(path + @"\CD", dsQuestionsCD, dsAnswersCD, countTicket);
    
                    // Считаем размеры полей для создания объектных таблиц
                    foreach (DataRow row in dsQuestionsCD.Tables[0].Rows)
                    {
                        len = row["Query"].ToString().Length;
                        if (len > lenQuery)
                            lenQuery = len;
    
                        len = row["Comment"].ToString().Length;
                        if (len > lenComment)
                            lenComment = len;
                    }
                    foreach (DataRow row in dsAnswersCD.Tables[0].Rows)
                    {
                        len = row["Answer"].ToString().Length;
                        if (len > lenAnswer)
                            lenAnswer = len;
                    }
                    break;
                case SelectTicket.ABCD:
                    // Заполняем DataSet
                    FillDataset(path + @"\AB", dsQuestionsAB, dsAnswersAB, countTicket);
                    FillDataset(path + @"\CD", dsQuestionsCD, dsAnswersCD, countTicket);
    
                    // Считаем размеры полей для создания объектных таблиц
                    foreach (DataRow row in dsQuestionsAB.Tables[0].Rows)
                    {
                        len = row["Query"].ToString().Length;
                        if (len > lenQuery)
                            lenQuery = len;
    
                        len = row["Comment"].ToString().Length;
                        if (len > lenComment)
                            lenComment = len;
                    }
                    foreach (DataRow row in dsAnswersAB.Tables[0].Rows)
                    {
                        len = row["Answer"].ToString().Length;
                        if (len > lenAnswer)
                            lenAnswer = len;
                    }
                    foreach (DataRow row in dsQuestionsCD.Tables[0].Rows)
                    {
                        len = row["Query"].ToString().Length;
                        if (len > lenQuery)
                            lenQuery = len;
    
                        len = row["Comment"].ToString().Length;
                        if (len > lenComment)
                            lenComment = len;
                    }
                    foreach (DataRow row in dsAnswersCD.Tables[0].Rows)
                    {
                        len = row["Answer"].ToString().Length;
                        if (len > lenAnswer)
                            lenAnswer = len;
                    }
                    break;
            }
        }
    
        public void Show(DataSet dsQuestions, DataSet dsAnswers)
        {
            for (int i = 0; i < dsQuestions.Tables.Count; i++)
            {
                // Распечатываем заголовки столбцов
                foreach (DataColumn col in dsQuestions.Tables[i].Columns)
                    Console.WriteLine("{0}", col.ColumnName);
                Console.WriteLine();
    
                // Распечатываем строки
                foreach (DataRow row in dsQuestions.Tables[i].Rows)
                {
                    foreach (DataColumn col in dsQuestions.Tables[i].Columns)
                        Console.WriteLine("{0}", row[col].ToString());
                    Console.WriteLine();
                }
    
                Console.WriteLine();
            }
    
            for (int i = 0; i < dsAnswers.Tables.Count; i++)
            {
                // Распечатываем заголовки столбцов
                foreach (DataColumn col in dsAnswers.Tables[i].Columns)
                    Console.WriteLine("{0}", col.ColumnName);
                Console.WriteLine();
    
                // Распечатываем строки
                foreach (DataRow row in dsAnswers.Tables[i].Rows)
                {
                    foreach (DataColumn col in dsAnswers.Tables[i].Columns)
                        Console.WriteLine("{0}", row[col].ToString());
                    Console.WriteLine();
                }
    
                Console.WriteLine();
            }
        }
    }
}

При создании экземпляра этого класса в клиенте должен быть произведен разбор кода HTML -таблиц и заполнены 4 (если режим SelectTicket.ABCD ) набора данных типа DataSet, ссылки на которые доступны через свойства QuestionsAB, AnswersAB, QuestionsCD, AnswersCD. Попутно будут вычислены максимальные размеры полей LenQuery, LenComment, LenAnswer.

  • Модифицируйте файл Program.cs следующим образом
using System;
using System.Collections.Generic;
using System.Text;
    
using System.Data;
    
namespace CreateDataSet
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.White;
            Console.WindowWidth = 81;
    
            CreateData tables = new CreateData();
            tables.CountTicket = 1;
            tables.Execute(SelectTicket.CD);
            tables.Show(tables.QuestionsCD, tables.AnswersCD);
    
            Console.WriteLine(String.Format("LenQuery={0}; LenComment={1}; LenAnswer={2}",
                tables.LenQuery, tables.LenComment, tables.LenAnswer));
    
            Console.ReadLine();
        }
    }
}
  • Через панель Solution Explorer создайте в корне текущего проекта папку CD и скопируйте в нее контекстной командой Add/Existing Item из прилагаемого к работе каталога Source файл Ticket1.htm
  • В Solution Explorer выделите файл Ticket1.htm и в панели Properties назначьте ему свойство
    • Build Action=Content
    • Copy to Output Directory=Copy if newer
  • Запустите проект на выполнение - получится следующий консольный вывод
QueryID
Query
CorrectAnswer
Comment
Theme 
1_4
Каким транспортным средствам в обозначенной знаком зоне запрещена стоянка в выходные и праздничные дни ?
1
Знак 5.27 "Зона с ограничением стоянки" относится к зональным знакам, требования которых действуют 
на всей территории (участке дороги), обозначенной такими знаками, вплоть до выезда из зоны, обозначенного в данном случае 
знаком 5.28 "Конец зоны с ограничением стоянки". Табличка 8.5.1, размещенная под знаком, распространяет его 
действие только на субботние, воскресные и праздничные дни. А изображение таблички 8.4.1 "Вид транспортного средства" 
в нижней части знака информирует о том, что в обозначенной зоне стоянка запрещена только грузовым автомобилям,
у которых разрешенная максимальная масса превышает 3,5 т.
4
1_9
По какой траектории Вы имеете право выполнить разворот, управляя автопоездом, имеющим большую длину ?
1
При недостаточной для разворота ширине проезжей части Правила разрешают вне перекрестка выполнение маневра не из крайнего 
левого положения, а с обочины или от правого края проезжей части (п. 8.8), т.е. по траектории А.
8
1_10
С какой скоростью Вы можете продолжить движение вне населенного пункта по левой полосе на грузовом автомобиле с 
С разрешенной максимальной массой более 3,5 т ?
3
Знак 4.6 "Ограничение минимальной скорости" и табличка 8.14 "Полоса движения" предписывают двигаться по 
левой полосе со скоростью не менее 50 км/ч. Однако при этом на дороге вне населенного пункта, не относящейся к автомагистрали, 
вы не имеете права развивать скорость на грузовом автомобиле более 70 км/ч (п. 10.3).
10
QueryID
AnswerID
Answer
1_4
1
Только грузовым автомобилям с разрешенной максимальной массой более 3,5 т.
1_4
2
Всем грузовым автомобилям.
1_4
3
Всем транспортным средствам.
1_9
1
Только по А.
1_9
2
Только по Б.
1_9
3
По любой.
1_10
1
Не более 50 км/ч.
1_10
2
Не менее 50 км/ч и не более 90 км/ч.
1_10
3
Не менее 50 км/ч и не более 70 км/ч.
LenQuery=157; LenComment=615; LenAnswer=74

Мы видим, что данные извлекаются утилитой из HTML -таблицы правильно и размещаются построчно в соответствующих полях объекта DataSet.

Упражнение 3. Изменение ширины окна колесом мыши

В заключение приведем интересный способ регулирования ширины окна WPF, приведенный в http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a4b5150f-5d70-4d33-9355-4cac9521677d

  • Создайте приложение WPF Application с именем WpfApplication1, внесите в него приведенный ниже код и испытайте работу
<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    Name="window1"  MouseWheel="Window_MouseWheel">
    <Grid>
    </Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Animation; 
    
namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    
        private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            int delta = e.Delta;
            double w1 = this.window1.ActualWidth;
            double w2 = w1 + 2 * delta / 10;
            DoubleAnimation anima = new DoubleAnimation();
            anima.Duration = new Duration(TimeSpan.FromSeconds(0.3));
            anima.From = w1;
            anima.To = w2;
            anima.FillBehavior = FillBehavior.HoldEnd;
            this.window1.BeginAnimation(Window.WidthProperty, anima);
        }
    }
}
  • Внимательно разберитесь со всем приведенным кодом упражнений. Такой подход - самый короткий путь научиться программировать

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Алексей Бабушкин
Алексей Бабушкин

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

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