о жизни, вебе, друзьях, семье и многом другом…
RSS icon Email icon Home icon
  • Экспорт содержимого GridView в Excel

    Очень часто при разработке веб-приложений на asp.net возникает задача осуществления эскпорта данных из GridView в экселевский файл. При этом каждый начинает придумывать свой велосипед, потому что можно придумать с десяток различных методов как это сделать. Я предлагаю на мой взгляд самый простой вариант.

    Сразу хочу отметить, весь приведенный код написан на VB.NET. Так произошло не потому, что мне так нравится, а потому что так принято в компании, в которой я работаю. Если вы хотите получить этот код на C#, просто воспользуйтесь онлайн конвертером, например, http://www.developerfusion.com/tools/convert/vb-to-csharp/.

    Итак, что нам нужно:

    1. Вспомогательный класс. Я назвал его ExcelExportHelper. Его код приведен ниже

    Imports System
    Imports System.Data
    Imports System.Configuration
    Imports System.IO
    Imports System.Web
    Imports System.Web.Security
    Imports System.Web.UI
    Imports System.Web.UI.WebControls
    Imports System.Web.UI.WebControls.WebParts
    Imports System.Web.UI.HtmlControls
    
    Public Class ExcelExportHelper
    
        Public Shared Sub PrepareAndExport(ByVal fileTitle As String, ByVal gv As GridView, ByVal showGrid As Boolean)
            Dim filename As String
            filename = String.Format("{0}_{1}.xls", fileTitle, DateTime.Now().ToString("yyyyMMdd_HHmmss"))
            gv.AllowPaging = False
            gv.DataBind()
            ExcelExportHelper.Export(filename, gv, showGrid)
        End Sub
    
        Public Shared Sub Export(ByVal fileName As String, ByVal gv As GridView, ByVal showGrid As Boolean)
            HttpContext.Current.Response.Buffer = True
            HttpContext.Current.Response.ClearContent()
            HttpContext.Current.Response.ClearHeaders()
            'HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
            HttpContext.Current.Response.ContentType = "application/ms-excel"
            HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename = " + fileName)
    
            Dim sw As StringWriter = New StringWriter
            Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
            '  Create a form to contain the grid
            Dim table As Table = New Table
            If (showGrid) Then
                table.GridLines = gv.GridLines
            Else
                table.GridLines = GridLines.None
            End If
    
            '  add the header row to the table
            If (Not (gv.HeaderRow) Is Nothing) Then
                PrepareControlForExport(gv.HeaderRow)
                table.Rows.Add(gv.HeaderRow)
            End If
            '  add each of the data rows to the table
            For Each row As GridViewRow In gv.Rows
                PrepareControlForExport(row)
                table.Rows.Add(row)
            Next
            '  add the footer row to the table
            If (Not (gv.FooterRow) Is Nothing) Then
                PrepareControlForExport(gv.FooterRow)
                table.Rows.Add(gv.FooterRow)
            End If
            '  render the table into the htmlwriter
            table.RenderControl(htw)
            '  render the htmlwriter into the response
            HttpContext.Current.Response.Write(sw.ToString)
            HttpContext.Current.Response.End()
        End Sub
    
        ' Replace any of the contained controls with literals
        Private Shared Sub PrepareControlForExport(ByVal control As Control)
            Dim i As Integer = 0
            Do While (i < control.Controls.Count)
                Dim current As Control = control.Controls(i)
                If (TypeOf current Is LinkButton) Then
                    control.Controls.Remove(current)
                    control.Controls.AddAt(i, New LiteralControl(CType(current, LinkButton).Text))
                ElseIf (TypeOf current Is ImageButton) Then
                    control.Controls.Remove(current)
                    control.Controls.AddAt(i, New LiteralControl(CType(current, ImageButton).AlternateText))
                ElseIf (TypeOf current Is HyperLink) Then
                    control.Controls.Remove(current)
                    control.Controls.AddAt(i, New LiteralControl(CType(current, HyperLink).Text))
                ElseIf (TypeOf current Is DropDownList) Then
                    control.Controls.Remove(current)
                    control.Controls.AddAt(i, New LiteralControl(CType(current, DropDownList).SelectedItem.Text))
                ElseIf (TypeOf current Is CheckBox) Then
                    control.Controls.Remove(current)
                    control.Controls.AddAt(i, New LiteralControl(CType(current, CheckBox).Checked))
                    'TODO: Warning!!!, inline IF is not supported ?
                End If
                If current.HasControls Then
                    PrepareControlForExport(current)
                End If
                i = (i + 1)
            Loop
        End Sub
    End Class

    Вкратце, что делает этот класс: есть два статичных публичных метода: PrepareAndExport и Export.

    Метод PrepareAndExport убирает в GridView разбивку на страницы, для того чтобы получить в экселевском файле все записи со всех страниц. Так же этот метод определяет имя целевого файла. В моем случае к переданной строковой переменной будет прибавлено текущее время. После этого PrepareAndExport вызывает метод Export, который собственно и генерирует output. PrepareControlForExport нужен для замены пользовательских контролов в GridView, эти контролы нужны на веб-странице, но совершенно бессмысленны в Excel.

    2. Размещаем на asp странице кнопку для осуществления экспорта:

    
    <asp:ImageButton ID="ibExportToExcel" runat="server" 
    
        ImageUrl="~/Img/export-excel.png"
    
        OnClick="ibExportToExcel_Click">
    

    Привязываем в ней onClick событие ibExportToExcel_Click.

    3. Реализуем это событие в code-behind страницы:

    
    Protected Sub ibExportToExcel_Click(ByVal sender As System.Object, 
    
             ByVal e As System.Web.UI.ImageClickEventArgs)
         ExcelExportHelper.PrepareAndExport(Page.Title, gvContent, True)
     End Sub
    

    Ну вот собственно и все, теперь при нажатии на кнопку экспорта произойдет вызов метода PrepareAndExport класса ExcelExportHelper. В качестве параметров этому методу передаем Page.Title (либо любую другую строку в качестве имени файла), GridView, который нужно экспортировать, и true (отображать границы таблицы в экселе).

     

    Теперь несколько “НО”:

    1. Если у клиента установлен Microsoft Excel 2007, то при открытии сгенерированного файла мы получим Security Alert.

    image

    Дело в том, что мы пытаемся подсунуть Excel-ю сгенерированный нами html файл. Он это понимает и сообщает, что содержание файла не соответствует его расширению. К сожалению, нормального пути обойти это сообщение нет. Единственное, что можно сделать – покопаться в реестре:

    [HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security]

    “ExtensionHardening”=dword:00000000

       1. Open your Registry (Start -> Run -> regedit.exe)

       2. Navigate to HKEY_CURRENT_USER\SOFTWARE\MICROSOFT\OFFICE\12.0\EXCEL\SECURITY

       3. Right click in the right window and choose New -> DWORD

       4. Type “ExtensionHardening” as the name (without the quotes)

       5. Verify that the data has the value “0?

    2. Если кнопка ibExportToExcel находится в Update Panel, то необходимо добавить ее в триггер:

    <asp:UpdatePanel ID="upContent" runat="server" UpdateMode="Always">
            <Triggers>
                <asp:PostBackTrigger ControlID="ibExportToExcel" />
            </Triggers>

  • Мой первый сайт

    Свой первый сайт я сделал в 2001 году. Он был посвящен поездке группы школьников из обычной самарской школы в замечательный американский городок Eaton Rapids. Я, естественно, был среди этих школьников :)

    У сайта было две версии: оригинальная, сделанная в течении пары недель в начале 2001 года, и вторичная, сделанная лично мной несколько позже. Вообще говоря, над оригинальным сайтом трудилось порядка 10-15 человек, и он был сделан, как говорится, "с душой", но версткой занимался в основном я.

    Сегодня я случайно нашел обе версии на своем необъятном переносном жестком диске и решил, что должен поделиться с общественностью)

    Оригинальная версия лежит по адресу: http://www.dimants.ru/slp_iatp_ru

    Переделанный вариант по адресу: http://www.dimants.ru/slp_iatp_ru_2

    Должен отметить, что, посмотрев на оба эти сайта сейчас 4 марта 2009 года, мне кажется, что они сделаны совсем неплохо. Особенно оригинальный вариант. Переделанный потерял какую-то часть своей самобытности и стал обычным непонятным фиолетовым пятном :). К тому же он работает только в самом свежем браузере IE 5!

     

    Товарищи, прокомментируйте, что вы думаете :)

  • Регулярное выражение

    Только что написал “маленькое” регулярное выражение:

    ([A-Z]{1}[A-Z0-9]{2,3})[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+([0-9.]+)[ ]+([0-9.]+)[ ]+([0-9.]+)[ ]+([0-9/]+)[ ]+([ABCD-]{2})[ ]*[\n\r]+[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9.]+)[ ]+([0-9.]+)[ ]+([0-9.]+)[ ]+([0-9.]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]+[ ]+([0-9.]+)[ ]+([0-9.]+)

    В принципе, ничего сложного, но боюсь посмотреть на того человека, который попытается в нем разобраться. Или даже на себя через недельку…

  • Парадокс Монти Холла однако…

    Совсем недавно узнал о таком понятии теории вероятности, как Парадокс Монти Холла.

    Вероятно, для многих людей – это очевидное понятие, но для меня стало настоящим открытием.

    Как всегда, некоторые теоретические сведения с Wikipedia (ссылка на статью целиком):

    Парадокс Монти Холла — одна из известных задач теории вероятностей, решение которой, на первый взгляд, противоречит здравому смыслу. Задача формулируется как описание гипотетической игры, основанной на американском телешоу «Let’s Make a Deal», и названа в честь ведущего этой передачи. Наиболее распространенная формулировка этой задачи, опубликованная в 1990 году в журнале Parade Magazine, звучит следующим образом:

    Представьте, что вы стали участником игры, в которой вам нужно выбрать одну из трех дверей. За одной из дверей находится автомобиль, за двумя другими дверями — козы. Вы выбираете одну из дверей, например, номер 1, после этого ведущий, который знает, где находится автомобиль, а где — козы, открывает одну из оставшихся дверей, например, номер 3, за которой находится коза. После этого он спрашивает вас, не желаете ли вы изменить свой выбор и выбрать дверь номер 2. Увеличатся ли ваши шансы выиграть автомобиль, если вы примете предложение ведущего и измените свой выбор ?

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

    При решении этой задачи обычно рассуждают примерно так: после того, как ведущий открыл дверь, за которой находится коза, автомобиль может быть только за одной из двух оставшихся дверей. Поскольку игрок не может получить никакой дополнительной информации о том, за какой дверью находится автомобиль, то вероятность нахождения автомобиля за каждой из дверей одинакова, и изменение первоначального выбора двери не дает игроку никаких преимуществ. Однако такой ход рассуждений неверен. Если ведущий всегда знает, за какой дверью что находится, всегда открывает ту из оставшихся дверей, за которой находится коза, и всегда предлагает игроку изменить свой выбор, то вероятность того, что автомобиль находится за выбранной игроком дверью, равна 1/3, и, соответственно, вероятность того, что автомобиль находится за оставшейся дверью, равна 2/3. Таким образом, изменение первоначального выбора увеличивает шансы игрока выиграть автомобиль в 2 раза. Этот вывод противоречит интуитивному восприятию ситуации большинством людей, поэтому описанная задача и называется парадоксом Монти Холла.

    (По ссылке полная статья)

    Так вот, для меня этот парадокс совсем-совсем неочевиден, и мне стало интересно попробовать его подтвердить (если можно так выразиться) эмпирическим образом. 

    Для этого было написано маленькое php приложение. Те, кому это интересно, могут попробовать выполнить его на своей машине. Парадокс ожидаемо подвердился, но от того для меня более понятным не стал :)

    Ниже листинг программы

    <?php
    /*
    Представьте, что вы стали участником игры, в которой вам нужно выбрать
    одну из трех дверей. За одной из дверей находится автомобиль, за двумя
    другими дверями - козы. Вы выбираете одну из дверей, например, номер 1,
    после этого ведущий, который знает, где находится автомобиль, а где -
    козы, открывает одну из оставшихся дверей, например, номер 3, за которой
    находится коза. После этого он спрашивает вас, не желаете ли вы
    изменить свой выбор и выбрать дверь номер 2. Увеличатся ли ваши шансы
    выиграть автомобиль, если вы примете предложение ведущего и измените
    свой выбор ?
    */

    //количество эмпирических выборок
    $iters = 10000;

    //количество вариантов выбора (в изначальной задаче - 3)
    $number_of_choices = 3;

    //угадали, если изменим решение после открытия всех дверей, кроме двух
    $true = 0;

    //не угадали, если изменим решение после открытия всех дверей, кроме двух
    $false = 0;

    //начинаем выборку
    for ($i = 0; $i< $iters; $i++)
    {
     //правильный ответ - случайное число от 1 до $number_of_choice
     $answer = rand(1,$number_of_choices);

     //наш выбор - случайно число от 1 до $number_of_choice
     $choice = rand(1,$number_of_choices);
     
     //массив открытых вариантов
     $opened = array();

     //открываем все варианты, кроме нашего выбора и правильного ответа
     //либо, если наш выбор = правильный ответ, правильный ответ и любой неправильный вариант
     for ($j=0; $j< $number_of_choices - 2; $j++)
     {
      $generated = 0;
      while (($generated!=0) && ($generated!=$answer) &&($generated!=$choice))
      {
       $generated = rand(1, $number_of_choices);
      }

      $opened[] = $generated;
     }
     //теперь проверяем, что будет, если мы изменим решение
     if ($choice == $answer)
     {
      //если мы изначально угадали
      $false++;
     }
     else
     {
      //если мы изменили решение
      $true++;
     }
    }

    echo "Если мы изменим решение, то угадаем с вероятностью:<br><b>$true/$iters</b><br>";
    echo "Если мы сохраним изначальное решение, то угадаем с вероятностью:<br><b>$false/$iters</b><br>";

     

    ?>

  • Новый сайт

    www.ladachess.ru

    Дизайн и верстка: Дмитрий Шуршилин

     

    Программирование: Я

  • Реализация Польской Инверсной Записи (ПОЛИЗ) на PHP

    Польская Инверсная Запись (ПОЛИЗ) или Обратная польская нотация (ОПН) — форма записи математических выражений, в которой операнды расположены перед операторами.
    Полностью получить информацию о том, что это такое можно на соответствующей странице Wikipedia (http://ru.wikipedia.org/wiki/Обратная_польская_запись).
    Я же здесь приведу общие сведения, взятые со страницы http://algolist.manual.ru/maths/misc/revpn.php.

    Общие теоретические сведения

    Обpатная польская нотация

    Одной из главных пpичин, лежащих в основе появления языков пpогpаммиpования высокого уpовня, явились вычислительные задачи, тpебующие больших объёмов pутинных вычислений. Поэтому к языкам пpогpаммиpования пpедъявлялись тpебования максимального пpиближения фоpмы записи вычислений к естественному языку математики. В этой связи одной из пеpвых областей системного пpогpаммиpования сфоpмиpовалось исследование способов выpажений. Здесь получены многочисленные pезультаты, однако наибольшее pаспpостpанение получил метод тpансляции с помощью обpатной польской записи , котоpую пpедложил польский математик Я. Лукашевич.

    Пример

    Пусть задано пpостое аpифметическое выpажение вида:
    (A+B)*(C+D)-E (1)
    Пpедставим это выpажение в виде деpева, в котоpом узлам соответствуют опеpации, а ветвям - опеpанды. Постpоение начнем с коpня, в качестве котоpого выбиpается опеpация, выполняющаяся последней. Левой ветви соответствует левый опеpанд опеpации, а пpавой ветви - пpавый. Деpево выpажения (1) показано на pис. 1.
    pис. 1
     
    Совеpшим обход деpева, под котоpым будем понимать фоpмиpование стpоки символов из символов узлов и ветвей деpева. Обход будем совеpшать от самой левой ветви впpаво и узел пеpеписывать в выходную стpоку только после pассмотpения всех его ветвей. Результат обхода деpева имеет вид:
    AB+CD+*E- (2)
    Хаpактеpные особенности выpажения (2) состоят в следовании символов опеpаций за символами опеpандов и в отсутствии скобок. Такая запись называется обpатной польской записью.
    Обpатная польская запись обладает pядом замечательных свойств, котоpые пpевpащают ее в идеальный пpомежуточный язык пpи тpансляции. Во-пеpвых, вычисление выpажения, записанного в обpатной польской записи, может пpоводиться путем однокpатного пpосмотpа, что является весьма удобным пpи генеpации объектного кода пpогpамм. Напpимеp, вычисление выpажения (2) может быть пpоведено следующим обpазом:
    #
    Анализиpуемая стpока
    Действие
    A B + C D + * E -
    r1=A+B
    1
    r1 C D + * E -
    r2=C+D
    2
    r1 r2 * E -
    r1=r1*r2
    3
    r1 E -
    r1=r1-E
    4
    r1
    Вычисление окончено
    Здесь r1, r2 - вспомогательные пеpеменные.
     
    Во-втоpых, получение обpатной польской записи из исходного выpажения может осуществляться весьма пpосто на основе пpостого алгоpитма, пpедложенного Дейкстpой. Для этого вводится понятие стекового пpиоpитета опеpаций(табл. 1):
    Таблица 1
    Операция
    Приоритет
    (
    0
    )
    1
    +|-
    2
    *|/
    3
    **
    4
     
    Пpосматpивается исходная стpока символов слева напpаво, опеpанды пеpеписываются в выходную стpоку, а знаки опеpаций заносятся в стек на основе следующих сообpажений:
    а) если стек пуст, то опеpация из входной стpоки пеpеписывается в стек;
    б) опеpация выталкивает из стека все опеpации с большим или pавным пpиоpитетом в выходную стpоку;
    в) если очеpедной символ из исходной стpоки есть откpывающая скобка, то он пpоталкивается в стек;
    г) закpывающая кpуглая скобка выталкивает все опеpации из стека до ближайшей откpывающей скобки, сами скобки в выходную стpоку не пеpеписываются, а уничтожают дpуг дpуга.
    Пpосматpиваемый
    символ
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Входная строка
    (
    A
    +
    B
    )
    *
    (
    C
    +
    D
    )
    -
    E
     
    Состояние
    стека
    (
    (
    +
    (
    +
    (
     
    *
    (
    *
    (
    *
    +
    (
    *
    +
    (
    *
    *
    -
    -
     
    Выходная
    строка
     
    A
     
    B
    +
       
    C
     
    D
    +
    *
    E
    -
     

    Реализация на PHP

    При реализации использован PHP 5.
    По сути, система нужна для того, чтобы вводить арифметические выражение в свободной форме ("(12-32)+23/(11-2)") и получать правильный результат
    Исходное приложение целиком можно скачать отсюда.
    В системе используются следующие классы:
    1. Calculator – собственно сама реализация полиза
    2. PolizItem – реализует один элемент входной строки – это может быть операция («*/-+()») или операнд: число (1, 2.12, 3.432,23432423) или ссылка на число (A2, C4, F23)
    3. PolizConstants
    4. DataTable - класс для отображения таблицы данных. Эта таблица реализована для показа возможностей полиза по оперированию не только числовыми значениями, но и ссылками на значения в каких-либо источниках данных.
     Если у кого-то возникнут вопросы по работе этого приложения- прошу обращаться ко мне
  • PHPCLUB.RU

    :) Я нашел упоминание о своем сайте на форуме www.phpclub.ru :)

    http://www.phpclub.ru/talk/showthread.php?s=&threadid=100067

    Кстати, моя статья об использовании flv-плеера на сайте видимо пользуется определенной популярностью, уже 5 человек постучались мне в аську с благодарностями, а вот теперь и на пхп клубе))))

     
     

  • Лестница IT-рангов


    взято с http://www.ms-dynamics.ru/images/stories/blogs/stairs.jpg

  • Опечатка по Фрейду:)

     

    И Гугл туда же

  • Delphi For PHP

    Нашел в инете статью Delphi for PHP first impressions. В ней естественно рассказывается о новой визуальной оболочке для PHP, которая позволяет создавать веб-приложения на PHP, как в Visual Studio или Delphi. Интересно, что Delphi For PHP поддерживает событийную модель. Но, в общем, как следует из этой статьи, ничего особо хорошего у создателей сего программного продукта не получилось (цитата: «I will say that the release looks rushed, which is a shame.»). А жаль, идея хороша.