Saturday, August 22, 2015

RadWindow cause RadComboBox to open popup unexpectedly and workaround

RadWindow and RadComboBox that I am talking about here  are both from Telerik(www.telerik.com) Silverlight controls, we use it quite a lot in our project.

Recently , I notice an issue  when using RadComboBox inside RadWindow , which somehow cause the RadComboBox to open it's dropdown  unexpectedly. Obviously it is quite annoying.

Originally I was suspect it is caused by our program related to the way how we use RadWindow and RadComboBox, but it turns out it is not ,because I created an isolated project and I can reproduce the same issue.  Just create a UserControl, and then drop a few RadComboBox in it.  Set the IsEditable=True, OpenDropDownOnFocus = true.


Then use code to open a RadWindow, Let's call it window1, and set the UserControl we created above as the content.  Inside the UserControl , provide a button , when click the button , open another RadWindow, let's call it window 2,  Then  leave window 2 open as it is, and click one of the RadComboBox on the  window 1, you will find out that all the combobox has it's dropdown open.

it will looks like the following snapshot.


I attach the sample project here.download

I also submit this issue to Telerik with the sample project , they confirm it is an issue, but no good solution yet.

But I work out a workaround that will collapse the dropdown when it is open without focus. 

I use a behaviour to achieve this, cause behaviour is nice , it can be easily add to the control without messing up the view's code behind. We are quite strictly using MVVM. So  there is very minimal code in the view's code behind.

using System.Windows.Interactivity;
 using Telerik.Windows.Controls;
 using System.Windows;
 /// <summary>
 /// Behavior to close unexpected dropdown behavior
 /// </summary>
 public class RadComboBoxCloseUnexpectedDropdownBehavior : Behavior<RadComboBox>
 {
  /// <summary>
  /// Default Constructor.
  /// </summary>
  public RadComboBoxCloseUnexpectedDropdownBehavior()
  {
   
  }
 
  /// <summary>
  /// When the behavior get attached into Visual Tree.
  /// </summary>
  protected override void OnAttached()
  {
   base.OnAttached();
   if (null == this.AssociatedObject) return;
   this.AssociatedObject.DropDownOpened += new SystemEventHandler(AssociatedObject_DropDownOpened);
 
  }
  void AssociatedObject_DropDownOpened(object sender, SystemEventArgs e)
  {
   if(!this.AssociatedObject.IsEnabled || !this.AssociatedObject.IsFocused)
    this.AssociatedObject.IsDropDownOpen = false;
  }
 
 
  /// <summary>
  /// Check whether keyboard focus is in this control.
  /// </summary>
  /// <param name="element"></param>
  /// <returns></returns>
  bool IsKeyboardFocusWithin(UIElement element)
  {
   UIElement uiElement = FocusManagerHelper.GetFocusedElement((DependencyObject)element) as UIElement;
   if (uiElement != null)
    return ParentOfTypeExtensions.IsAncestorOf((DependencyObject)element, (DependencyObject)uiElement);
   return false;
  }
  /// <summary>
  /// When behavior get removed
  /// </summary>
  protected override void OnDetaching()
  {
   this.AssociatedObject.DropDownOpened -= AssociatedObject_DropDownOpened;
   base.OnDetaching();
  }
 }

In order to use this behavior conveniently in Style, I also create attached property

