пятница, 27 августа 2010 г.

Раскрашивание рядов данных Silverlight.

Часто возникает необходимость как-то кастомизировать ряды данных в DataGrid, например выделить цветом ряды, в которых хранятся данные с определенными свойствами.

Можно разделить задачу на две подзадачи:

1. Раскрашиваение грида при его создании.

2. Изменение цвета ряда при его изменении при помощи формы с данными.

По очереди рассмотрим эти задачи:

Интересно то, что получить список рядов в DataGrid в Silverlight 4 нельзя. Иначе наша задача решалась бы очень просто, поскольку этого сделать нельзя будем использовать обходные пути.

Для того чтобы решить первую задачу нам нужно подписаться на событие LoadingRow нашего грида. В обработчике выполнить свой код проверки состояния контекста данных.

Ничего сложного:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Windows.Navigation;

using MyApplication.Web.Services;

using MyApplication.BLL;

using System.Threading;

using System.ComponentModel;

using System.ServiceModel.DomainServices.Client;
 

namespace MyApplication.Views

{
     public partial class SomePage : Page
     {
         public SomePage()
         {
             if (WebContext.Current.User.IsAuthenticated)
             {
                 InitializeComponent();
                 someDataGrid.LoadingRow += new EventHandler<DataGridRowEventArgs>(someDataGrid_LoadingRow);
 
             }
 
         }
 
         void someDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
         {
             var some = e.Row.DataContext as SomeTable;
             if (some.IsNeedToDrawRed)
             {
                 e.Row.Foreground = new SolidColorBrush(Colors.Red);
             }
             else
             {
                 e.Row.Foreground = new SolidColorBrush(Colors.Black);
             }
 
         }
 
         // Executes when the user navigates to this page.
         protected override void OnNavigatedTo(NavigationEventArgs e)
         {
             if (!WebContext.Current.User.IsAuthenticated)
             {
                 this.NavigationService.Navigate(new Uri("/Home", UriKind.Relative));
                 return;
             }        }
 
         private void someDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e)
         {
 
             if (e.HasError)
             {
                 System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
                 e.MarkErrorAsHandled();
             }
 
         }
 
         private void OpenSomeViewForm()
         {
             var window = new SomeTableView();
             window.CurrentSome = (SomeTable)someDataGrid.SelectedItem;
             window.Context = someDomainDataSource.DomainContext;
             window.ParentLayoutRoot = LayoutRoot;
             window.Show();
             window.Closed += new EventHandler(window_Closed);
         }
 
         void window_Closed(object sender, EventArgs e)
         {
             if (someDomainDataSource.HasChanges)
             {
                 someDomainDataSource.DomainContext.SubmitChanges();
 
                 if (someDomainDataSource.CanLoad)
                 {
                     someDomainDataSource.Clear();
                     someDomainDataSource.Load();
                 }
             }
 
         }
 
         private void someDataGrid_DoubleClick(object sender, MouseButtonEventArgs e)
         {
             OpenSomeViewForm();
         }
 
     }

}


Решение следующей задачи ялвяется, пожалуй, гораздо менее очевидным. Предположим, что в форме открываемой при двойной нажатии мышью на ряд мы изменили поле IsNeedToDrawRed. Данные в гриде обновятся, но вот цвет ряда не изменится.



Получается, что нам нужно самостоятельно найти измененный ряд (в простом случае – это текущий ряд грида) и изменить его цвет если это нужно.



Сделаем эту проверку при закрытии окна с формой.



Код будет достаточно хитрым: нам нужно будет получить текущий объект данных, из него полуичть ячейку данных, а уже их нее мы сможет получить текущий ряд. (запутано, но иначе не получается)



private void OpenSomeViewForm()

        {


var window = new SomeView();


            window.CurrentSome = (Some)someDataGrid.SelectedItem;


            window.Context = someDomainDataSource.DomainContext;


            window.ParentLayoutRoot = LayoutRoot;


            window.Show();


            window.Closed += new EventHandler(window_Closed);


        }


