Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

В двенадцатом выпуске рассылки '.Net Собеседник' вы можете познакомиться с


Информационный Канал Subscribe.Ru

.Net Собеседник #12

Содержание
  1. От автора
  2. Обзор новостей
  3. Эксплуатация событий DataTable в качестве клиентских триггеров 
  4. Время кода - Программная печать отчётов с использованием C# и SQL Server 2000 Reporting Services
  5. Форумы .Net на www.sql.ru

От автора

Здравствуйте, коллеги!

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

На этом всё - желаю интересного чтения.

{К содержанию}

Обзор новостей

  1. Доступна бета PlusSuite
    Olvio IT, Inc. объявила о выпуске первой беты своего набора элементов управления для .NET Framework. PlusSuite содержит улучшенные элементы управления, такие как боковые панели, мощные списки и ниспадающие списки. Все элементы управления настраиваются и поддерживают темы Windows XP.
  2. Вышел патч для TierDeveloper V 3.0
    AlachiSoft выпустила исправление и исправленную версию TierDeveloper 3.0.
  3. VistaDB™ 2.0 (Beta 2) получила хорошую прессу
    Хорошие результаты получены при тестовых конвертациях БД SQL Server и Access в БД VistaDB 2.0 (Beta 2).
  4. Вышел .netCHARTING 2.4
    Команда .netCHARTING рада объявить о выходе полнофункциональной бесплатной версии .netCHARTING 2.4.
  5. Innovasys выпустила DockStudioXP V2.0
    DockStudioXP 2 даст вам возможность использовать панели и плавающие окна в стиле Office XP/2003. Доступны стили Docked, Floating, Collapsed и Tab-Docked для плавающих окон.
  6. Вышел Apoc PDF Toolkit V2.1
    Apoc PDF Toolkit – это высококачественный компонент, который разработчики смогут добавить в свои приложения для манипуляции существующими PDF-документами и создания новых PDF-документов. Достигнута совместимость с приложениями .NET 1.1 - ASP.NET, WinForms и консольными.
  7. Вышел XtraReports Suite v.1.0
    Developer Express с гордостью сообщает о выходе XtraReports Suite – платформы для создания отчётов для приложений Windows Forms и ASP.NET. Разработанная с нуля с использованием только управляемого кода, XtraReports была написана на C# и предлагает полную интеграцию с Visual Studio .NET, предоставляя вам возможность создавать отчёты также, как вы строите свои приложения Windows Forms.

{К содержанию}

Эксплуатация событий DataTable в качестве клиентских триггеров

Эксплуатация событий DataTable в качестве клиентских триггеров

ЯЗЫК: C#
ASP.NET VERSIONS: 1.0 | 1.1
Автор статьи: Brian Noyes, http://www.aspnetpro.com/

ПЕРЕВОД: Чужа В.Ф. ака hDrummer


О чём: Использование событий DataTable для проверки данных и выполнения бизнес-процессов, базирующихся на изменении полей и записей.
Общим подходом в случае приложений, написанных на ASP.NET является использование серверных элементов управления для проверки правильности данных при их изменении. Элементы контроля ввода ASP.NET выполняют проверку данных с использованием клиентского скрипта, если это возможно, и серверного скрипта, не взирая на то, возможна ли проверка данных с помощью клиентского скрипта. Это обычный подход для любого типа пользовательского ввода.
Однако иногда может оказаться полезным иметь возможность проверки введенных данных непосредственно перед их внесением, например, ещё на сервере приложений, а не там, где пользователь производит эти изменения. Используя события класса DataTable, можно легко выполнять пре- и постпроцессинг полей и записей в наборе данных, что очень напоминает использование триггеров в обычной СУБД.

К делу

Класс DataTable имеет набор событий, которыми можно воспользоваться для получения контроля над изменениями, которые производят с данными в таблице. Есть три типа событий и в каждом типе находятся два события. События происходят во время изменений в столбце (ColumnChanging/ColumnChanged), при изменении записи (RowChanging/RowChanged) или удалении записи (RowDeleting/RowDeleted). Событие, именуемое XXChanging, происходит перед тем, как изменение будет выполнено; событие XXChanged происходит после завершения внесения изменений.

