среда, 29 июня 2011 г.

Разработка бизнес приложения на silverlight –Часть 3 (создание DataGrid и DomainDataSorce, привязка данных)



Продолжаем писать наше бизнес приложение на Silverlight и сегодня мы напишем нашу xaml разметку, рассмотрим мспользование dataform и datagrid. Для тех кто ещё не знает что такое xaml.
XAML — это декларативный язык разметки. С точки зрения модели программирования .NET Framework язык XAML упрощает создание UI для приложения .NET Framework. Можно создать видимые элементы UI в декларативной разметке XAML, а затем отделить определение UI от логики времени выполнения, используя файлы с выделенным кодом, присоединенные к разметке с помощью определений разделяемых классов.

Итак, приступим. В проекте BuildingApp откройте файл MainPage.xaml. В области элементов перетащите элемент управления DataGrid на элемент Grid. Автоматически будут добавлены пространство имен XML и ссылки на сборки Data. Затем задайте имя для buildingDataGrid. В тегах DataGridTextColumn  я описываю колонки, которые будет отображаться в datagrid, как показано в следующем XAML-коде.

<navigation:Page xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
                 xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"
  x:Class="BuildingApp.Home"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
  xmlns:app="clr-namespace:BuildingApp.Web.DomainService"
  mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" 
  Style="{StaticResource PageStyle}" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:my="clr-namespace:BuildingApp.Web.DataAccess"
  xmlns:appControls="clr-namespace:BuildingApp.Controls">

    <Grid>
        <appControls:BusyIndicator IsBusy="{Binding IsBusy, ElementName=buildingDomainDataSource}" Grid.Row="1" Grid.Column="0" >
            <sdk:DataGrid Name="buildingDataGrid"
                              AutoGenerateColumns="False"
                              ItemsSource="{Binding ElementName=buildingDomainDataSource, Path=Data}"
                              RowDetailsVisibilityMode="VisibleWhenSelected">
                <sdk:DataGrid.Columns>
                    <sdk:DataGridTextColumn x:Name="nameColumn" Binding="{Binding Path=Name}" Header="Название" Width="160" IsReadOnly="True" />
                    <sdk:DataGridTextColumn x:Name="addressColumn" Binding="{Binding Path=Address}" Header="Адрес" Width="155" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="floorCountColumn" Binding="{Binding Path=FloorCount}" Header="Этажность" Width="90" IsReadOnly="True"/>
                    <sdk:DataGridTemplateColumn x:Name="creationDateColumn" Header="Дата постройки" Width="90" IsReadOnly="True" >
                        <sdk:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                                <sdk:DatePicker SelectedDate="{Binding Path=CreationDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" />
                            </DataTemplate>
                        </sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <sdk:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=CreationDate, StringFormat=\{0:d\}}" />
                            </DataTemplate>
                        </sdk:DataGridTemplateColumn.CellTemplate>
                    </sdk:DataGridTemplateColumn>
                    <sdk:DataGridTextColumn x:Name="totalAreaColumn" Binding="{Binding Path=TotalArea}" Header="Общая площадь" Width="90" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="roomColumn" Binding="{Binding Path=Room}" Header="Общее кол-во помещений" Width="70" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="minRentalRateColumn" Binding="{Binding Path=MinRentalRate}" Header="Мин.арендная ставка" Width="70" IsReadOnly="True" />
                    <sdk:DataGridTextColumn x:Name="maxRentalRateColumn" Binding="{Binding Path=MaxRentalRate}" Header="Макс.арендная ставка" Width="70" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="tenantsCountColumn" Binding="{Binding Path=TenantsCount}" Header="Кол-во арендаторов" Width="70" IsReadOnly="True"/>
                </sdk:DataGrid.Columns>
            </sdk:DataGrid>
        </appControls:BusyIndicator>
    </Grid >
</navigation:Page>


