суббота, 15 марта 2014 г.

Как сделать TabControl без закладок.

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


1. Создаем класс, унаследованный от System.Windows.Forms.TabControl, в котором переопределяем метод WndProc. Нас интересует сообщение TCM_ADJUSTRECT, которое посылается TabControl'у для вычисления размера вместе с закладками. Все что нужно, чтобы закладки не рисовались это перехватить это сообщение и ответить, что все хорошо, все обработано. Проверка на DesignMode нужна чтобы в дизайнере вкладки все-таки рисовались.

    public partial class TablessTabControl : System.Windows.Forms.TabControl
    {
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x1328 && !DesignMode)
                m.Result = (IntPtr)1;
            else
            base.WndProc(ref m);
        }
    }

2. После компиляции проекта TablessTabControl появится в тулбоксе и  его можно будет использовать.


четверг, 13 марта 2014 г.

LIMIT в MSSQL

Наверное многие разработчики, работавшие с MySQL, недоумевают почему в MSSQL нет аналога инструкции LIMIT и как без нее вообще жить. Рассказываю как. Вот как сделать аналог LIMIT 5,10 для вот такой таблицы:


Вариант номер 1:
   
    SELECT top 10 * FROM [test].[dbo].[limit_test] WHERE [id] NOT IN (
    SELECT top 5 [id] FROM [test].[dbo].[limit_test] ORDER BY [id]
    ) ORDER BY [id]


Строки в .Net, что в них интересного

Всем, наверное, известно, что строки в .Net хоть и являются ссылочным типом, неизменяемы, что делает их поведение отчасти похожим на поведение значимых типов. То есть, вот в этом коде мы создали не две строки, а три:

            
            string s1 = "te";
            string s2 = "st";
            s1 = s1 + s2;

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

            string s1 = "hello";
            string s2 = s1;

            Console.WriteLine(s1);            
            Console.WriteLine(s2);

            Console.WriteLine();
                        
            s1 = "world";
            Console.WriteLine(s1);            
            Console.WriteLine(s2);

В этом примере неизменяемость строк приводит к не очень очевидным результатам. Как думаете, что будет выведено на экран? Правильный ответ:

            hello
            hello

            world
            hello

 И еще, чтобы окончательно запутать бедных программистов, тип string переопределяет оператор ==, чтобы он сравнивал не ссылки, а содержимое объектов. Что, впрочем, для строк очень часто одно и то же, что и сравнение по ссылке.
 Так почему строки сделали неизменяемыми, спросите вы. Причин несколько.


среда, 12 марта 2014 г.

Отличные интеллектуальные шутки.

Только что наткнулся на эти шутки. Не могу не поделиться.


Все 20 шуток под катом.


Как получить размер объекта в .Net

Вы все знаете, что в .Net память управляется CLR и многих, привычный для не управляемого кода вещей тут нет, например оператора sizeof. То есть, он, конечно, есть. Но умеет возвращать размеры только простых значимых типов типа char. При попытке натравить его на любой управляемый класс вы получите ошибку:

error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('System.Console')


Многие разработчики вообще не парятся что и сколько места занимает и на какой срок, но если вам интересно, то единственный более-менее достоверный  способ узнать объем памяти, занимаемый объектом, это сравнив размер используемой памяти до инициализации объекта и после, например:

            long mem = GC.GetTotalMemory(true);
            int[] intArray = new int[100000];
            mem = GC.GetTotalMemory(true) - mem;
            //В mem - размер объекта в байтах


Добавляем почти серверные контролы "на лету"

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


Как думаете, во что они превратятся на стороне клиента? На самом деле, в самые банальные HTML-контролы, которые при изменений состояния вызывают JavaScript функцию __doPostBack

Эта функция добавляется в HTML-код страницы автоматически, если на ней есть хоть один серверный контрол. Если же все контролы хотите генерировать самостоятельно, то можете написать что-то типа:


 

  

То есть, в том, чтобы получить чекбокс, который при изменений состояния будет отправлять страницу на сервер, ничего трудного нет. Достаточно написать что-то типа:

           
Response.Write("чекбокс");

            

Теперь переходим к более интересной части - как узнать о существовании этого чекбокса на сервере.


понедельник, 10 марта 2014 г.

Как сделать, чтобы можно было запустить только единственный экземпляр приложения.

Часто возникает необходимость ограничить приложение возможностью запуска только одного экземпляра. Сделать это можно несколькими способами, разной степени красивости и эффективности. Мне же, больше нравится вариант с использованием мьютекса. Для этого нужно в самое начало процедуры Main добавить несколько строчек:

            bool newMutexCreated = false;
            myMutex = new Mutex(false, "MyAppTestMutex", out newMutexCreated);
            if (!newMutexCreated)
            {
                Console.WriteLine("Только один экземпляр приложения может быть запущен!");
                Console.ReadLine();
                Environment.Exit(1);
            }

Ну а если уж делать все совсем красиво и правильно, то имя мьютекса должно быть уникально. Достичь этого можно использовав следующую конструкцию:

string mutexName = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();

К сожалению, цена подобной красоты - необходимость добавления двух дополнительных сборок: System.Reflection и System.Runtime.InteropServices;