При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Разработка компонента WPF и анализатора HTML-таблиц
Пример 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 |
Для правильной работы утилиты таблица должна удовлетворять следующим условиям:
- HTML -файл должен содержать хотя бы одну таблицу
- Все ячейки таблицы должны содержать параграфы, включая каждый ответ
- Заголовки таблицы будут являться заголовками столбцов в DataTable
- Необходимо удалить управляющие символы " (кавычки) и (пробел) из всей таблицы, иначе они перейдут в 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); } } }
- Внимательно разберитесь со всем приведенным кодом упражнений. Такой подход - самый короткий путь научиться программировать