Работаем с MS Word из C#, часть 0, класс и тестовый проект-пример WinForms

Иллюстрация к циклу заметок про работу с Microsoft Word из C#. Проект Visual Studio 2010, два класса - WordDocument и WordSelection (просто часть документа, обертка над Range), реализующие описанные приемы, тестовый шаблон и простенькое окошко, позволяющее протестировать работу классов и наглядно увидеть, как именно все цепляется к событиям формы для самых начинающих. Если вы любите умные слова, то эти классы используют шаблон Фасад.


Читать далее

LinQ запрос к DataTable

Задача: выполнить запрос на LinQ к DataTable. Стандартная DataTable LinQ не поддерживает, но решается это затруднение очень просто, надо использовать метод AsEnumerable() из LinQ to Dataset.

string someTextValue = (from dataRow in someDataTable.AsEnumerable()
                   where dataRow.Field<int>("VALUE_ID") == valueId
                   select dataRow.Field<string>("VALUE_TEXT") ).Single();

// тоже самое методическим синтаксисом (method syntax)
string someTextValue = someDataTable.AsEnumerable(). Where(dataRow => dataRow.Field<int>("VALUE_ID") == valueId). Select(dataRow => dataRow.Field<string>("VALUE_TEXT")).Single(); 

Таблица должна быть строго типизирована, иначе получим ошибку Specified cast is not valid. Минимальный код для динамически создаваемой DataTable:

someDataTable.Columns.Add(new DataColumn("VALUE_ID", System.Type.GetType("System.Int32")));

Также в виде костыля можно использовать конвертацию прямо внутри запроса LinQ

int someCountById = someDataTable.AsEnumerable().Where(dataRow => Convert.ToInt32(dataRow["SOME_INT_ID"]) == 1).Count();

