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

Ширина колонок в DataGrid в Silverlight 4.

В Silverlight существует проблема при задании ширины колонок в DataGrid. К сожалению, существует лишь возможность задать ширину колонки в пикселях (еще существуют и другое варианты задания ширины колонки, например, ширина колонки может равняться ширине данных или ширине заголовка колонки, но это также не слишком применимо в реальной жизни), хотя в реальной жизни больше смысла в задании ширины колонки в процентах. Поскольку не свегда заранее известна ширина всего грида в пикселях. Пользователь может работать в произвольном разрешении, а также может растягивать окно с Silverlight приложением до удобных ему размеров.

В этот раз мы реализуем, пожалуй, наиболее распространенных способ задания ширины колонок в процентах.

В теории, для этого существует символ *, например, для того, чтобы задать ширину для некоторой колонки равную 20%, нужно указать Wodth=”0.2*”. Проблема в том, что это не работает.

Предположим, что нам нужно создать три колонки, ширина которых будет состалять 20, 30 и 50 процентов.

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

Реализуем свой метод растягивания, для этого подпишемся на событие SizeChanged элемента DataGrid.

<sdk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ElementName=someDomainDataSource, Path=Data}" Name="someDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" ColumnWidth="Auto" IsReadOnly="True" SelectionMode="Single" SizeChanged="someDataGrid_SizeChanged">

  <sdk:DataGrid.Columns>
                             <sdk:DataGridTextColumn x:Name="SomeColumn1" Binding="{Binding Path=Some_Data1 }" Header="Some Data1" MinWidth="20"/>
                             <sdk:DataGridTextColumn x:Name="SomeColumn2" Binding="{Binding Path=Some_Data2 }" Header="Some Data2" MinWidth="30"/>
                             <sdk:DataGridTextColumn x:Name="SomeColumn3" Binding="{Binding Path=Some_Data3 }" Header="Some Data3" MinWidth="50"/>

</sdk:DataGrid.Columns>


 


<i:Interaction.Behaviors>

<behaviors:DataGridDoubleClickBehavior DoubleClick="someDataGrid_DoubleClick"/>


</i:Interaction.Behaviors>


</sdk:DataGrid>



В коде обработчика нам нужно получить свойство MinWidth колонки и общую длину грида с данными. По этим параметрам легко определить нужную длину каждой колонки.



private void someDataGrid_SizeChanged(object sender, SizeChangedEventArgs e)

{


DataGrid dg = (DataGrid)sender;


foreach (DataGridColumn dgCol in dg.Columns)


{


                dgCol.Width = new DataGridLength((int)(dgCol.MinWidth * dg.ActualWidth / 100));


}


}



Также не стоит забывать о том, что, когда мы устанавливаем значение свойства Width для колонки, событие SizeChanged срабатывает снова. Чтобы не попасть в бесконечный цикл, необходимо добавить следующую проверку:



private void someDataGrid_SizeChanged(object sender, SizeChangedEventArgs e)

        {


if (e.PreviousSize.Width == e.NewSize.Width)

            {


return;


            }



DataGrid dg = (DataGrid)sender;


foreach (DataGridColumn dgCol in dg.Columns)


            {


                dgCol.Width = new DataGridLength((int)(dgCol.MinWidth * dg.ActualWidth / 100));


            }


        }



Этот простой код помогает значительно улучшить дизайн приложения, так что, пожалуй, он может пригодиться многим Silverlight прогрммистам.



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();;
 
             }
 
         }
 



         private void someDataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
         {
             if (e.PreviousSize.Width == e.NewSize.Width)
             {
                 return;
             }
             DataGrid dg = (DataGrid)sender;
 
             foreach (DataGridColumn dgCol in dg.Columns)
             {
                 dgCol.Width = new DataGridLength((int)(dgCol.MinWidth * dg.ActualWidth / 100));
             }
         }



 
         // 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 projectDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e)
         {
             if (e.HasError)
             {
                 System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
                 e.MarkErrorAsHandled();
             }
             else
             {
                 var list = ((DomainDataSource)sender).Data.OfType<Project>().ToList<Project>();
 
                 var allProjects = new Project();
                 allProjects.Name = "All Projects";
                 list.Insert(0, allProjects);
                 projectComboBox.ItemsSource = list;
                 projectComboBox.SelectedIndex = 0;
             }
         }



 
         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();
                 }
             }


         }
 
                 private void someDataGrid_DoubleClick(object sender, MouseButtonEventArgs e)
         {
             OpenSomeViewForm();
         }
 
     }

}


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="False" ItemsSource="{Binding ElementName=someDomainDataSource, Path=Data}" Name="someDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" ColumnWidth="Auto" IsReadOnly="True" SelectionMode="Single" SizeChanged="someDataGrid_SizeChanged">

  <sdk:DataGrid.Columns>

                            <sdk:DataGridTextColumn x:Name="SomeColumn1" Binding="{Binding Path=Some_Data1 }" Header="Some Data1" MinWidth="20"/>
                             <sdk:DataGridTextColumn x:Name="SomeColumn2" Binding="{Binding Path=Some_Data2 }" Header="Some Data2" MinWidth="30"/>
                             <sdk:DataGridTextColumn x:Name="SomeColumn3" Binding="{Binding Path=Some_Data3 }" Header="Some Data3" MinWidth="50"/>

</sdk:DataGrid.Columns>


 


                       <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>

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

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