Tuesday, September 24, 2013

Silverlight RIA service, DomainContextBatchLoader

I am working on Silverlight these days. And we are using Silverlight RIA service and Entity framework to access database.

If you had ever worked with RIA , you will come across a situation that you might want to load many entities from the server using different queries, before you can present an appropriate UI to your customer.

for example, customer, you might want to load customer detail infomation, customer history, customer order etc etc.

I did some search , and didn't find an appropriate batch loader, so create one by myself, in case someone else also need to implement similar features, can take it as a reference.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
namespace SilverlightApplication4
{
    public class DomainContextBatchLoader
    {
        public abstract class LoadStep
        {
            public bool IsComplete { getset; }
            public abstract void Execute();
            public Action<LoadOperation> OnSuccess;
            public Action<LoadOperation> OnFail;
        }
 
        public class BatchLoadStep<T> : LoadStep
            where T : Entity
        {
            private DomainContext _context;
            public EntityQuery<T> EntityQuery { getset; }
            private LoadBehavior _loadBehavior = LoadBehavior.MergeIntoCurrent;
 
            #region Construction
            public BatchLoadStep(DomainContext contextEntityQuery<T> queryLoadBehavior loadBehavior = LoadBehavior.MergeIntoCurrent)
            {
                _context = context;
                EntityQuery = query;
                _loadBehavior = loadBehavior;
            }
            #endregion
            #region Overrides
            public override void Execute()
            {
                _context.Load(EntityQuery_loadBehaviorlp =>
                {
                    this.IsComplete = true;
                    this.LoadOperation = lp;
                    if (lp.IsComplete && !lp.HasError)
                    {
                        if (this.OnSuccess != null)
                        {
                            this.OnSuccess(lp);
                        }
                    }
                    else
                    {
                        if (this.OnFail != null)
                        {
                            this.OnFail(lp);
                        }
                    }
                }, null);
            }
            #endregion
 
            public LoadOperation<T> LoadOperation { getset; }
        }
 
        #region Construction
        public DomainContextBatchLoader(Action<DomainContextBatchLoader> completeAction)
        {
            this._completeAction = completeAction;
        }
        #endregion
 
        #region Private Properties
        private Action<DomainContextBatchLoader> _completeAction = null;
        private List<LoadStep> _lstSteps = new List<LoadStep>();
        private List<LoadOperation> _lstFaildOperation = new List<LoadOperation>();
        public event EventHandler OnComplete;
        #endregion
 