События ColumnChanging и ColumnChanged включают аргумент типа DataColumnChangeEventArgs, который имеет три ключевых свойства: Column, Row и ProposedValue. Column – это ссылка на тот DataColumn, который будет изменяться, Row – ссылка на тот DataRow, который будет изменяться, а ProposedValue содержит значение, присвоенное полю.
События записи включают аргумент типа DataRowChangeEventArgs. Этот объект включает два свойства, которые нам интересны: Action и Row. Свойство Action – это перечисление, содержащее значения Add, Change, Delete, Commit и Rollback, что даёт нам возможность узнать причину вызова события. Свойство Row позволяет нам проверить значения полей с помощью свойства ItemArray класса DataRow; также можно проверить свойство RowState для определения состояния записи до и после модификации.
Для более глубокого понимания того, когда происходит вызов каждого события и что можно сделать в его обработчике, давайте пройдёмся по трём сценариям модификации данных (вставка, обновление и удаление). Посмотрим, какие события будут вызываться для каждого из сценариев, и обсудим аргументы, доступные в обработчиках этих событий, которые мы можем использовать для исполнения каких-то действий над данными.
Для начала необходимо иметь набор данных, заполненный некоторыми данными, а также необходимо подписаться на те события, в которых мы заинтересованы. В этом случае, для компактности кода, я использовал класс Data Access Application Block (DAAB) SqlHelper и типизированный набор данных для таблицы Customers из БД Northwind.


public void LoadDataSet()
{
// Заполним набор данных
SqlHelper.FillDataset(connString,CommandType.Text,
"SELECT * FROM Customers",m_ds,
new string[]{m_ds.Customers.TableName});

// Привяжем обработчики событий
m_ds.Customers.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging);
m_ds.Customers.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
m_ds.Customers.RowChanging += new DataRowChangeEventHandler(OnRowChanging);
m_ds.Customers.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
m_ds.Customers.RowDeleting += new DataRowChangeEventHandler(OnRowDeleting);
m_ds.Customers.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
}

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

Обработка событий Change

При добавлении новой записи к таблице в коде, мы обычно создаём эту новую запись и затем добавляем её к таблице:

CustomersDataSet.CustomersRow newrow = m_ds.Customers.NewCustomersRow();
//Заполняем поля, которые не могут быть NULL
newrow.CompanyName = "Домик друзей";
newrow.CustomerID = "Чебурашка";
// Добавление к таблице
m_ds.Customers.AddCustomersRow(newrow);

В каждой строке кода, где мы устанавливаем значение поля, мы пользуемся свойством типизированного набора данных, что эквивалентно установке значения посредством индексатора DataRow в нетипизированном наборе данных. Для каждого из таких присвоений происходит событие ColumnChanging, а затем ColumnChanged. Потом, когда происходит вызов AddCustomersRow (что эквивалентно вызову Rows.Add в нетипизированном наборе данных), происходит событие RowChanging, а за ним - RowChanged.

Повторюсь, что каждое событие, имеющее отношение к столбцу, содержит аргумент типа DataColumnChangedEventArgs. Текущее значение поля можно получить через свойства Column и Row, а сам аргумент содержит будущее значение поля как свойство ProposedValue:

private void OnColumnChanging(object sender,
DataColumnChangeEventArgs e)
{
string colName = e.Column.ColumnName;
object currVal = e.Row[e.Column.ColumnName];
object newVal = e.ProposedValue;
// Вывод на экран...
}

Использовав свойство ColumnName свойства Column аргумента события, можно легко написать конструкцию switch..case по ColumnName, проверять текущее и предлагаемое значение поля на соответствие типов, а также выполнять дополнительные проверки или другие действия на этом этапе.

Проверка в триггерах или бизнес-логика

Итак, для проверки ввода вы можете воспользоваться обработчиком события ColumnChanging, вне зависимости от того, вызваны ли изменения вставкой или обновлением. Например, можно проверять значение введенной суммы в валюте на вход в определённую область значений. Для более аморфных типов, таких как строковый или XML, можно трансформировать введенное значение в какой-то другой формат, основываясь на других данных. Свойство ProposedValue является свойством для записи и чтения, поэтому можно изменять его значение прямо в обработчике события ColumnChanging, и именно измененное значение свойства будет внесено в набор данных.