/// <summary>
    /// Extensions on RadComboBox.
    /// </summary>
    public static class RadComboBoxExtensions
    {
        #region CloseDropdown
        /// <summary>
        /// Gets the <see cref="CloseUnexpectedDropdownProperty"/>
        /// </summary>
        public static readonly DependencyProperty CloseUnexpectedDropdownProperty = DependencyProperty.RegisterAttached(
            "CloseUnexpectedDropdown",
            typeof(bool),
            typeof(RadComboBox), //Note MUST be DepOb to support use in styles
            new PropertyMetadata(OnCloseUnexpectedDropdownChanged));
        
        /// <summary>
        /// Sets the DropOnFocus value
        /// </summary>
        /// <param name="element">Element</param>
        /// <param name="value">Value</param>
        public static void SetCloseUnexpectedDropdown(RadComboBox element, bool value) { element.SetValue(CloseUnexpectedDropdownProperty, value); }
        /// <summary>
        /// Gets the DropOnFocus value
        /// </summary>
        /// <param name="element">Element</param>
        /// <returns>Bool</returns>
        public static bool GetCloseUnexpectedDropdown(RadComboBox element) { return (bool)element.GetValue(CloseUnexpectedDropdownProperty); }
        static void OnCloseUnexpectedDropdownChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var behaviours = Interaction.GetBehaviors(d);
 
            var existing = behaviours.OfType<RadComboBoxCloseUnexpectedDropdownBehavior>().ToList();
 
            if ((e.NewValue is bool) && (bool)e.NewValue)
            {
                if (existing.Count <= 0) behaviours.Add(new RadComboBoxCloseUnexpectedDropdownBehavior());
            }
            else
            {
                foreach (var item in existing) { behaviours.Remove(item); }
            }
 
        }
        #endregion
    }

 I didn't dig into telerik's RadWindow source code to see what actually cause this, but I suspect the window is trying to to set the focus appropriately when it get activated,but I hope Telerik can fix this issue appropriately in their future release.

Thursday, August 13, 2015

Import data from SQL2012 to SQL2008

SQL Server is the database that we use in many of our products. And as you know there are also many versions of SQL Server out there as well.  At the moment our core product is still using SQL Server 2008 R2 unfortunately.  

Quite a while ago we need to import data from a legacy application into core product, which is using SQL Server 2008 R2.  however the legacy database is using some very old technology.  During that time the guy who worked on the data migration project decided to migrate the database to SQL 2012 assume that we will have upgrade our product to SQL2012 by the time when he finish, also there are some nice features in SQL2012 made his life a little bit easier.

So , here comes the problem, as time goes by , the  person who worked on data migration is long gone and our core product fail to upgrade to SQL 2012, cause we never get the time. I was ask to import some data from a client to our production core system. Which is still using SQL 2008 R2. 

That's where the problem comes in.  Update database from lower version to higher version is nice and easy, SQL Server have very good support. Not too much need to be done.  However if I need to downgrade a database from Higher version to lower version, the tool doesn't support by default. I can't restore a database from SQL2012 to SQL2008.

The Data Compare feature in my Visual Studio 2010 unfortunately doesn’t support database version higher than SQL 2008 R2 either.

I can also use SQL server's data import/export to do this as well, but since we use Timestamp field in our database, and use that to do concurrency check, which make it is very tedious to change the each single one of table setting.

Thus I did a bit search. And decide to create a script to achieve this goal. Here is what I did, in case someone else need to do similar task. And also for future myself , just in case I need to do similar things later on.

The following few conditions are unique in my situation, which is also the foundation that this solution is based on. 
  1. The database in SQL 2012 and SQL 2008 have exactly the same schema, table structure etc.
  2. We don't use any fancy features of SQL Server, no triggers, no  SSB , no Queue etc. just basic table.
  3. Our primary key is unique comprise with two part, one part is using the database auto-generated , Identity or Guid, the other part is maintained by our application based on setting. Thus we won't violate any primary key constrain.

First of all, I need to create a linked server my SQL 2008 R2  , so as I can access the database in 2012 format. You will need to have access to both SQL2008 and SQL2012 databases.



Click "New Linked Server…" option.  Assume I have the SQL Server 2012 and SQL Server 2008 R2 installed on the same machine.
And the instance name of SQL 2012 is "SQL2012"
Also go to security tab to specify logons that you need to use to access SQL2012
After these , I can access my SQL2012 database  easily.

A few things I need to do in my script.
  1. Need to traverse every table in the database. To check whether I have data there need to move across to SQL2008
  2. If the table contains Identity column ,then I need to SET IDENTITY_INSERT ON , before I insert data.
  3. If the table has foreign key constrains , I need to turn off the constrian check , because the order to insert data is undetermined
  4. After insert data, need to SET IDENTITY_INSERT OFF .
  5. We are using Timestamp column in our database which is readonly , so I need to specifically exclude Timestamp column from the script.

