November 2010 - Posts

Sencha How to

I’ve been following this since version 0.96 beta, now it’s already 1.0 released. there are some bugs fixed and enhancement on android, new model validation.

but let me recap what i do to use this sencha, this is OO extjs thing and component based. inside 1 control could be more items and so on to the child level below.

  • first of all pick your main Container, TabPanel,Panel, Vbox(vertical box), Hbox(horizontal box),fit(will try to fit in everything).

Choose whether to fullscreen (will append to document.body) or to a div (use renderTo:’divname’)

  • To override Icon on toolbar. it’s base 64 image.
   1: //toolbar
   2: {
   3: iconCls:askbtn
   4: }
   5: .askbtn {
   6:   -webkit-mask-box-image: url(data:image/png;base64,[Base64Encoded Image String]}
   7: }
   8:  

 

  • I found that when changing background, using componentCls(has effect but have to build all css for that component), or Cls (has no effect). the least way to change it without effecting the UI is by overriding it using !important, and remember all the css is webkit css3, you can do a lot more with css3 of webkit, transition effect, scale effect, gradient all just with webkit css3.use the online generator for grandient
   1: .x-toolbar-dark .x-button, .x-toolbar-dark .x-button.x-button-back::after, .x-toolbar-dark .x-button.x-button-forward::after, .x-toolbar .x-toolbar-dark .x-button, .x-toolbar .x-toolbar-dark .x-button.x-button-back::after, .x-toolbar .x-toolbar-dark .x-button.x-button-forward::after, .x-toolbar-dark .x-field-select .x-input-text, .x-toolbar-dark .x-field-select .x-input-text.x-button-back::after, .x-toolbar-dark .x-field-select .x-input-text.x-button-forward::after, .x-toolbar .x-toolbar-dark .x-field-select .x-input-text, .x-toolbar .x-toolbar-dark .x-field-select .x-input-text.x-button-back::after, .x-toolbar .x-toolbar-dark .x-field-select .x-input-text.x-button-forward::after
   2:  {
   3:      background-image:-webkit-gradient(
   4:         linear,
   5:         left bottom,
   6:         left top,
   7:         color-stop(0.19, rgb(0,247,255)),
   8:         color-stop(0.6, rgb(31,158,255))
   9:         )
  10:       !important;
  11: }
  12:  
  13: .x-button:hover,.x-button-back:hover
  14: {
  15:    background-image: -webkit-gradient(
  16:     linear,
  17:    left bottom,
  18:    left top,
  19:    color-stop(0.17, rgb(63,33,188)),
  20:    color-stop(0.59, rgb(95,60,226)),
  21:    color-stop(0.8, rgb(124,90,255))
  22:     background-color:White;
  23:     ) !important;
  24: cursor:pointer;
  25:  
  26: }
  • Display Error summary message on formpanel

I personally use fieldset and set or add the fieldset error message, so it looks like error message

  • There is this Formpanel submit Url which will serialize the field and values and post to it. but since I already make it before this, i use the hiddenValue field and save the value when submit click serialize with delimiter, and on the postback read the value. We have to use renderTo, because when fullscreen will be appended to body so outside of the Single Form of Asp.net .
  • How to do paging

Previously the paging would be added to the Store , but i haven’t check it. 1 way i accomplish this is to Add a handler and make the ajax request with PageIndex and PageSize which return Json

 

   1: //Global
   2: var pageIndex=1;
   3: var pageSize=8;
   4: ...
   5: //Get Template 
   6: var tpl = Ext.XTemplate.from('weather');
   7: ...
   8: //OnReady, get first Page
   9: var makeAjaxRequest = function() {
  10:            Ext.Ajax.request({
  11:                url: '../service/MobileHandler.ashx?page=something&pageindex='+pageIndex+'&pagesize='+pageSize,
  12:                success: function(response, opts) {            
  13:                var questionAnswers = Ext.decode(response.responseText);
  14:                var html=tpl.applyTemplate(questionAnswers);
  15:                html="<br/>"+html;
  16:                if(questionAnswers.length>0 && questionAnswers[0].DisplayMore==true)
  17:                {
  18:                html+="<div style='width:100%;padding:10px'><div style='width:200px;margin-left:auto;margin-right:auto'><input style='width:180px' type='button' value='Load More Entries' onclick='GetNext();'></div></div>";
  19:                }
  20:                else if(questionAnswers.length==0)
  21:                {
  22:                html+='<div style="padding:10px"><p>No [Object] found</p></div>';
  23:                }
  24:                Ext.getCmp('content').update(html);                  
  25:                }
  26:            })
  27:        };
  28:        makeAjaxRequest();
  29: ...
  30: //Outside of Ready
  31: var GetNextQuestionAnswers = function() {
  32: pageIndex++;
  33: //same Logic as makeAjaxRequest();
  34: }