А что если надо отменить изменения? Это чуть сложнее. К сожалению, аргументы события не имеют свойства Cancel, как многие другие свойства в .NET, которые позволяют вам отменить действие. Так что у нас есть два пути, ни один из которых не может устраивать нас во всех ситуациях. Первый и самый простой – установить значение свойства ProposedValue в текущее значение поля записи в обработчике события ColumnChanging:
e.ProposedValue = e.Row[e.Column.ColumnName];
Единственная проблема в таком подходе – если вы используете этот набор данных для обновления БД, то запись будет помечена как измененная, что приведет к ненужному ‘обновлению’ её в БД, а также, возможно, потенциально может привести к запуску другой логики, что в этом случае совершенно ни к чему.
Можно также вызвать исключение, что воспрепятствует внесению изменений. Однако, вызов исключения достаточно тяжелая операция, поэтому врядли вы захотите ею часто пользоваться. В этом случае также необходимо позаботиться о соответствующей обработке исключений.
В конце концов, можно вызвать метод RejectChanges в обработчике события RowChanged после того, как изменения были внесены, но тем самым будут отменены все изменения во всех полях записи, так что и этот метод может вам не подойти.
Ещё один способ использования событий столбца – изменение данных в других таблицах в ответ на изменение данных в исходной таблице. Если есть зависимости между одним полем в одной таблице и другим в другой, или между объектами в коде, можно так написать обработчик событий ColumnChanged, чтобы он выполнял эти изменения в соответствии с новым значением данного поля.
Как уже говорилось, в случае вставки записи методом AddCustomerRow происходят ещё два события RowChanging и RowChanged. Как для этих событий, так и для операции вставки, свойство Action будет установлено в значение Add. В событии на изменение RowState будет всё еще в состоянии Detached (это состояние, когда запись создана, но ещё не добавлена) а в событии постизменения RowState будет изменено на ‘добавлено’, так что можно будет отобрать только добавленные записи, если это будет необходимо. И если вам надо производить аудит записей, которые были добавлены к набору данных, то именно таким образом этот аудит и можно осуществить. Используя свойство ItemArray аргумента, доступное через свойство Row, вы можете выполнять другие действия, основываясь на свойстве Action и/или RowState записи.
При удалении записи не происходит событий, касающихся столбцов, а только события RowDeleting и RowDeleted со свойством Action установленным в Delete. RowState будет установлен в текущее состояние в обработчике события RowDeleting и будет изменен в Deleted в обработчике события RowDeleted.
Обновление таблицы работает во многом как добавление, которое обсуждалось ранее. Единственное отличие в том, что при обновлении существующей записи события изменения записи вызываются после изменения каждого поля сразу за событием изменения столбца. Поэтому для каждого модифицированного поля получим четыре события: ColumnChanging, ColumnChanged, RowChanging и RowChanged.
И, наконец – если вы вызываете метод AcceptChanges для таблицы, события изменения записи будут вызываться для каждой записи в таблице со значением свойства Action равным Commit. Если же был вызван метод RejectChanges, те же события будут вызываться для записей, имеющих изменения со значением свойства Action равным Rollback.
Пример для этой статьи – простое консольное приложение, которое вы можете использовать для экспериментов с событиями. Можно поиграться со значениями в обработчиках событий и посмотреть на полученный эффект. Использование событий класса DataTable предоставляет вам необходимую гибкость для того, чтобы быть в курсе изменений, происходящих с данными в памяти, и позволяет вам проверить или отформатировать их перед записью в таблицу. Можно также запустить другой процесс как ответ на эти изменения. Используя события класса DataTable можно создавать ещё более событийно-управляемые программы, что во многих случаях может существенно упростить бизнес-логику для используемых сценариев.

Проект к статье можно скачать здесь.

{К содержанию}

Время кода

Программная печать отчётов с использованием C# и SQL Server 2000 Reporting Services