Here is the script that I used to generate the data import script.

USE [Your database name]

GO
IF OBJECT_ID('SQLStatement') IS NOT NULLBEGIN
   DROP TABLE
SQLStatementENDGOCREATE TABLE SQLStatement([SQL] NVARCHAR(MAX),Id INT NOT NULL IDENTITY)GOSET NOCOUNT ON

DECLARE
@TenantId INT
DECLARE
@FromTable NVARCHAR(255)DECLARE @ColumnList NVARCHAR(MAX)DECLARE @SourceTable NVARCHAR(255)DECLARE @SourceTablePreFix NVARCHAR(255)DECLARE @SQLPrepareSource NVARCHAR(MAX)--SET @SourceTablePreFix = '[eVisionRelease].'SET @SourceTablePreFix = '.\sql2012.[Your database name].'SET @TenantId = 3SET @SQLPrepareSource = 'insert #rectables select ''?'',count(*) rec_count from ? 'CREATE TABLE #rectables (tbl_name VARCHAR(100), rec_count INT)EXEC sp_MSforeachtable @SQLPrepareSourceDECLARE cTable CURSOR FOR
  SELECT
tbl_name FROM #rectables WHERE rec_count > 0
OPEN cTable
FETCH NEXT FROM cTable INTO @FromTableWHILE @@FETCH_STATUS = 0BEGIN

   DECLARE
@cols AS NVARCHAR(MAX),  @query  AS NVARCHAR(MAX)
  
SET @SourceTable =  @SourceTablePreFix + @FromTable
  
--get all columns, except timestamp
  
SELECT name AS ColumnName,column_id AS ColumnId INTO #ColumnSource FROM sys.columns WHERE OBJECT_ID=OBJECT_ID(@FromTable) AND system_type_id != 189
  
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(ColumnName)
                      
FROM #ColumnSource
                      
GROUP BY ColumnName, ColumnId
                      
ORDER BY ColumnId
              
FOR XML PATH(''), TYPE
              
).value('.', 'NVARCHAR(MAX)')
           ,
1,1,'')
  
DECLARE @HasIdentityColumn INT
   SET
@HasIdentityColumn =  (SELECT COUNT(*) FROM sys.identity_columns WHERE [object_id] = OBJECT_ID(@FromTable))
  
  
INSERT INTO SQLStatement ([SQL]) SELECT 'ALTER TABLE ' + @FromTable + ' NOCHECK CONSTRAINT ALL'
  
IF @HasIdentityColumn > 0
      
INSERT INTO SQLStatement ([SQL]) SELECT 'SET IDENTITY_INSERT ' + @FromTable + ' ON'
  
INSERT INTO SQLStatement ([SQL]) SELECT 'DELETE FROM ' +@FromTable +  ' WHERE TenantId=@TenantId'
  
INSERT INTO SQLStatement ([SQL]) SELECT 'INSERT INTO ' + @FromTable + '(' + @cols + ') SELECT ' + @cols +' FROM ' + @SourceTable + ' WHERE TenantId=@TenantId'
  
IF @HasIdentityColumn > 0 INSERT INTO SQLStatement ([SQL]) SELECT 'SET IDENTITY_INSERT ' + @FromTable + ' OFF'
  
DROP TABLE #ColumnSource

  
FETCH NEXT FROM cTable INTO @FromTable
  
END
CLOSE
cTableDEALLOCATE cTable DROP TABLE #rectablesSELECT [SQL] FROM SQLStatement ORDER BY Id



------------------------------------------------------------
After execute this script, it will generate the final script that we will need to execute to import data. Run the script in SQL2008 database. The one we need to import data into.

 Finger cross!

Final step, as we turn off the constrain check on foreign key, after we done with the import we need to turn it back on.

USE [Your databasename]
EXEC sp_MSforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL'


That's it...

Be aware this solution can be only executed on an isolated and offline environment, if you trying to do this on your live database, DBA will certainly kill you….

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>  

Thursday, October 25, 2012

Wednesday, August 1, 2012

must receive before sending a fault message on an implemented port

