zoukankan      html  css  js  c++  java
  • 自定义控件为了虚拟化表结构

    I’ve just Copied the Article of paul van bladel for sharing, original link:

    http://blog.pragmaswitch.com/?p=318

     

    Introduction

    LightSwitch has a powerful and robust set of standard controls which are doing a great job. Apart from that there is always the possibility the create your own custom controls.

    That’s what we will do in this post.

    I want to demonstrate a way to visualize data of rooms and their corresponding reservations on a kind of “plan board”. This differs radically from a normal datagrid because the visualization that we have in mind has kind of undefined amount of “columns.

    The Data model

    We have a pretty simple Parent-child relationship between rooms and reservations.

    For completeness, here the Reservation entity design:

    As you can see a reservation has a slot property, which is the reservation date. A room can only reserved for at least a full day. Apart from the link to the room in question, a reservation has as well a state property. In my simple example this can be A, B or C, but you can use your imagination to think about something more realistic.

    The classic list-detail representation

    How do we want to visualize the room reservations?

    I will not focus here on a graphical masterpiece, I limit things to a spartan representation in such a way all attention can go to the necessary plumbing.

    You can click on a current reservation and a modal form will pop up:

    The necessary ingredients

    The Xaml

    <UserControl xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"  x:Class="LightSwitchApplication.ReservationSilverlightControl"
        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:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
        mc:Ignorable="d" xmlns:local="clr-namespace:LightSwitchApplication"
        d:DesignHeight="300" d:DesignWidth="400">
        <UserControl.Resources>
            <local:PeriodParameters x:Key="PeriodParameters"></local:PeriodParameters>
            <local:ReservationValueConverter x:Key="ReservationValueConverter"></local:ReservationValueConverter>
        </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White"  DataContext="{Binding Screen}"  Loaded="LayoutRoot_Loaded" >
            <sdk:DataGrid  AutoGenerateColumns="False" x:Name="grid"  ItemsSource="{Binding Rooms}">
                <sdk:DataGrid.Columns>
                    <sdk:DataGridTextColumn
                                 Binding="{Binding Name}"
                                 Header="Name"/>
                    <sdk:DataGridTemplateColumn   Width="*">
                        <sdk:DataGridTemplateColumn.HeaderStyle>
                            <Style
                              TargetType="primitives:DataGridColumnHeader">
                                <Setter
                                  Property="HorizontalContentAlignment"
                                  Value="Stretch" />
                                <Setter
                                  Property="VerticalContentAlignment"
                                  Value="Stretch" />
                                <Setter Property="Margin"
                                             Value="0" />
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <ItemsControl
                              ItemsSource="{Binding Source={StaticResource PeriodParameters},Path=DateList,Mode=TwoWay}">
                                                <ItemsControl.ItemsPanel>
                                                    <ItemsPanelTemplate>
                                                        <StackPanel
                                             Orientation="Horizontal">
                                                        </StackPanel>
                                                    </ItemsPanelTemplate>
                                                </ItemsControl.ItemsPanel>
                                                <ItemsControl.ItemTemplate>
                                                    <DataTemplate>
                                                        <Border  Width="25" >
                                                            <TextBlock Text="{Binding }"
                                                  TextAlignment="Center"/>
                                                        </Border>
                                                    </DataTemplate>
                                                </ItemsControl.ItemTemplate>
                                            </ItemsControl>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </sdk:DataGridTemplateColumn.HeaderStyle>
                        <sdk:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl ItemsSource="{Binding Converter={StaticResource ReservationValueConverter},  ConverterParameter={StaticResource PeriodParameters}}">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate  >
                                            <StackPanel   Orientation="Horizontal"/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <Border Width="25">
                                                    <TextBlock Height="25" Width="25" TextAlignment="Center"
                                                               MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"
                                                               Tag="{Binding Id}"  Text="{Binding State}">
                                                    </TextBlock>
                                                </Border>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </sdk:DataGridTemplateColumn.CellTemplate>
                    </sdk:DataGridTemplateColumn>
                </sdk:DataGrid.Columns>
            </sdk:DataGrid>
        </Grid>
    </UserControl>

    You’ll notice that my control is basically a datagrid with 2 columns where the first column (a DataGridTextColumn)  is bound to the room visual collection and the second column ( a DataGridTemplateColumn) is in fact a stackpanel which “horizontalises” the reservations for the current room.

    One difficulty is here that a room does not necessary have reservations for the complete time frame for which the overview is requested. Also finding out the right way to do the binding was, at least for me, a challenge.

    The Xaml Code behind

    public partial class ReservationSilverlightControl : UserControl
        {
            public ReservationSilverlightControl()
            {
                InitializeComponent();
                PeriodParameters.DateList = new ObservableCollection<string>();
            }
     
            private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                TextBlock textBlock = sender as TextBlock;
                var context = (IContentItem)this.DataContext;
                var screen = (IScreenObject)context.Screen;
     
                if (textBlock.Tag != null)
                {
                    int myReservation = int.Parse(textBlock.Tag.ToString());
     
                    screen.Details.Dispatcher.BeginInvoke(() =>
                        {
     
                            screen.Details.Properties["CurrentReservationId"].Value = myReservation;
                            screen.Details.Methods["EditDetails"].CreateInvocation(null).Execute();
                        });
                }
                else
                {
                    //here we could  call a create reservation screen.
                }
     
            }
     
            private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
            {
                if (((sender as Grid).DataContext as SimpleCustomControl).StartDate.HasValue)
                {
                    PeriodParameters.StartDate = ((sender as Grid).DataContext as SimpleCustomControl).StartDate.Value.Date;
                }
                else
                {
                    PeriodParameters.StartDate = DateTime.Now.Date;
                }
     
                if (((sender as Grid).DataContext as SimpleCustomControl).EndDate.HasValue)
                {
                    PeriodParameters.EndDate = ((sender as Grid).DataContext as SimpleCustomControl).EndDate.Value.Date;
                }
                else
                {
                    PeriodParameters.EndDate = DateTime.Now.AddDays(31).Date;
                }
     
                TimeSpan span = PeriodParameters.EndDate - PeriodParameters.StartDate;
     
                for (int i = 0; i <= span.Days; i++)
                {
                    PeriodParameters.DateList.Add(PeriodParameters.StartDate.AddDays(i).Day.ToString());
                }
            }
        }

    The row ValueConverter

    public class PeriodParameters
        {
            public PeriodParameters() { }
            public static ObservableCollection<string> DateList { get; set; }
            public static DateTime StartDate { get; set; }
            public static DateTime EndDate { get; set; }
        }
     
        public class ReservationValueConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                ObservableCollection<Reservation> reservationObservableCollection = new ObservableCollection<Reservation>();
                Room currentRoom = value as Room;
                var query = currentRoom.ReservationsQuery as IExecutableWithResult;
                query.ExecuteCompleted += new EventHandler<ExecuteCompletedEventArgs>((s, e) =>
                {
                    IEnumerable<Reservation> reservationList = query.Result as IEnumerable<Reservation>;
     
                    DateTime startDate = PeriodParameters.StartDate.Date;
                    DateTime endDate = PeriodParameters.EndDate.Date;
                    TimeSpan span = endDate - startDate;
                    for (int i = 0; i <= span.Days; i++)
                    {
                        Reservation reservation = reservationList.Where(r => r.Slot.Date == startDate.AddDays(i)).SingleOrDefault();
     
                        reservationObservableCollection.Add(reservation);
                    }
                });
                query.ExecuteAsync();
                return reservationObservableCollection;
            }
     
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return value;
            }
        }

    As you can see, the row IValueConverter will load for each room row the corresonding reservation data in an asynchronous way. So, if you have a lot of reservation data, the loading can take a few seconds, but it will never block the screen.

    The LightSwitch screen.

    The LightSwitch screen containing the reservation control is very light and contains only the code for showing the modal form for editing the current reservation:

    public partial class SimpleCustomControl
       {
           partial void EditDetails_Execute()
           {
               this.OpenModalWindow("CurrentReservation");
           }
       }

    Sample Project

    You can find here  the sample project: RoomReservation. It contains also functionality to generate some working test data.

    Enjoy !

    Many thanks to Lifeng for the help on the LightSwitch forum.

  • 相关阅读:
    DataTable转换成IList<T>的简单实现
    websocket
    获取用户使用设备信息
    判断对象是否相等
    关于PC适配
    树形数据结构实现平铺展示
    埋点
    多层表单验证
    表格行拖动,数据中状态值不同的禁止拖拽
    element tree 深度查询
  • 原文地址:https://www.cnblogs.com/otomii/p/2530949.html
Copyright © 2011-2022 走看看