ЯЗЫК: C#
АВТОР: Bryan Keller,
Программная печать отчётов с использованием C# и SQL Server 2000 Reporting Services
ПЕРЕВОД: Чужа В.Ф ака hDrummer

О чём: В статье показано, как программно печатать отчёты, используя Reporting Services XML Web service и C#.

Microsoft SQL Server 2000 Reporting Services – новая, располагающаяся на сервере платформа для создания отчётов самых разных видов – табличных, графических, пользовательских и т.д., содержащих данные из реляционных и многомерных источников данных. Просмотр и управление созданными отчётами можно выполнять через веб-соединение. У вас, как у разработчика, есть несколько возможностей, доступных через использование Reporting Services API. Одним из наиболее привлекательных аспектов Reporting Services – наличие открытого и гибкого Web service API (также известного как SOAP API). Его наличие позволяет нам интегрировать существующие особенности и возможности Reporting Services в ваши инструменты для создания отчётов для веб-сайтов и приложении Windows. SOAP API содержит около сотни различных методов XML веб-сервисов, которые мы можем использовать для управления, обработки и интеграции отчётов с нашими приложениями. В этой статье я сосредоточусь на одном из способов: программный рендеринг отчёта и отсылка его непосредственно на локальный или сетевой принтер. Использоваться будут язык C# и веб-сервис Reporting Services.

Перед прочтением можно скачать исходный код.

Создание ссылки на веб-сервис