As a .net developer , just moved to BizTalk field,  I came across a lot issues in the last couple month when our project start to use BizTalk intensively.

As the title, when I was trying to implement a very simple sample ,  I got this error .

I setup a port which have request/response/fault, refer to the above snapshot.  in my orchestration, I implement very simple logic.
1.receive a message from the request port.
2.read the information from request, and then based on the message type specified in the request, dynamically transform the request to a response message.
3.send the response back to client.
4.if there are any error/exception happens, send a fault back to client.
refer to the following snapshot.
it is quite simple logic , but when I compile it, I get the following two errors.
1.must receive before sending a fault message on an implemented port
2.incomplete requestresponse operation; missing 'send'

By just simply look at the orchestration, I didn't aware anything is wrong, I do have a receive shape at the beginning , also I do have a send shape at the end of the orchestration,thus I refer to my good friend google for answers.  

It is quite hard to find a solution for this easily , I think this might be too easy, too basic, thus no one bother to talk about it.  but I do find some clues, When Visual Studio compile the solution , it will try to make sure every logic path is correct.  Then I go back to visit my orchestration, assume we get an exception in the scope , during the dynamic mapping.  here is the flow. 
1.receive a message from the port. 
2.construct the response message.
3.do the dynamic mapping. here we get an exception.
4.it jump to exception handling.
5.construct fault message
6.send the fault message back to client. 
7 then the flow continue to send a response back. 

You see the issue, after you send a fault message back to client, the whole channel had been faulted, how could we send  a response back client again?

In order to resolve this issue, I simple put a terminate shape after send the fault message back , then it compiles and works smoothly.  The orchestration looks like this.

It puzzled me a while as new BizTalk developer. when you get it , it is so easy.


Monday, March 12, 2012

AQGridView, load AQGridCell from xib file

Recently I am working on an app , which will need to use AQGridView, which will allow me to present my content in a grid format.
Like the UITableView, we need to implement a class to draw the cell content, and this class should inherit from AQGridCell.  the downside of this method is , we need to draw the whole cell UI use code, if it is simple cell , that should be fine. but I don't want to write too much code which can be done with a xib file. so I was thinking how to load a xib file on the fly. it does take me sometime to figure it out, thus I write it down, hope someone else still want to do the same thing can benefit from this, also for myself , if later on I need to implement similar features, I can come back to read it, my long term memory is bad.

So here it is.
First of all, I create a class and inherit it from UIView,


#import <UIKit/UIKit.h>

@interface TVViewCellWithUI : UIView
{
    
}

Then I create a xib file call it , TVViewCellWithUI.xib, pretty simple , put one UIImagView and a couple labels on it, 
On the view, I set the view is "TVViewCellWithUI" 

Then I can create outlet, actions stuff with drag and drop in TVViewCellWithUI class. 


then , the tricky part is , how I create the AQGridCell ,  refer to the following snapshot. 


so what I did is , first of all I create an instance of TVViewCellWithUI and then use NSBundle to load the TVViewCellWithUI xib file dynamically.  after that , assign the first element of the array to TVViewCellWithUI instance.
TVViewCellWithUI *vClass = [[TVViewCellWithUI alloc] init];
        NSArray* array = [[NSBundle mainBundle] loadNibNamed:@"TVViewCellWithUI" owner:vClass options:nil];
        
        vClass = [array objectAtIndex:0];

Note, NSArray* array = [[NSBundle mainBundleloadNibNamed:@"TVViewCellWithUI" owner:vClass options:nil]; the type of owner parameter should match with the type of the root view which we specified in the xib file, in my cause it is TVViewCellWithUI. 

if a different type of instance has been passed in as the owner, you will get unexpected result, for me , the function will stuck there without return control to you. 

after all these , create an instance of AQGridViewCell , and also add the TVViewCellWithUI into 
filledCell = [[AQGridViewCell alloc] initWithFrame:vClass.frame reuseIdentifier:FilledCellIdentifier];
        [filledCell.contentView addSubview:vClass];

In this way, we can take advantage of the xib file which we can easily change the UI without writing extra code.