Элемент управления DataGrid предоставляет гибкий способ для отображения коллекции данных в виде строк и столбцов. К встроенным типам столбцов относятся столбец текстового поля, столбец флажков и столбец шаблона для размещения пользовательского содержимого. К встроенным типам строк относится раскрывающийся раздел сведений о строке, который можно использовать для отображения дополнительного содержимого под значениями ячеек.
По умолчанию элемент управления DataGrid автоматически генерирует столбци при установке свойства ItemsSource. Созданные столбцы являются принадлежат к типу свойствDataGridCheckBoxColumn для присоединенного Boolean (и допускающий значение 0 Boolean), а также всем остальным типам свойств DataGridTextColumn. Если свойство не имеет String или типа числовых значений, то созданные столбцы текстового поля доступны только для чтения и отображения значения ToString объектов данных.

Можно предотвратить автоматическое создание столбцов, присвоив свойству AutoGenerateColumns значение false. Это полезно, если требуется создать и настроить все столбцы явным образом. Кроме того, можно разрешить сетке данных создавать столбцы, но обрабатывать событие AutoGeneratingColumn для настройки столбцов после создания. Чтобы изменить порядок отображения столбцов, можно задать свойство DisplayIndex для отдельных столбцов. Настройка автоматически создаваемых столбцов в элементе управления DataGrid.
Созданные столбцы распознают атрибут DisplayAttribute, если он есть в исходном объекте.

Независимо от того, создаются ли столбцы, можно использовать коллекцию DataGrid..::..Columns, чтобы программно добавлять, вставлять, удалять и изменять какие-либо столбцы в элементе управления во время выполнения. Также можно задать столбцы в XAML, при этом следует присвоить свойству AutoGenerateColumns значение false. Создание собственных столбцов позволяет использовать дополнительные типы столбцов, таких как тип DataGridTemplateColumn или пользовательские типы столбцов. Тип DataGridTemplateColumn предоставляет легкий способ создания простого пользовательского столбца. Свойства CellTemplate и CellEditingTemplate позволяют указать шаблоны содержимого для режимов отображения и редактирования.
Итак, datagrid для отображения зданий создан, давайте также создадим datagrid для отображения этажей выбранного здания.

        <TextBlock Style="{StaticResource HeaderTextStyle}" Text="{Binding ElementName=buildingDataGrid, Path=SelectedItem.Name, StringFormat='Информация по этажам здания {0}'}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" />
        <appControls:BusyIndicator IsBusy="{Binding IsBusy, ElementName=floorDomainDataSource}" Grid.Row="3" Grid.Column="0">
            <sdk:DataGrid Name="floorDataGrid" AutoGenerateColumns="False"
                              ItemsSource="{Binding ElementName=floorDomainDataSource, Path=Data}"
                              RowDetailsVisibilityMode="VisibleWhenSelected" >
                <sdk:DataGrid.Columns>
                    <sdk:DataGridTextColumn x:Name="numberColumn" Binding="{Binding Path=Number}" Header="Номер этажа" Width="SizeToHeader" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="areaColumn" Binding="{Binding Path=Area}" Header="Общая площадь" Width="SizeToHeader" IsReadOnly="True"/>
                    <sdk:DataGridTextColumn x:Name="tenantsCountColumn1" Binding="{Binding Path=TenantsCount}" Header="Кол-во арендаторов" Width="SizeToHeader" IsReadOnly="True"/>
                </sdk:DataGrid.Columns>
            </sdk:DataGrid>
        </appControls:BusyIndicator>


Для того что бы datagrid получил данные нужно указать ему источник данных.

