|
При выполнении в лабораторной работе упражнения №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);
}
}
}-
Внимательно разберитесь со всем приведенным кодом упражнений. Такой подход - самый короткий путь научиться программировать