        #region Methods
        public void Add<T>(DomainContext contextEntityQuery<T> queryLoadBehavior loadBehaviorwhere T : Entity
        {
            var step = new BatchLoadStep<T>(contextqueryloadBehavior);
            step.OnSuccess = lp =>
            {
                this.CheckComplete();
            };
            step.OnFail = lp =>
            {
                this._lstFaildOperation.Add(lp);
                this.CheckComplete();
            };
            _lstSteps.Add(step);
        }
        private void CheckComplete()
        {
            if (!this._lstSteps.Any(o => o.IsComplete == false))
            {
                if (this._completeAction != null)
                {
                    this._completeAction(this);
                }
                if (this.OnComplete != null)
                {
                    this.OnComplete(thisnew EventArgs());
                }
            }
        }
        public void Start()
        {
            if (_lstSteps.Count > 0)
                _lstSteps.ForEach(o => o.Execute());
            else
            {
                CheckComplete();
            }
        }
 
        public IEnumerable<T> GetEntities<T>() where T : Entity
        {
            var step = _lstSteps.OfType<BatchLoadStep<T>>().FirstOrDefault();
            if (step != null)
                return step.LoadOperation.Entities.OfType<T>();
            return null;
 
        }
        public int FailedOperationCount { get { return _lstFaildOperation.Count; } }
 
        public IEnumerable<LoadOperation> FailedOperations
        {
            get { return _lstFaildOperation; }
        }
        #endregion
    }
}

Friday, January 25, 2013

Apple Style Scroll bar in WPF

I am working on a WPF application recently, created a Apple style scrollbar.
Here is the code, hope it will be useful. This version had been tailored to meet my requirement.  after apply it to a listbox, it looks like the following.
Also there is very good article  http://www.codeproject.com/Articles/37366/Styling-A-ScrollViewer-Scrollbar-In-WPF explain the structure of Scrollbar and how to change it.
1:  <SolidColorBrush x:Key="ScrollBarDisabledBackground" Color="#F4F4F4"/>  
2:      <Style x:Key="VerticalScrollBarPageButton" TargetType="{x:Type RepeatButton}">  
3:        <Setter Property="OverridesDefaultStyle" Value="true"/>  
4:        <Setter Property="Background" Value="Transparent"/>  
5:        <Setter Property="Focusable" Value="false"/>  
6:        <Setter Property="IsTabStop" Value="false"/>  
7:        <Setter Property="Template">  
8:          <Setter.Value>  
9:            <ControlTemplate TargetType="{x:Type RepeatButton}">  
10:              <Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>  
11:            </ControlTemplate>  
12:          </Setter.Value>  
13:        </Setter>  
14:      </Style>  
15:      <Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">  
16:        <Setter Property="OverridesDefaultStyle" Value="true"/>  
17:        <Setter Property="IsTabStop" Value="false"/>  
18:        <Setter Property="Template">  
19:          <Setter.Value>  
20:            <ControlTemplate TargetType="{x:Type Thumb}">  
21:              <Border Background="#FF868686" BorderThickness="0,0,1,0" Height="Auto" CornerRadius="4" />  
22:            </ControlTemplate>  
23:          </Setter.Value>  
24:        </Setter>  
25:      </Style>  
26:      <Style x:Key="HorizontalScrollStyle" TargetType="{x:Type ScrollBar}">  
27:        <Setter Property="Background" Value="Transparent"/>  
28:        <Setter Property="Template">  
29:          <Setter.Value>  
30:            <ControlTemplate TargetType="{x:Type ScrollBar}">  
31:              <Grid x:Name="Bg" Background="{TemplateBinding Background}" Height="10" SnapsToDevicePixels="true">  
32:                <Grid.RowDefinitions>  
33:                  <RowDefinition />  
34:                </Grid.RowDefinitions>  
35:                <Track x:Name="PART_Track" IsDirectionReversed="true" IsEnabled="{TemplateBinding IsMouseOver}">  
36:                  <Track.DecreaseRepeatButton>  
37:                    <RepeatButton Command="{x:Static ScrollBar.PageUpCommand}" Style="{StaticResource VerticalScrollBarPageButton}"/>  
38:                  </Track.DecreaseRepeatButton>  
39:                  <Track.IncreaseRepeatButton>  
40:                    <RepeatButton Command="{x:Static ScrollBar.PageDownCommand}" Style="{StaticResource VerticalScrollBarPageButton}"/>  
41:                  </Track.IncreaseRepeatButton>  
42:                  <Track.Thumb>  
43:                    <Thumb Style="{StaticResource ScrollBarThumb}" Cursor="Hand"/>  
44:                  </Track.Thumb>  
45:                </Track>  
46:              </Grid>  
47:              <ControlTemplate.Triggers>  
48:                <Trigger Property="IsEnabled" Value="false">  
49:                  <Setter Property="Background" TargetName="Bg" Value="{StaticResource ScrollBarDisabledBackground}"/>  
50:                </Trigger>  
51:              </ControlTemplate.Triggers>  
52:            </ControlTemplate>  
53:          </Setter.Value>  
54:        </Setter>  
55:      </Style>  
56:      <Style x:Key="AppleStyleVerticalScrollBarStyle" TargetType="{x:Type ScrollBar}">  
57:        <Setter Property="Template">  
58:          <Setter.Value>  
59:            <ControlTemplate TargetType="{x:Type ScrollBar}">  
60:              <Grid x:Name="Bg" SnapsToDevicePixels="true" Width="10" HorizontalAlignment="Right" Margin="0">  
61:                <Grid.RowDefinitions>  
62:                  <RowDefinition />  
63:                </Grid.RowDefinitions>  
64:                <Track x:Name="PART_Track" IsDirectionReversed="true" IsEnabled="{TemplateBinding IsMouseOver}">  
65:                  <Track.DecreaseRepeatButton>  
66:                    <RepeatButton Command="{x:Static ScrollBar.PageUpCommand}" Style="{StaticResource VerticalScrollBarPageButton}" />  
67:                  </Track.DecreaseRepeatButton>  
68:                  <Track.IncreaseRepeatButton>  
69:                    <RepeatButton Command="{x:Static ScrollBar.PageDownCommand}" Style="{StaticResource VerticalScrollBarPageButton}"/>  
70:                  </Track.IncreaseRepeatButton>  
71:                  <Track.Thumb>  
72:                    <Thumb Style="{DynamicResource ScrollBarThumb}" Cursor="Hand"/>  
73:                  </Track.Thumb>  
74:                </Track>  
75:              </Grid>  
76:            </ControlTemplate>  
77:          </Setter.Value>  
78:        </Setter>  
79:      </Style>  
80:      <ControlTemplate x:Key="AppleStyleScrollBarStyle" TargetType="{x:Type ScrollViewer}">  
81:        <Grid x:Name="Grid" Background="{TemplateBinding Background}">  
82:          <Grid.ColumnDefinitions>  
83:            <ColumnDefinition Width="*"/>  
84:            <ColumnDefinition Width="Auto"/>  
85:          </Grid.ColumnDefinitions>  
86:          <Grid.RowDefinitions>  
87:            <RowDefinition Height="*"/>  
88:            <RowDefinition Height="Auto"/>  
89:          </Grid.RowDefinitions>  
90:          <Rectangle x:Name="Corner" Grid.Column="1" Fill="{x:Null}" Grid.Row="1"/>  
91:          <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}"   
92:                      CanHorizontallyScroll="False" CanVerticallyScroll="False"   
93:                      ContentTemplate="{TemplateBinding ContentTemplate}"   
94:                      Content="{TemplateBinding Content}" Grid.Column="0"   
95:                      Margin="{TemplateBinding Padding}" Grid.Row="0"/>  
96:          <ScrollBar x:Name="PART_VerticalScrollBar" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"   
97:              AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1"   
98:              Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0"   
99:              Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"   
100:              ViewportSize="{TemplateBinding ViewportHeight}" Style="{DynamicResource AppleStyleVerticalScrollBarStyle}"   
101:                Background="{x:Null}" Width="Auto" Margin="0"/>  
102:          <ScrollBar x:Name="PART_HorizontalScrollBar" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"   
103:              AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0"   
104:              Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1"   
105:              Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"   
106:              ViewportSize="{TemplateBinding ViewportWidth}" Style="{DynamicResource HorizontalScrollStyle}"/>  
107:        </Grid>  
108:      </ControlTemplate>