You could also use the Store and first define your model, it has to mapped the same properties like the one returned from our handler.this is specially Used on the NestedList

   1: //register model First
   2: Ext.regModel('test',{
   3:         fields: [
   4:        { name: 'text', type: 'string' },
   5:         { name: 'leaf', type: 'bool' },
   6:          { name: 'Title', type: 'string' },
   7:           { name: 'Description', type: 'string' }
   8:             ]
   9: });
  10: //our store
  11: var store = new Ext.data.TreeStore({
  12:                model: 'test',
  13:                proxy: {
  14:                     type: 'ajax',
  15:                    url: '../service/OurHandler.ashx',
  16:                    reader: {
  17:                        type: 'tree',
  18:                        root: 'items'
  19:                    },
  20:                    extraParams:
  21:                                    {
  22:                                        page: 'custom1'
  23:                                    }
  24:                }
  25:  
  26:  
  27:  
  28:            });
  29: //our nested List
  30: NestedList = new Ext.NestedList({
  31:                fullscreen: true,
  32:                emptyText: 'No Photos Available',
  33:                useTitleAsBackText: true,
  34:                plugins: [new Ext.LeafSelectedPlugin()],
  35:                toolbar: {
  36:                    items: [docktoolbar]
  37:                },
  38:                store: store,
  39: ...
  • NestedList, in order to work, you have to have the correct structure of your json,the root for example you define items than it will go to the child of it and see more items.

when you define a leaf=true, than it will fire getDetailCard method. here you can define your own html.

 

   1: getDetailCard: function(record, parentRecord) {
   2:     //get Previous Parent Text
   3:     var PreviousCategory = parentRecord.subStore.data.items[0].data.text;
   4:    //do your logic
   5: }

a couple of event’s that might be useful or used is on ‘CardSwitch’ ,’itemtap’,’LeafSelected’

   1: NestedList.on('cardswitch', function(container, newCard, oldCard, index, animated) {
   2:               try {
   3:                   if (newCard.recordNode.isRoot == true) {
   4:             //do something
   5:             }
   6:             } catch (e) {
   7:                 console.log(e);
   8:             }
   9:         });            

 

  • To get a component , you have to define id on that component , and used the Ext.getCmp(‘name’);
  • Binding event is by the object.on(‘eventname’,function);
  • define the Scroll by vertical or horizontal when needed on the parent component
  • Carousel won’t work if not flex:1 or fullscreen.
  • For card type layout, use the setCard(html); it will override it
  • There are so many tricky part and the most important thing is Read and Browse the documentation and forum there are lots and much better now since last time Disappointed smileat lastttt
  • If you Put your code on the Ext.Setup({onReady:function(){ //here });  You will suffer a delay like 2-3 seconds. Workaround for this is to use
   1: Ext.regApplication({
   2:     launch: function() {
             Sweet!

 

When your app is on Landscape orientation:

on your panel set the monitorOrientation =True than when user change the view to landscape or back to potrait will fire OrientationChange event , here you can adjust all height and width

   1: navigation.on('orientationchange',function(panel,orientation,width,height)
   2:       {
   3:        navigation.setWidth(width);
   4:        navigation.setHeight(height)
   5:        if(orientation=='landscape')
   6:         {
   7:         //do on landscape
   8:        }
   9:         else
  10:         {
  11:             //do on potrait
  12:         }
  13: }

You can set your Toolbar to look a like with the Tab Bar Docked Bottom

   1: var bottomtoolbar = new Ext.Toolbar({ componentCls: 'x-tabbar', defaults: { xtype: 'tab', iconMask: true, ui: 'plain', iconAlign: 'left'}); 

You can set the Tilte of your toolbar which will make the title align center

On your NestedList, just use dockedItems to dock toollbar  Set the Title of that additional Toolbar on Top to the Text You’ve click using onCardSwitch Event

 

   1: getDetailCard: function(record, parentRecord) {
   2: //save category clicked
   3:                     PreviousCategory = parentRecord.subStore.data.items[0].data.text;
   4: }
   5:  
   6: NestedList.on('cardswitch', function(container, newCard, oldCard, index, animated) {
   7:                 try {
   8:                     if (newCard.recordNode.isRoot == true) {
   9:                         PreviousCategory = '';
  10:                         this.toolbar.setTitle('Select Category');
  11:                     }
  12:                     else {
  13:                         this.toolbar.setTitle(PreviousCategory);
  14:  
  15:                     }
  16:                 } catch (e) {
  17:                     console.log(e);
  18:                     this.toolbar.setTitle(PreviousCategory);
  19:  
  20:                 }
  21:             });

Now this is something cool. You don’t have to Store to cookie to persist value. there is this HTML 5 Local Storage. how to use it on sencha?:

  • define model
  • Set the Proxy ID or else it won’t persist the same object on page reload
  • use the Store functionality, add(), sync()
   1: Ext.regModel('samebilling', {
   2:     fields: [
   3: //to identify each record
   4:                 {name: 'id', type: 'int' },
   5:                 {name: 'ischecked', type: 'bool' }
   6:             ]
   7:             });
   8:  
   9:  
  10: var store = new Ext.data.Store({
  11:     model: 'samebilling',
  12:     proxy: {
  13:         type: 'localstorage',
  14:         id  : 'samebillingStore',
  15:         proxy: {
  16: //this is important or else won't saved correctly
  17:             idProperty: 'id'
  18:         }
  19:  
  20:     }
  21: });
  22:  
  23: ...
  24: {
  25:  
  26:                     xtype: 'checkbox',
  27:                     id:'shpsameasbilling',
  28:                     name: 'shpsameasbilling',
  29:                     label: 'Same As Billing Address',
  30:                     listeners:{    
  31:                         check: function(chkbox){
  32:                          issameasbilling=true;
  33:                         store.read();
  34:                        var sameasbilling= store.getAt(0);
  35:                         if (!sameasbilling) {
  36:                             sameasbilling = Ext.ModelMgr.create({
  37:                               id:1, ischecked:true
  38:                             }, 'samebilling');
  39:                             store.add(sameasbilling);
  40:                             store.sync();
  41:                         }
  42:  
  43:                         sameasbilling.set("ischecked", true)
  44:                         store.sync();
  45:                         }
  46:                         ,
  47:                         uncheck:function(chkbox){
  48:                          issameasbilling=false;
  49:                         store.read();
  50:                          var sameasbilling= store.getAt(0);
  51:                         if (!sameasbilling) {
  52:                             sameasbilling = Ext.ModelMgr.create({
  53:                               id:1, ischecked:false
  54:                             }, 'samebilling');
  55:                             store.add(sameasbilling);
  56:                             store.sync();
  57:                         }
  58:  
  59:                         sameasbilling.set("ischecked", false)
  60:                         store.sync();
  61:                         }                      
  62:                     }
  63:                 }
  64:  
  65:  
  66: //Some where on Launch or OnReady ..
  67: //Read the Values Stored
  68: store.read();
  69:       var sameasbilling= store.getAt(0);
  70:       if (sameasbilling) {
  71:            var chkbox=Ext.getCmp('shpsameasbilling');
  72:            if(sameasbilling.data.ischecked==true){
  73:              chkbox.check();
  74:            }
  75:            else
  76:            if(sameasbilling.data.ischecked==false){
  77:            chkbox.uncheck();
  78:            }
  79:       }
Share this post: | | | |
Posted by cipto with no comments

Optimizing telerik Winform

http://www.telerik.com/support/kb/winforms/general/performance-considerations.aspx

Wow after doing this Theme thing enhancement, which is built by using telerik own framework outside of wpf the loading and stall are gone.

Instead of create/drag and drop each Theme to each form. if you're on MDI initialize it for once then set it using ThemeResolutionService, For Example:

public MDI()

{

InitializeComponent();

//set to indonesian

Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("id-ID");

new Office2007BlackTheme().DeserializeTheme();

ThemeResolutionService.ApplicationThemeName = "Office2007Black";this.ThemeName = "Office2007Black";

}

All of the child form controls will use that office black theme

Enabling the RadGridView EnableFastScrolling to True also speed up things.

Put all logic of setting Grid between the RadGridView.BeginUpdate() and EndUpdate(), and also set

RadGridView.MasterTemplate.BestFitColumns() if you don't mind it's shrink, to speed up again.

I haven't Execute the virtualmode because i need the Filtering feature.

 

Share this post: | | | |
Posted by cipto with 1 comment(s)
Filed under:

Building a Restful Services with asp.net mvc 2 , returns XML/Json

At first I’m thinking of doing this using webservice and basic soap header authentication.

but then after thinking a while , considering of lightweight, cross platform services, and easy to code and structural. I finally make my decision to move this type of project to be under asp.net mvc2.

  • by default it uses IHttpAsyncHandler,
  • i don’t have a View except for the Home->Index , which is a perfect place for documentation of the service
  • on Controller now Return ActionResult, which i than can reuse the code on other method
  • Use Routing which than make easier for other user to remember
  • Straight forward HttpPost and Get with Nice Folder Structural, “a mail without the envelope” Smile

under Model ,

  • I add folders based on controller Name , and put the Class file in it
  • For what ever relates to database i named it [Controller]Repository.cs and also create the interface and implement it
  • for other than which related to business logic let’s called it [Controller]ViewModel.cs

For Global/Common Class:

  • I simply make new folder called it common, here is the utility class, Error Number Enum and all class act as global related to that application

View

  • By default add View under a View->[Controller] Folder
  • add Master Page on the Shared

Now we make new class which Inherit from Action Result, Action Result only have a abstract method ExecuteResult.

   1: public class MyResult<T>:ActionResult
   2:     {
   3:         public T Data { get; set; }
   4:         public MyResult(T data)
   5:         {
   6:             this.Data = data;
   7:         }
   8:         public override void ExecuteResult(ControllerContext context)
   9:         {
  10:           string dataTypeReturn=context.RouteData.Values["datatype"].ToString();
  11:           if (dataTypeReturn == "xml" && this.Data != null)
  12:           {
  13:               var xmlserializer = new System.Xml.Serialization.XmlSerializer(this.Data.GetType());
  14:               context.HttpContext.Response.ContentType = "text/xml";
  15:               xmlserializer.Serialize(context.HttpContext.Response.Output, this.Data);
  16:               
  17:           }
  18:           else if (dataTypeReturn == "json" && this.Data!=null)
  19:           {
  20:               HttpResponseBase response = context.HttpContext.Response;
  21:               JsonTextWriter writer = new JsonTextWriter(response.Output) { Formatting = Formatting.Indented };
  22:               var SerializerSettings = new JsonSerializerSettings();
  23:               JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
  24:               serializer.Serialize(writer, Data);
  25:               writer.Flush();
  26:               context.HttpContext.Response.ContentType = "application/json";
  27:           }
  28:         }
  29:     }

I use the NewtonSoft Json dll for the json, yes i know on 3.5 there is jsonserializer. but i choose this one.Below is just an example on how to use it, just to get the idea

   1: public ActionResult Login(string dataType, string username,string password)
   2:        {
   3:            try
   4:            {
   5:                if (Membership.ValidateUser(username, password))
   6:                {
   7:                    var result = memberDetailsRepository.Login(username);
   8:                    if (result == null)
   9:                        return Utility.SetError((int)ErrorNumber.AccountNotExists, "Account does not exists");                    
  10:                    return new MyResult<LoginResult>(result);
  11:                }
  12:                else
  13:                    return Utility.SetError((int)ErrorNumber.AccountPasswordIsWrong, "Password is wrong");
  14:  
  15:            }
  16:            catch (Exception ex)
  17:            {
  18:                return Utility.SetError((int)ErrorNumber.Unknown, "Unkown");
  19:  
  20:            }
  21:           
  22:        }

what really nice on mvc is the separation, and i can use the logic of the controller in another controller Method. because of the action result being returned you can than examine the result.

the pattern of the service is : {controller}/{action}/{methodname}/{datatype}/{parameter1}/{parameter2} .. n

now another thing that we will dealing with is , does my Url works with Routing, does it Forwarding correctly?

  • Use Route Debugger to see, whether the url you type in , fall into the correct Routing you add on global.asax
  • if you declare parameter1 and parameter2, on your controller you must have the Exact Same name or else it will passed in Null
   1: routes.MapRoute(
   2:               "Custom",
   3:               "{controller}/{action}/{datatype}/{id}",
   4:               new { controller = "home", action = "Index", datatype = "xml", id = UrlParameter.Optional }, new { datatype = "xml|json" }
   5:            );
   6:            routes.MapRoute(
   7:             "Custom2",
   8:             "Login/{action}/{datatype}/{username}/{password}",
   9:             new { controller = "home", action = "Index", datatype = "xml", username = UrlParameter.Optional, password = UrlParameter.Optional }, new { datatype = "xml|json", username = @"\w", password =@"\w"}
  10:          );

For Default Parameters, it’s important as What MVC must have is Controller and Action

if you don’t have on your URL pattern you supply it on the defaultparameters Object(2nd parameter), as for the 3rd is the constraint you can put any Regex for the parameter.

the Validation work on conjuction with dataAnnotation model from 3.5, which you can define as an external partial class using metaAttribute .

I think the Must follow rule is: Never make a Response.write or anything that relate to the View on the Controller Action, or else  you will break the idea of separation.

the controller method must return something even yield an error object, It make sense so that your Controller Action can be reused somewhere else and testable.

when you are using UnitTesting and on you controller action logic there is tryupdatemodel , will not work. this bugs is known on MVC RC2 but still occured on released version.(ah it’s because the controllerContext is null, i don’t see the message Open-mouthed smile)

Unit Testing With Form Collection, Post Action

wow after go here and there and try to see the source code.

there 2 ways to debug and step into the mvc source:

We can Step through using the mvc source code or Download the debug symbol from microsoft debug server. I finally understand how it works. So in order to test this type of Post:

  • we need to fake the ControllerContext using moq
  • set the Controller.ValueProvider.
  • and if our action method is Strong typed, which mvc will try to mapped it using the DefaultModelBinder class on the GetparametersValue. the end result is if it’s not there it will be the default value, if string than that property is null. so let’s assume it’s already converted and just pass it in
   1: [TestMethod]
   2:        public void ContactInsertLastNameRequired()
   3:        {
   4:            var ordercontroller=new OrderController();
   5:            var formcollection = new ContactInsertReturnContacttIDModel();
   6:            formcollection.FirstName="Cipto";
   7:  
   8:           //ordercontroller.ValueProvider = formcollection;
   9:            var request = new Mock<HttpRequestBase>();
  10:            request.Setup(r => r.HttpMethod).Returns("POST");
  11:            //mock the httpcontext
  12:            var mockHttpContext = new Mock<HttpContextBase>();
  13:            mockHttpContext.Setup(c => c.Request).Returns(request.Object);
  14:            //fake controllercontext
  15:            var controllerContext = new ControllerContext(mockHttpContext.Object
  16:            , new RouteData(), new Mock<ControllerBase>().Object);
  17:            
  18:            ordercontroller.ControllerContext= controllerContext;
  19:            //fake one, just so that it doesn't failed
  20:            ordercontroller.ValueProvider = new NameValueCollectionValueProvider(new System.Collections.Specialized.NameValueCollection(),new System.Globalization.CultureInfo("en-US"));
  21:            var isrequestvalid=ordercontroller.ValidateRequest;
  22:            //MVC will use the DefaultModelBinder to bind each form keys collection to mapped to the mvc model
  23:            //if not found that model property will result null, so let's just assume it's already Converted to the strong typed object
  24:            //just pass it through
  25:            var returnresult=ordercontroller.ContactInsertReturnContacttID("xml", formcollection);
  26:  
  27:            var expectedResult = new MyResult<Error>(new Error() { Code = (int)ErrorNumber.LastNameRequired });
  28:            Assert.AreEqual(((MyResult<Error>)returnresult).Data.Code, expectedResult.Data.Code);
  29:        //
  30:        }
Share this post: | | | |
Posted by cipto with 1 comment(s)