Returning a single value with Linq to SQL
LINQ query on a DataTable
How to: Write LINQ Queries in C#
Lambda Expressions (C# Programming Guide)
IEnumerable Interface

Выбираем/получаем выбранную строку/ячейку в DataGridView

Задача: получить выбранную в данный момент строку/ячейку DataGridView и/или выбрать ее. На самом деле это одна и та же задача, если количество строк и столбцов в гриде может непредсказуемо меняться. Мы конечно можем получить выбранный столбец через свойство SelectedRows, но для этого свойство SelectionMode должно быть установлено в FullRowSelect или RowHeaderSelect. Универсальный метод будет всегда работать через выбранную ячейку и свойство SelectedCells или CurrentCell

 
int selRowNum = _someDataGridView.SelectedCells[0].RowIndex; 

// или так

  int selRowNum = _someDataGridView.CurrentCell.RowIndex;

С выбором конкретной ячейки еще хуже, по-настоящему надежно будет работать только следующий код

 
int rowNum = 1;
DataGridViewCell cell = _someDataGridView.Rows[rowNum].Cells[0];
_someDataGridView.CurrentCell = cell;
_someDataGridView.CurrentCell.Selected = true; // в некоторых случаях без этого не работает

Упростить себе жизнь можно парой простых методов
Читать далее

Ошибка Collection was modified; enumeration operation might not execute

Иногда программисту хочется чего-то удалить из коллекции. Например строку из коллекции строк DataTable. Он радостно пишет что-то в духе:

// на этом месте могла бы быть ваша реклама... то есть любая коллекция
foreach (DataRow currRow in _someDataTable.Rows)
{
    if (/*условие для удаления*/)
    {
        someDataTable.Rows.Remove(currRow);
    }
}

и получает жестокий облом в виде ошибки с невнятным сообщением "Collection was modified; enumeration operation might not execute".
Читать далее

Совершенный код. Главная задача программирования

Этой записью я надеюсь начать цикл конспектов замечательной книги Стива Макконела "Совершенный код" - обязательного чтения для любого программиста. При всей своей замечательности книга очень большая и сложная, даже при повторном прочтении очень сложно удержать ее в голове всю.

Начну я с главной задачи современного программирования,которой подчинены все остальные техники вроде от шаблонов проектирования и объектно-ориентированного программирования до разнообразных фреймворков и библиотек. Главная задача программирования - это снижение сложности. Суть этой проблемы была давным-давно описана в знаменитой статье Федерика Брукса Серебрянной пули нет - главной трудностью при разработке программ является не неудобство конкретного языка программирования или недостаточная скорость железа, а сложность задачи реального мира,которую должна решить ваша программа. Даже если мы сможем описать программу на человеческом языке и выполнить ее на неограниченно быстром компьютере, нам все равно придется потратить огромное количество времени на анализ сложного, неорганизованного реального мира, определение зависимостей и исключительных ситуаций, проектирование достаточно точных решений. Программные проекты чаще всего терпят крах из-за того, что программисты сами перестают понимать, что происходит внутри программного кода и к чему приведут даже самые незначительные изменения, как они скажутся на других частях программы. Самым важным условием успеха программного проекта является непрерывная борьба за снижение его сложности, начиная с самых ранних стадий проектирования и заканчивая написанием последней строчки кода.
Читать далее

А ваш язык программирования это может? (перевод)

Как-то раз, просматривая свой код, вы заметили, что два больших участка выглядят практически одинаково. Они действительно были одинаковы, за исключением того, что один участок относился к "спагетти" а второй к "шоколад".

// простейший пример
alert("Я люблю спагетти!");
alert("Я люблю шоколад!");

Эти примеры написаны на JavaScript, но даже если вы его не знаете, то все равно поймете общий смысл.

Повторяющиеся куски кода выглядели неправильно, так что вы создали функцию

function SwedishChef( food )
{
    alert("Я люблю " + food + "!");
}
	
SwedishChef("спагетти");
SwedishChef("шоколад");

(Swedish Chef)

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

Теперь вы заметили еще два участка кода, которые выглядели практически одинаковыми, за исключением того, что один из них вызывал функцию PutInPan, а другой PutInPot. Больше ничего не отличалось.
Читать далее

Отслеживаем изменения в таблице с помощью триггеров Transact Sql

Задача: сохранять информацию о всех изменения в определенной таблицы. Наиболее простое решение - создать таблицу, совпадающую по структуре с отслеживаемой и при каждом изменении писать в эту таблицу строку с обновленным состоянием измененной строки. Сделать это можно с помощью триггера, отслеживающего операции INSERT, UPDATE и DELETE.

Ниже приведен код триггера для исходной таблицы людей PERSONS таблицы изменений CHANGES_PERSONS вида:

CREATE TABLE PERSONS
(
PERSON_ID INT NOT NULL IDENTITY PRIMARY KEY,
SURNAME VARCHAR(150) NOT NULL, 
NAME VARCHAR(150) NOT NULL,
OTCHESTVO VARCHAR(150) NOT NULL
)

CREATE TABLE CHANGES_PERSONS
(
CHANGE_ID_PERS int not null identity,
CHANGE_DATE datetime not null default getdate(),
CHANGE_TYPE varchar(10) not null,
PERSON_ID INT NOT NULL,
SURNAME VARCHAR(150) NOT NULL, 
NAME VARCHAR(150) NOT NULL,
OTCHESTVO VARCHAR(150) NOT NULL
) 

Читать далее

Прекрасный код

В подавляющем большинстве случаев то, что неопытным разработчикам кажется прекрасным, поверхностно, а то, что они считают уродливым - это на самом деле закаленный в боях, готовый к внедрению код от мастеров.

Learn to Read the Source, Luke on Coding Horror

(And most of the time, what inexperienced developers consider beautiful is superficial, and what they consider ugly, is battle-hardened production-ready code from master hackers.)

ComboBox - подстраиваем ширину выпадающего списка под самый длинный элемент

Два очевидных решения - сделать всплывающую подсказку или увеличить ширину самого выпадающего списка. Вычисляем максимальную длину строки в таблице-справочнике:

// устанавливаем ширину выпадающего списка на основании наибольшей длины элемента в источнике данных 
public static void SetComboBoxDropDownWidth(ComboBox comboBox,  DataView comboBoxSourceView, string visibleStringName)
{
	if (comboBoxSourceView.Count == 0) { return; }
	System.Drawing.Graphics graphics = comboBox.CreateGraphics();
	comboBox.DropDownWidth =
		(from width in
			(from DataRowView item in comboBoxSourceView
			select Convert.ToInt32( graphics.MeasureString( item[visibleStringName].ToString(), comboBox.Font).Width))
		select width).Max();
	comboBox.DropDownWidth += 10; //иногда не влезает последняя буква
}

Setting DropDown list width of DataGridView ComboBoxColumn - WinForms

Работа с Excel из C# через COM Interop, часть 1, открываем документ и выводим данные

Задача: вывести данные в таблицу Excel с красивым оформлением и открыть ее, чтобы пользователь мог напечатать или сохранить средствами самого Excel. Необходимо поддерживать все версии Office, начиная с 97, то есть вывод в новые xml-форматы Office 2007 и выше невозможен

Самая сложная часть - работа с оформлением, так как во-первых интерфейс Excel крайне неочевиден, запутан и плохо документирован, во-вторых оформление Excel таблицы из кода работает достаточно медленно. В связи с этим в большинстве случаев подойдет вариант с использованием шаблонов .xlt. Так как мы выводим файл для просмотра и печати, без расчета на сложные вычисления, диаграммы и прочие прелести жизни, мы можем привести формат всех ячеек к тексту и забыть про различные типы данных.
Читать далее