Для привязки DataGrid к данным, установите значение свойства ItemsSource на реализацию IEnumerable. Каждая строка в гриде данных привязана к объекту в источнике данных, а каждый столбец в сетке данных привязывается к свойству объекта данных. Чтобы пользовательский интерфейс DataGrid обновлялся автоматического при добавлении или удалении элементов из источника данных, DataGrid должен быть привязана к коллекции, реализующей INotifyCollectionChanged, например ObservableCollection<(Of <(<'T>)>)>. Чтобы автоматически отражать изменения свойств, объекты в исходной коллекции должны реализовывать интерфейс INotifyPropertyChanged.

Мы привяжем наш DataGrid к DomainDataSource. Службы WCF RIA предоставляет элемент управления DomainDataSource, чтобы упростить взаимодействие между пользовательским интерфейсом и данными из контекста домена. С помощью DomainDataSource можно получать, формировать и изменять данные, используя только декларативный синтаксис.
Чтобы использовать элемент управления DomainDataSource, необходимо добавить ссылку в проекте Silverlight к сборке System.Windows.Controls.DomainServices. Такая ссылка автоматически добавляется при перетаскивании DomainDataSource из области элементов. При необходимости для использования DataGrid с DomainDataSource следует также добавить ссылку на System.Windows.Controls.Data. Такая ссылка также автоматически добавляется при перетаскивании элемента управления DataGrid из области элементов.
Элемент управления ведущего приложения, такой как UserControl, должен содержать следующую ссылку на пространство имен:

xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"
При необходимости, чтобы использовать элемент управления DataGrid с DomainDataSource, необходимо также добавить следующее пространство имен:
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Чтобы определить контекст домена в декларативном коде, необходимо включить пространство имен серверного проекта. В следующем примере серверный проект носит имя ExampleApplication.Web. Следует использовать это имя серверного проекта.
xmlns:domain="clr-namespace:ExampleApplication.Web"
Итак, нам необходимо указать контекст домена для DomainDataSource и указать имя метода для загрузки данных. Затем можно привязать элементы управления к DataGrid. Давайте сделаем DomainDataSource для отображения данных по зданиям и . DomainDataSource для отображения данных по этажам выбранного здания.

<riaControls:DomainDataSource AutoLoad="True"
                                               d:DesignData="{d:DesignInstance my:Building, CreateList=true}"
                                               LoadedData="buildingDomainDataSource_LoadedData"
                                               Name="buildingDomainDataSource"
                                               QueryName="GetBuildingQuery">
            <riaControls:DomainDataSource.DomainContext>
                <app:BuildingDomainContext />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>

        <riaControls:DomainDataSource Name="floorDomainDataSource"
                                              AutoLoad="True"
                                              d:DesignData="{d:DesignInstance my:Floor, CreateList=true}"
                                              LoadedData="floorDomainDataSource_LoadedData"
                                              QueryName="GetFloorsByBuildingQuery">
            <riaControls:DomainDataSource.DomainContext>
                <app:BuildingDomainContext />
            </riaControls:DomainDataSource.DomainContext>
            <riaControls:DomainDataSource.QueryParameters>
                <riaControls:Parameter ParameterName="bID" Value="{Binding ElementName=buildingDataGrid, Path=SelectedItem.ID}" />
            </riaControls:DomainDataSource.QueryParameters>
        </riaControls:DomainDataSource>


Как вы видите во втором DomainDataSorce  для метода запроса требуется использовать параметр. Для отображения только тех этажей, которые принадлежат выбранному зданию.
Итак, в данной статье мы научились создавать DataGrid и DomainDataSorce, посмотрели как делается привязка  DataGrid к DomainDataSorce.
В следующей статье изучим такой полезный элемент управления как Dataform.

2 комментария:

  1. Здравствуйте, спасибо за статью!)))
    Как работать с 2-ми связными таблицами понятно))))
    А вот если таблиц в БД большое количество и чтоб вывести в DataGrid нужные данные надо пройти почти по всем таблицам?
    Как я понимаю на написать хранимую процедуру?, я это сделала :))), а вот как теперь с ней работать не понятно :(
    Буду очень благодарна за ответ.

    ОтветитьУдалить
    Ответы
    1. Не надо хранимых процедур.
      Надо в сервисе написать метод (как, например, GetFloorsByBuildingQuery), который будет тянуть данные из всех нужных таблиц, через связи, которые есть классах сущностей.

      Рекомендую для начала почитать какие-нибудь базовые статьи про Entity Framework.

      Удалить