четверг, 7 февраля 2013 г.

Как отображать изображение в заголовке столбца DataGridView

Один из способов сделать это использование события CellsPainting.  Чтобы нарисовать изображение для конкретной ячейки заголовка.


this.headerImages - ImageList изображения для столбцов


void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex != -1 && e.RowIndex == -1)
    {
        e.PaintBackground(e.ClipBounds, false);
        Point pt=e.CellBounds.Location;
        int offset=(e.CellBounds.Width-this.headerImages.ImageSize.Width)/2;
        pt.X += offset;
        pt.Y += 1;
        this.images.Draw(e.Graphics, pt, e.ColumnIndex);
// Для случая, если не хранить изображения в ImageList, e.Graphics.DrawImage (image, Pt);        e.Handled = true;
    }
}


пятница, 4 января 2013 г.

Форматирование строк (System.String.Format)


Сегодня я расскажу о том, как формировать строки, помещая в них значения переменных различных типов. Я думаю, вы знаете, что любое значение можно преобразовать в строку через метод ToString(). Например, так:
var a = 10.50;
var message = "Сумма = " + a;
Но, используя такой метод, вы можете получить строковое представление значения только в одном формате, определенном вашей текущей культурой (CultureInfo).
Сейчас мы рассмотрим, каким образом можно задавать формат для значений при формировании строки. Для этого в .NET есть встроенная возможность, представленная “записывающими” методами различных классов. К таким, например, относятся:
  • System.String.Format
  • Console.WriteLine
  • StreamWriter.Write
Я буду рассматривать форматирование на примере String.Format, но то же самое можно использовать и в остальных методах. Выглядит это так:
var a = 10.50;
var message = string.Format("Сумма = {0}", a);
Метод String.Format принимает первым параметром шаблон строки, в которую подставляются форматированные значения. Шаблон содержит маркеры – фигурные скобки, которые указывают, куда необходимо подставить значения. В простейшем случае этот маркер содержит одно число – номер параметра, который надо подставить (0 – соответствует первому параметру).
В следующем коде у меня производится формирование строки из двух параметров:
var a = 10.50;
var dt = new DateTime(2011, 09, 01);
var message = string.Format("Сумма = {0}, Дата = {1}", a, dt);
Но, как я уже сказал, мы также можем влиять на формат значений, которые вставляются в строку.
var a = 10.50;
var dt = new DateTime(2011, 09, 01);
var message = string.Format("Сумма = {0:c}, Дата = {1:d}", a, dt);
В этом примере я внутри маркера задал форматы для обоих значений: для суммы я указал формат Currency (“:c” внутри маркера), для даты – “краткий формат даты” (“:d” в маркере).
Это примеры встроенных в .NET форматов, и конечный результат их применения зависит от текущей культуры (CultureInfo), которая по умолчанию соответствует настройкам Windows. Если у вас в Windows выбраны российские региональные настройки, то в данном примере сумма выведется в рублях, а дата в российском формате даты.
Иногда бывает необходимо преобразовать набор чисел в строки таким образом, чтобы все строки были выравнены по левому или правому краю и имели равные длины. Числа при этом дополняются пробелами слева или справа:
var a1 = 1234;
var a2 = 12345;
Console.WriteLine(@"{0,5:d}", a1); //по правому краю
Console.WriteLine(@"{0,5:d}", a2); //по правому краю
Console.WriteLine(@"{0,-5:d}", a1);//по левому краю
Console.WriteLine(@"{0,-5:d}", a2);//по левому краю
В этом примере внутри шаблона указывается дополнительный параметр, через запятую после индекса параметра. Этот параметр указывает минимальное число символов, которое должно быть в строке. Если это положительное число, то строки выравниваются по правому краю, если отрицательное – по левому.
Встроенные форматы
Кроме приведенных форматов существует еще много других встроенных форматов:
КодТипОписание
c/CВалюта
d/DЦифровойТолько для целых типов, выводит целое (с “-“ для отрицательных)
e/EНаучныйВыводит число в экспоненциальном формате. Регистр буквы “E” влияет на регистр этой буквы при форматировании
f/FФиксированная точкаВыводит целое или дробное число
g/GОбщийВыбирает формат в соответствии с типом значения и размером значения – научный или фиксированная точка.
n/NРазделители групп разрядовВыводит целое или дробное число, но при этом отделяет группы разрядов
p/PПроцентУмножает число на 100 и выводит со знаком процентов
r/RОбратныйТолько плавающая точка и BigInt; переводит в строку таким образом, что значение можно без потерь точности преобразовать обратно
x/XШеснадцатиричныйТолько для целых, переводит в Hex-формат. Регистр буквы X влияет на регистр символов в выходной строке.
Пример использования можно посмотреть здесь:
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