Первым делом необходимо добавить веб-ссылку на веб-сервис Reporting Services, указывающую на ваш сервер отчётов. Исходный код уже имеет ссылку на локальный сервер отчётов (localhost). Если у вас есть удалённый сервер отчётов, просто измените URL этой веб-ссылки. Конечной точкой для любого веб-сервиса Reporting Services - "http://servername/reportserver/reportservice.asmx". Энтузиасты веб-сервисов могут получить доступ к ней посредством браузера, добавив директиву ?wsdl для просмотра Web Service Description Language (WSDL) для веб-сервиса Reporting Services Web service (http://servername/reportserver/reportservice.asmx?wsdl).

Метод Render

Добавив правильную веб-ссылку, вы получаете в своё распоряжение все веб-методы веб-сервиса. Веб-методы – методы класса ReportingService. Для доступа к веб-методам необходимо создать прокси-объект ReportingService и установить права на его использование. Примерно это выглядит вот так:


ReportingService rs;
// создание объекта прокси и аутентификации
Console.WriteLine("Authenticating to the Web service...");
rs = new ReportingService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

Как только вы создали прокси-объект для веб-сервиса, вы можете использовать его методы также как и методы обычного класса, написанного на C#. Наиболее интересный метод в контексте данной статьи - ReportingService.Render. Это основной метод для обработки отчётов, которые мы публикуем на сервере отчётов. Синтаксис этого метода таков:

public Byte[] Render( string Report,
string Format,
string HistoryID,
string DeviceInfo,
[Namespace].ParameterValue[] Parameters,
[Namespace].DataSourceCredentials[] Credentials,
string ShowHideToggle,
out string Encoding,
out string MimeType,
out [Namespace].ParameterValue[] ParametersUsed,
out [Namespace].Warning[] Warnings
out string[] StreamIds);
Member of [Namespace].ReportingService

Для более подробного описания аргументов метода обратитесь к Reporting Services Books Online.
В коде вы должны отрендерить отчёт в выходной формат изображения, указанный в аргументе Format. Значение этого параметра – строка, просто "IMAGE". Для получения отчёта в формате Enhanced Meta File (EMF), т.е. того формата, который необходим для печати, также надо будет указать информацию об устройстве при вызове метода Render. Эта информация об устройстве может быть передана как XML-строка в аргументе DeviceInfo и должна выглядеть как "<DeviceInfo><OutputFormat>EMF</OutputFormat> </DeviceInfo>". Метод Render возвращает отчёт как массив байт, кодированный по стандарту BASE64. Этот массив байт может быть использован для выполнения ряда операций, включая сохранение его в файл или, что более важно, передача в виде потока на принтер.
Код в примере рендерит один из отчётов, поставляемых с Reporting Services: отчёт Company Sales. Как только вы научитесь эффективно использовать метод Render для обработки отчётов, вы можете начать обдумывание того, как программно напечатать этот отчёт.

Программная печать отчёта

Есть несколько ключевых моментов, которые нужно уяснить, чтобы научиться печатать отчёты с использованием C# и Reporting Services. Первый момент – уяснить, как можно печатать в .NET Framework, используя C#. В коде, который приведен в этой статье, я использую классы пространства имён System.Drawing.Printing для отсылки вывода в формате EMF на принтер. Исходный код продемонстрирует вам как всё это вместе выглядит. С точки зрения Reporting Services, основным моментом является определение количества страниц в отчёте. В SOAP API для Reporting Services отсутствует возможность определить количество напечатанных страниц отчёта через свойства этого отчета. К счастью, SOAP API возвращает массив идентификаторов потока всякий раз, когда вызывается метод Render. Что это за идентификаторы потока? Дело в том, что когда на вывод имеет формат EMF, метод Render возвращая результат в виде массивов байт, возвращает только первую страницу. Следующие страницы ассоциируются с отчётом как потоки с соответствующими идентификаторами. Подсчитав количество StreamID в конечном массиве, вы можете определить количество страниц в отчёте. Этот код выдаст вам количество страниц:


// Общее количество страниц в отчёте = 1 + кол-во streamID
int m_numberOfPages = streamIDs.Length + 1;

Теперь, когда вы знаете сколько страниц у вас в отчёте, вы можете вызвать метод Render для каждой страницы отчёта и отослать её на принтер. Вы можете обработать некоторые страницы с использованием информации об устройстве, которое носит имя StartPage. В коде примера информация об устройстве для каждого следующего вызова рендеринга (т.е. для каждого после самого первого) выглядит как "<DeviceInfo><OutputFormat>EMF</OutputFormat><StartPage>текущая страница </StartPage></DeviceInfo>". После обработки каждой страницы, вы загружаете её (как набор обработанных байт) в массив страниц, многомерный массив байт и обрабатываете этот массив. Для каждого такого массива генерируете поток в памяти и выгружаете изображение из этого потока как документ для печати. Вот теперь можно его и распечатать. Печать с использованием данной технологии не для новичков, поэтому вы можете захотеть дополнительно изучить Руководство Разработчика .NET Framework. В конце статьи есть список рекомендуемой литературы для дополнительного чтения. Что ещё надо помнить, так это то, что вам будет необходимо указать имя принтера, который имеется в вашей системе:


static void Main(string[] args) {

PrintExample pe = new PrintExample();
pe.PrintReport(@"PrinterName");
}

Выводы

Ну что, пора бы написать пару строк кода – в конце концов, строка именно для этого и предназначена. Ну а если серьёзно, я надеюсь, что статья ознакомила вас с некоторыми особенностями программной печати отчётов с использованием C# и Reporting Services.

Литература

Reporting Services Books Online на MSDN
Пространство имён System.Drawing.Printing на MSDN
Документация по XML Web Services на MSDN
Пробная версия Reporting Services


{К содержанию}

Форумы .Net - вопросы оставшиеся без ответа

View в Crystal reports
Пусто вместо 0 в отчете Crystal Reports
Как на Datagride показывать изменения, сделанные в базе другими юзерами?
(потеря указателя) Пусть не покажется странным мой вопрос...
Какое событие происходит перед вызовом WebMethod?
название столбца в DataGrid Вертикально
акая область видимости?
help!!!
MxDataGrid Выделение строки
Удаление из DataGrid
Подскажите WAP сайт, сделанный на ASP.NET
VS. Net перегружается при открытии xsl файл или создании нового...
Unrecognized attribute 'requireSSL'?
Временные таблицы MsSQL 2000 и SqlDataAdapter
RowState


На этом двенадцатый выпуск .Net Собеседника закончен.
До следующего номера.



Чужа Виталий Ф. aka hDrummer,
hdrummer@sql.ru - жду ваши предложения, вопросы и замечания.


Рассылки Subscribe.Ru
.Net Собеседник - Новости мира Net, C#, ASP.Net


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу


В избранное