void window_Closed(object sender, EventArgs e)


        {


if (someDomainDataSource.HasChanges)


            {


                someDomainDataSource.DomainContext.SubmitChanges();


if (someDomainDataSource.CanLoad)


                {


                    someDomainDataSource.Clear();


                    someDomainDataSource.Load();


                }


            }


SomeTable some = (SomeTable)someDataGrid.SelectedItem;

FrameworkElement feTemp = someDataGrid.Columns[1].GetCellContent(some);


DataGridRow currentRow = DataGridRow.GetRowContainingElement(feTemp);


            currentRow.DataContext = null;


            currentRow.DataContext = some;


if (some.IsNeedToDrawRed)


            {


                currentRow.Foreground = new SolidColorBrush(Colors.Red);


            }


else


            {


                currentRow.Foreground = new SolidColorBrush(Colors.Black);


            }


        }



SomePage.xaml



<navigation:Page x:Class="MyApplication.Views.SomePage" 
            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"
            mc:Ignorable="d"
            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
            d:DesignWidth="640" d:DesignHeight="480"
            Style="{StaticResource PageStyle}"
                  xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"
                  xmlns:my="clr-namespace:MyApplication.Web.Services"
                  xmlns:my1="clr-namespace:MyApplication.BLL"
                  xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
                  xmlns:my2="clr-namespace:MyApplication.Controls"

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

xmlns:behaviors="clr-namespace:MyApplication.Helpers;assembly=MyApplication"

xmlns:converter="clr-namespace:MyApplication"

>
     <navigation:Page.Resources>
         <converter:VisibilityConverter x:Key="VisibilityConverter" />
     </navigation:Page.Resources>
     <Grid x:Name="LayoutRoot">
         <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}" >
 
             <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
 
                 <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
                            Text="{Binding Path=ApplicationStrings.SomesPageTitle, Source={StaticResource ResourceWrapper}}"/>


bility="Collapsed">
                     <StackPanel Orientation="Horizontal">
                         <TextBlock Text="Project:" VerticalAlignment="Center"/>
                         <ComboBox HorizontalAlignment="Left" Height="23" ItemsSource="{Binding ElementName=projectDomainDataSource, Path=Data}" DisplayMemberPath="Name" Name="projectComboBox" Width="120" Margin="10,0,0,0" SelectionChanged="projectComboBox_SelectionChanged">
                             <ComboBox.ItemsPanel>
                                 <ItemsPanelTemplate>
                                     <VirtualizingStackPanel />
                                 </ItemsPanelTemplate>
                             </ComboBox.ItemsPanel>
                         </ComboBox>
 
                     </StackPanel>



                 <riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my1:Some, CreateList=true}" Height="0" LoadedData="someDomainDataSource_LoadedData" Name="someDomainDataSource" QueryName="GetSomeTableQuery" Width="0" >
                     <riaControls:DomainDataSource.DomainContext>
                         <my:MyApplicationDomainContext />
                     </riaControls:DomainDataSource.DomainContext>
                     <riaControls:DomainDataSource.SortDescriptors>
                         <riaControls:SortDescriptor PropertyPath="ID" Direction="Ascending"/>
                     </riaControls:DomainDataSource.SortDescriptors>
                     <riaControls:DomainDataSource.QueryParameters>
                         <riaControls:Parameter ParameterName="projectId" Value="{Binding ElementName=projectComboBox, Path=SelectedItem.ID}" />


                    </riaControls:DomainDataSource.QueryParameters>
 
                 </riaControls:DomainDataSource>
                 <my2:BusyIndicator x:Name="busyIndicator1" IsBusy="{Binding ElementName=someDomainDataSource, Path=DomainContext.IsLoading}" BusyContent="Loading..." >
 
                     <sdk:DataGrid AutoGenerateColumns="True" ItemsSource="{Binding ElementName=someDomainDataSource, Path=Data}" Name="someDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" ColumnWidth="Auto" IsReadOnly="True" SelectionMode="Single" SizeChanged="someDataGrid_SizeChanged">
 


                       <i:Interaction.Behaviors>
 
                             <behaviors:DataGridDoubleClickBehavior DoubleClick="someDataGrid_DoubleClick"/>
 
                         </i:Interaction.Behaviors>
                     </sdk:DataGrid>
                 </my2:BusyIndicator>
                 <sdk:DataPager x:Name="somePager" PageSize="30" Source="{Binding ElementName=someDomainDataSource, Path=Data}">
                 </sdk:DataPager>
                 <riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my1:Project, CreateList=true}" Height="0" LoadedData="projectDomainDataSource_LoadedData" Name="projectDomainDataSource" QueryName="GetProjectsQuery" Width="0" >
                     <riaControls:DomainDataSource.DomainContext>
                         <my:MyApplicationDomainContext />
                     </riaControls:DomainDataSource.DomainContext>
                 </riaControls:DomainDataSource>
              </StackPanel>
         </ScrollViewer>
     </Grid>