Вместе с символом формата можно также указать число – точность:
var a = 1234.34542;
Console.WriteLine(@"{0:N3}", a);
В этом примере число указывает число символов после запятой.
Теперь посмотрим, какие есть встроенные форматы дат:
КодТипПример
dКороткая дата01.09.2011
DДлинная дата1 сентября 2011 г.
tКороткое время10:20
TДлинное время10:20:30
fДлинная дата/короткое время1 сентября 2011 г. 10:20
FДлинная дата/длинное время1 сентября 2011 г. 10:20:30
gКороткая дата/короткое время01.09.2011 10:20
GКороткая дата/длинное время01.09.2011 10:20:30
M/mМесяц и деньсентября 01
o/OОбратный2011-09-01T10:20:30.0000000
r/RRFC1123Thu, 01 Sep 2011 10:20:30 GMT
sДля сортировки2011-09-01T10:20:30
uЛокальное, в универсальном формате2011-09-01 10:20:30Z
UGMT1 сентября 2011 г. 6:20:30
YГод и месяцСентябрь 2011
При преобразовании чисел в строку при помощи встроенных форматов .NET использует правила, которые заданы в текущем CultureInfo.
CultureInfo влияет на множество аспектов – символ валюты, символы разделителей, символ “-”, количество знаков после запятой по умолчанию. То же самое и с датами. CultureInfo определяет символы разделителей, имена месяцев и дней недели, форматы времени.
Таким образом, если вы используете для форматирования значений только встроенные форматы, то вы автоматически получите глобализацию преобразований чисел и дат в строки. В каждой стране это преобразование будет происходить по своим правилам.
С другой стороны, если вам необходимо при преобразовании применить другую культуру, то это, как правило, можно сделать, используя соответствующую перегрузку метода.
var a = 10.50;
var dt = new DateTime(2011, 09, 01);
var info = new CultureInfo(1033);
var message = string.Format(info, "Сумма = {0:c}, Дата = {1:d}", a, dt);
В этом примере я применил другую культуру для преобразования значений.
Свой формат
Если нас не устраивает встроенный формат, то можно задавать формат самостоятельно. Суть этого процесса в том, что вы с помощью специальных символов и обычного текста создаете строку формата, эти символы я дальше покажу в таблице, а пока пример.
Я произведу форматирование серийного номера, который, например, в базе данных лежит в виде целого Int32:
var message = string.Format("Серийный = {0:000-000-000}", a);
Console.WriteLine(message);
Здесь у меня внутри маркера 000-000-000 – это шаблон, в нем каждый 0 – это специальный символ цифры (вставляется цифра, если она есть, либо ‘0’), дефис – это просто промежуточный текст.
var a = 2345.43;
var message = string.Format(@"Сумма = {0:#.00р\.}", a);
Console.WriteLine(message);
Здесь строка формата “#.00р\.”. В ней символ “#”, который я могу опустить, означает цифры (до запятой в этом примере), “.” – это разделитель дроби, “00” – означает “взять и показать две цифры после запятой”, “р” – просто текст – рубли, “\.” – просто точка; я использовал символ “\” перед точкой, т. к. точка – специальный символ.
Вот краткое описание специальных символов, которые можно использовать в своих шаблонах:
КодТипПримерРезультатОписание
Исходное число1234,567
0Цифра или ноль00000.000001234, 5670Если нет цифры, то вместо маркера ставится 0
0.001234,56
#Цифра#####.####1234,567Если нет цифры, то вместо маркера ничего не ставится
#.##1234,56
.Разделитель дроби0.#1234,5Интерпретируется только первая из точек
,Разделитель тысяч00,0 или 0,000 или 00,0,0001 234Интерпретируется только первая из запятых. Слева и справа от запятой должны быть “0” или “#”, но не обязательно рядом
,.Масштабирование0,.01,2Число уменьшается в 1000^N раз, где N – число запятых, точка позволяет задать дробную часть.
0,1Если дробной части нет, запятые ставятся в конце
0,,.0000,001
%Процент0%123456%Умножает на 100 и добавляет знак процента
eЭкспонента00.0e+0012,3e+02Научный формат, цифры после “E” задают число разрядов порядка
;Разделитель секций0.##;(0.#);ноль1234,56Позволяет задать три секции: отдельно для положительных, отрицательных чисел и нуля
0.##;(0.#);ноль(1234,56)Для значения “-1234.56”
0.##;(0.#);нольНульДля значения “0”
\Escape\.##.#\..1234,5.Дает возможность вставлять спец-символы как обычный текст
Специальные символы можно комбинировать. К примеру, шаблон “000,0,.##e+00;(0.#);ноль” даст результатом для числа “123456789.1234567” строку “1234,57e+02”.
Число положительное, поэтому будет использоваться первая секция. Сначала будет произведено деление на 1000 (символы “,.”), затем приведение к экспоненте (“e+00”), при котором будет оставлено 4 цифры слева от точки (четыре нуля), затем будет произведено округление до сотых (“.##”), и в конце разделение тысяч (первая запятая).
Кроме специальных символов в шаблон можно вставлять обычный текст, так я вставил скобки в шаблон с разделителем секций. Текст можно вставлять в любое место.
Стоит обратить внимание еще на два момента:
1. Eсли количество цифр целой части больше числа символов “0” и “#” слева от точки в шаблоне, то целая часть выводится все равно полностью. При этом лишние левые цифры ставятся в соответствие крайнему символу “0” или “#”. Например, используя шаблон “(#)##” для числа 12345, получим строку “(123)45”.
2. Если в числе нет целой части, например в числе 0,34, то шаблон “#.##” даст результат “,34”. Чтобы перед разделителем дроби был ноль, необходимо слева от точки использовать маркер “0”, как, например, здесь “0.##”.
Теперь посмотрим, какой арсенал у нас имеется для форматирования дат своим форматом. Здесь такой же принцип – для построения шаблона используются специальные символы.
КодТипРезультатОписание
Значение01.01.2001 14:20:30.1234
yГод 0-991
yyГод 00-9901
yyyyГод, 4 цифры2001
MМесяц 1-121
MMМесяц 01-1201
dДень 1-311
ddДень 01-3101
hЧас 1-122
hhЧас 01-1202
HЧас 1-2414
HHЧас 01-2414
mМинута 0-5920
mmМинута 00-5920
sСекунда 0-5930
ssСекунда 00-5930
f – ffffffДоли секунды12 (для шаблона ff)Количество f соответствует количеству разрядов долей секунды
F-FFFFFFДоли секунды, если они не равны 012 (для шаблона FF)Количество F соответствует количеству разрядов долей секунды
MMMСокращенное имя месяцаянв
MMMMИмя месяцаЯнварь
dddКороткое имя дня неделиПн
ddddИмя дня неделипонедельник
ttМаркер для  “AM” и “PM” 12-часового форматаPM
zzСмещение временное зоны, короткое+03
zzzСмещение временное зоны, полное+03:00
ggЭраA.D.
:Разделитель времени14:20:30
/Разделитель даты01.01.2001
\EscapeДает возможность вставлять спец-символы как обычный текст
%Custom Format“%d” даст “1”Указывается перед символом, чтобы указать, что это не встроенный формат
Разделители даты и времени – это специальные символы, при форматировании они будут заменены на соответствующие символы CultureInfo.
При формировании строки специальные символы и их последовательности можно размещать как угодно и совместно с обычным текстом.
Вот несколько примеров:
Console.WriteLine(@"{0:dd/MM/yyyy}", dt); // 01.01.2001
Console.WriteLine(@"{0:dd/MM/yyyy HH:mm:ss}", dt); // 01.01.2001 10:20:30
Console.WriteLine(@"{0:dd/MM/yyyy HH часов}", dt); // 01.01.2001 10 часов
Console.WriteLine(@"{0:MMMM yyyy г.}", dt); // Январь 2001 г.
Что еще важно знать.
1. Те же самые строки форматов можно использовать, вызывая перегрузку метода ToString у чисел и дат.
var a = 10.50;
var message = a.ToString("c");
2. Еще раз напоминаю, что CultureInfo влияет на то, как будут работать встроенные форматы. Но кроме того, CultureInfo влияет и на то, как ведут себя специальные символы и их комбинации во встроенных форматах.
Например, от этого зависят имена месяцев и дней недели, символ разделителя дат и времени, символы разделителя дроби и разделитель тысяч и др.
3. По возможности старайтесь использовать встроенные форматы. Это сделает ваше приложение более гибким.

Источник: http://sharp-net.ru/blog/system-string-format/


Форматирование строк в языке c#

До сих пор для кода примеров этой книги нами было написано множество классов, и обычно они реализовывали метод ToString () для того, чтобы отображать содержимое экземпляров этих классов. Однако довольно часто у пользователей возникает потребность отобразить содержимое переменных другим способом — в зависимости от национальных и культурных стандартов. Класс .NET System. DateTime представляет наиболее очевидный пример этого. Например, может понадобиться отобразить одну и ту же дату как 10 June 2007, 10 Jun 2007, 6/10/07 (США), 10/6/07 (Великобритания), или 10.06.2007 (Германия).

Аналогично, структура Vector из главы 3 реализует метод Vector. ToString () для отображения вектора в формате (4, 56, 8). Однако существует другой общепринятый способ записи векторов — в форме 4i + 5 б j + 8 k. Если вы хотите, чтобы написанные вами классы были дружественными к пользователю, они должны предлагать средства для отображения своихстроковых представлений в любом из форматов, которые могут понадобиться пользователю. Исполняющая система .NET определяет стандартный способ достижения этого — интерфейс IFormattable. Описание способа добавления этого важного свойства к пользовательским классам и структурам и представляет собой тему настоящего раздела.
Как вам известно, формат, в котором нужно отобразить значение переменной, следует указывать при вызове Console .WriteLine (). Таким образом, мы используем здесь этот метод в качестве примера, хотя большая часть обсуждения относится к любой ситуации, когда возникает потребность в форматировании строки. Например, если требуется отобразить значение переменной в окне списка или текстовом поле, то при этом для получения соответствующего строкового представления переменной обычно используется метод String.Format (). Однако действительные спецификато¬ры формата, применяемые для указания конкретного формата, идентичны тем, что передаются методу Console .WriteLine (). Поэтому мы сосредоточимся на примере Console .WriteLine (). Начнем с рассмотрения того, что происходит, когда форматная строка применяется к примитивному типу, а отсюда станет ясно, как следует включать спецификаторы формата для пользовательских классов и структур.
В главе 2 строки формата применялись в Console. Write () и Console. WriteLine () следующим образом:
double d = 13.45;
int i = 45;
Console.WriteLine("Значение double равно {0,10:E}, a int содержит {1}", d, i); 
Сама форматная строка содержит большую часть отображаемого текста, но всякий раз, когда в нее должно быть вставлено значение переменной, в фигурных скобках указывается индекс. В фигурные скобки может быть включена и другая информация, относящаяся к формату данного элемента, например, как та, что описана ниже.
Количество символов, которое займет представление элемента, снабженное префиксом-запятой. Отрицательное число указывает, что элемент должен быть выровнен по левой границе, а положительное — по правой. Если элемент на самом деле занимает больше символов, чем ему отведено форматом, он отображается полностью.
Спецификатор формата предваряется двоеточием. Это указывает, каким образом необходимо отформатировать элемент. Например, можно указать, должно ли число быть форматировано как денежное значение либо его следует отобразить в научной нотации.
В табл. 8.3 перечислены часто используемые спецификаторы формата для числовых типов, которые уже кратко упоминались в главе 2.
Таблица 8.3. Часто используемые спецификаторы формата для числовых типов
Спецификатор
Применяется к
Значение
Пример
с
Числовым типам
Символ местной валюты
$4834.50 (США) £4834.50 (Великобритания)
D
Целочисленным типам только
Обычное целое
4834
Е
Числовым типам
Экспоненциальная (научная) нотация
4.834Е+003
F
Числовым типам
С фиксированной десятичной точкой
4384.50
G
Числовым типам
Обычные числа
4384.5
N
Числовым типам
Формат чисел, принятый в данной местности
4,384.50 (Великобритания/США) 4 384,50 (континентальная Европа)
Р
Числовым типам
Процентная нотация
432,000.00%
X
Целочисленным типам только
Шестнадцатеричный формат
1120 (если нужно отобразить 0x1120, то Ох нужно выводить отдельно)
Если целое число требуется дополнить нулями, можно воспользоваться спецификатором формата 0 (ноль), повторив его столько раз, сколько составляет требуемая длина. Например, спецификатор формата 0000 отобразит 3 в виде 0003, 99 — в виде 0099 и так далее.
Мы не можем привести здесь полный список, поскольку другие типы данных добавляют свои собственные спецификаторы. Целью настоящего раздела будет показать, как определять собственные спецификаторы для пользовательских классов.


суббота, 24 ноября 2012 г.

Stopwatch (время выполнения, мониторинг)


Измерить время выполнения можно так


using System.Diagnostics;  
...
...
...

Stopwatch sw = new Stopwatch();
  sw.Start();

... Измеряемый Код

  sw.Stop();
  MessageBox.Show(sw.Elapsed.Minutes + "Min " + sw.Elapsed.Seconds + "Sec " + sw.Elapsed.Milliseconds + "ms");

пятница, 23 ноября 2012 г.

Icon Size - Windows Forms Applications

Circumstance:Icon Version:
Control Box16x16x256
Taskbar16x16x256
Notify Icon32x32x256, shrunk down (see below)
Desktop Shortcut32x32x256 (Normal sized icons)
48x48x256 (Large sized icons)
Add/Remove Programs16x16x256
Folder Browse dialog16x16x256

CSV и DataTable


Создание и чтение CSV файла.

Первая строка в CSVфайле содержит имена столбцов и типы в формате
name1:String;name2:String;name3:Int32;name4:Decimal;name5:DateTime

Пример:
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
CSV.CreateFile(table, @"c:\test.csv");
DataTable dt = CSV.LoadFile(@"c:\test.csv");

--------------------------------------------------------------------------------------------------------
using System;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;

public static class CSV
    {
        public static void CreateFile(DataTable dt, String strFilePath)
        {
            #region Export DataTable to CSV

            using (StreamWriter sw = new StreamWriter(strFilePath, false))
            {
                int iColCount = dt.Columns.Count;

                // First we will write the headers.
                for (int i = 0; i < iColCount; i++)
                {
                    sw.Write(String.Format(@"{0}:{1}", dt.Columns[i], dt.Columns[i].DataType.ToString().Replace(@"System.", "")));
                    if (i < iColCount - 1)
                    {
                        sw.Write(";");
                    }
                }
                sw.Write(sw.NewLine);

                // Now write all the rows.
                foreach (DataRow dr in dt.Rows)
                {
                    for (int i = 0; i < iColCount; i++)
                    {
                        if (!Convert.IsDBNull(dr[i]))
                        {
                            sw.Write(dr[i].ToString());
                        }
                        else
                        {
                            sw.Write(@"");
                        }
                        if (i < iColCount - 1)
                        {
                            sw.Write(";");
                        }
                    }
                    sw.Write(sw.NewLine);
                }
                sw.Close();
            }

            #endregion
        }


        public static DataTable LoadFile(String strFilePath)
        {
            if (!File.Exists(strFilePath))
            {
                return null;
            }

            #region Export CSV to DataTable

            DataTable dt = new DataTable();

            FileInfo f = new FileInfo(strFilePath);
            double readSize = 0;

            using (var sr = new StreamReader(strFilePath, System.Text.Encoding.ASCII))
            {
                String line;
                bool setColums = false;
                char[] splRow = new char[] { ';' };
                char[] splCol = new char[] { ':' };

                Int32 cols = 0;
                while (sr.Peek() >= 0)
                {
                    try
                    {
                        line = sr.ReadLine();
                        readSize += line.Length;

                        if (string.IsNullOrEmpty(line)) continue;
                        var values = line.Split(splRow, StringSplitOptions.None);

                        if (!setColums)
                        {
                            setColums = true;
                            cols = values.Length;
                            String colName;
                            Type colType;
                            for (int colNum = 0; colNum < cols; colNum++)
                            {
                                if (values[colNum].IndexOfAny(splCol) != -1)
                                {
                                    var v = values[colNum].Split(splCol);
                                    colName = v[0];
                                    colType = Type.GetType(@"System." + v[1], false, false);
                                    dt.Columns.Add(colName, colType != null ? colType : typeof(String));
                                }
                                else
                                {
                                    dt.Columns.Add(values[colNum]);
                                }
                            }
                        }
                        else
                        {
                            try
                            {
                                dt.Rows.Add(values);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message + "\n" + line);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }

            return dt;

            #endregion
        }
    }

Запуск одного экземпляра приложения

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


using System;
using System.Windows.Forms;
using System.Threading;

namespace OneCopyOfApp
{
    static class Program
    {
        private static Mutex m_instance;
        private const string m_appName = "NameOfMyApp";

        [STAThread]
        static void Main()
        {
            bool tryCreateNewApp;
            m_instance = new Mutex(true, m_appName, 
                    out tryCreateNewApp);
            if (tryCreateNewApp)
            {
                Application.EnableVisualStyles();
                Application.
                  SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
                return;
            }          
        }
    }
}



Есть второй, более безопасный в отношении атак способ. Основан он на библиотеках VB. Для начала добавьте ссылку на сборку Microsoft.VisualBasic.dll.
Для удобства вынести в начало проекта пространство имен Microsoft.VisualBasic.ApplicationServices. Ну а сам код следующий (обратите внимание каким образом мы вызываем метод Run())


using System;
using System.Windows.Forms;
using System.Threading;
using Microsoft.VisualBasic.ApplicationServices;

namespace OneCopyOfApp
{
    public class OneInstanceApp : 
        WindowsFormsApplicationBase
    {
        private SingleInstanceApplication()
        {
            base.IsSingleInstance = true;
        }

        public static void Run(Form form,
            StartupNextInstanceEventHandler startupHandler)
        {
            OneInstanceApp app = 
                new OneInstanceApp();
            app.MainForm = form;
            app.StartupNextInstance += startupHandler;
            app.Run(Environment.GetCommandLineArgs());
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            OneInstanceApp.Run(new Form1(),
                StartupNextInstanceHandler);
        }

        static void StartupNextInstanceHandler(
            object sender, StartupNextInstanceEventArgs e)
        {
            MessageBox.Show(e.CommandLine[0]);
        }
    }
}