</navigation:Page>


SomePage.xaml.cs



using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Windows.Navigation;

using MyApplication.Web.Services;

using MyApplication.BLL;

using System.Threading;

using System.ComponentModel;

using System.ServiceModel.DomainServices.Client;
 

namespace MyApplication.Views

{
     public partial class SomePage : Page
     {
         public SomePage()
         {
             if (WebContext.Current.User.IsAuthenticated)
             {
                 InitializeComponent();
                 someDataGrid.LoadingRow += new EventHandler<DataGridRowEventArgs>(someDataGrid_LoadingRow);
 
             }
 
         }
 
         void someDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
         {
             var some = e.Row.DataContext as SomeTable;
             if (some.IsNeedToDrawRed)
             {
                 e.Row.Foreground = new SolidColorBrush(Colors.Red);
             }
             else
             {
                 e.Row.Foreground = new SolidColorBrush(Colors.Black);
             }
 
         }
 
         // Executes when the user navigates to this page.
         protected override void OnNavigatedTo(NavigationEventArgs e)
         {
             if (!WebContext.Current.User.IsAuthenticated)
             {
                 this.NavigationService.Navigate(new Uri("/Home", UriKind.Relative));
                 return;
             }        }
 
         private void someDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e)
         {
 
             if (e.HasError)
             {
                 System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
                 e.MarkErrorAsHandled();
             }
 
         }
 
         private void OpenSomeViewForm()
         {
             var window = new SomeView();
             window.CurrentSome = (Some)someDataGrid.SelectedItem;
             window.Context = someDomainDataSource.DomainContext;
             window.ParentLayoutRoot = LayoutRoot;
             window.Show();
             window.Closed += new EventHandler(window_Closed);
         }
 
         void window_Closed(object sender, EventArgs e)
         {
             if (someDomainDataSource.HasChanges)
             {
                 someDomainDataSource.DomainContext.SubmitChanges();
 
                 if (someDomainDataSource.CanLoad)
                 {
                     someDomainDataSource.Clear();
                     someDomainDataSource.Load();
                 }
             }
 
             SomeTable some = (SomeTable)someDataGrid.SelectedItem;
             FrameworkElement feTemp = someDataGrid.Columns[1].GetCellContent(some);
             DataGridRow currentRow = DataGridRow.GetRowContainingElement(feTemp);
 
             currentRow.DataContext = null;
             currentRow.DataContext = some;
 
             if (some.IsNeedToDrawRed)
             {
                 currentRow.Foreground = new SolidColorBrush(Colors.Red);
             }
             else
             {
                 currentRow.Foreground = new SolidColorBrush(Colors.Black);
             }
         }
 
                 private void someDataGrid_DoubleClick(object sender, MouseButtonEventArgs e)
         {
             OpenSomeViewForm();
         }
 
     }

}

Комментариев нет:

Отправить комментарий