Tuesday, October 16, 2012

Web Scraping - Open Source .Net Libraries

Nowadays, everyone may need some data from internet for different purposes. Some may need listings of businesses that she have to work with, some may need some book listing that she will sell on her website, some may need entire data of a website, and this may go beyond your imagination. You never know who will need what.

This becomes a major problem and companies or individuals seek for solutions. Here you can guess manual data entry as a solution, indeed it may be a solution but when the problem gets bigger you have to spend that much time on manual data entry. 
There is an alternative solution which is called Web Scraping. Scraping action is accomplished with automated software. In my case, I use .Net and tried several different libraries. I may list them as Watin, WebZinc, HtmlAgilityPack and HtmlAgilityPack's wrapper Fizzler. I will try to explain their differences.

Let me start with WebZinc. I found it when I needed it actually. A former client requested it to be used as main component of scraper application. It is not totally open source but you can use it as free or just buy it for 99$. When you use it for free, it pops up an alert window which requires you to click "OK" each time application runs. WebZinc has ability to visual browsing, which means that it initiates a browser instance and you can see what is going on. It also has non-visual methods which is good for applications which will run simultaneous or on a web server.

Watin is another option for web scraping, which I usually use. It requires you either choose Firefox or IE as visual browser. It basically manages that browser instance so you can check status of web pages and what is going on. You should choose IE which is better since Watin supports Firefox 3.6.28 which is very old. Watin has better documentation than WebZinc since it is very hard to find anything on google about WebZinc. Using Watin convention is simple, it has objects for almost each Html tag like Table, TableRow, TableCell, Form, Div, Button, Image, Para (which is actually p tag), List (ul or ol element), ListItem (li element), etc. Each of these objects have almost same actions like you can simply just call .Click() method to click on that element.

HtmlAgilityPack is the last option that you may use. This is not as functional as Watin, like you have to code a lot to just simply mimic click action of a button. It is good for solid Html text where you do not need to post or get anything via buttons or javascript. It is based on Webclient so you can use proxies easily and just parse the acquired html. It is actually based on XPath to select Html elements. If you have to use HtmlAgilityPack, then you need to use something on top of it, or you have to write your own Wrapper library.

Fizzler uses HtmlAgilityPack at basic level and adds some more functionality to it. But not more functional than HtmlAgilityPack. It adds css selector ability and you easily adapt if you are familiar with javascript.

As a conlusion, I prefer Watin, but in some cases it is not enough or suitable for web scraping. I will write more about Watin on later posts.

Let me know if anything missing or there is a mistake.
Mehmet.

Friday, September 21, 2012

DropDownListFor vs ListBoxFor in Asp.Net MVC

Our task was simple as changing DropDownListFor into ListBoxFor. It does not return any errors on compile time when you just change DropDownListFor into ListBoxFor. But it is not that simple.

We did use MultiSelectLists to populate our DropDownList and it was working just fine until we decided to change it into ListBoxFor. Then we thought that there is something that we have missed. Our DropDownListFor was in the following format,

          <%:Html.DropDownListFor(
                    x => x.ContacId,

                    new MultiSelectList(Model.Contacts, "ContactId", "ContactName"))%>

It is just a simple dropdown, which have element id as ContactId, and text as ContactName. The populating IEnumerable was Model.Contacts. So far it is just fine and working well.

Then we need to change this into ListBoxFor since user needs to select multiple elements and dropdown component is just not enough for it.

When you just change dropdown into listbox it seems fine until you run the page. We got source is null error and at first glance did not have any idea about it. After some google searches we found a solution which simply indicates that listboxfor needs selected element list as first argument not id of select list (in this case it is ContactId).

We modified our model with a new list which just contains selected items in listboxfor. So our listboxfor turned into following,

          <%:Html.ListBoxFor(
                     x => x.SelectedContacts,

                    new MultiSelectList(Model.Contacts, "ContactId", "ContactName"))%>

You have to simply indicate selected items as a list since it has the ability to select multiple items.

Hope it helps,
Have a nice day.

Mehmet

Sunday, September 16, 2012

OCR with MODI.dll (Microsoft Office Document Imaging)

Before starting with MODI.dll, I have to explain what OCR is. Converting images into text is called OCR (Optical Character Recognition). For example pdf files those are screenshots of a plain text page, can be converted into Microsoft Word files and this process requires OCR and this can be done in many ways.

There are lots of solutions which offers OCR in similar ways, some of them can be multilangual and some others can be better at recognizing only some set of fonts. Some of them can be open source and some others can require some licences.

If you need to use open source library, then I suggest you to start with Google's Tesseract. You can find some different C# wrappers like TessNet2, but it currently uses Tesseract2 and I suggest you to wait for a Tessseract3 wrapper.

I dig into Tesseract and at some point I was training my own font to improve results but then I decided to try other options since training is a little bit tricky and I will share it later. Then I found MODI and it actually does almost perfect OCR except that it requires Microsoft Office licence (I guess).

MODI was actually built in OCR dll which existed in Microsoft Office 2003 and 2007 but not in 2010 directly. They have moved MODI into OneNote 2010 but it is a different world.

If you have 2003 or 2007 Office then you just have to include Microsoft Office Document Imaging in your Office configuration. (Software -> Edit Microsoft Office Installation -> Add/Remove Components -> Office- Tools -> Microsoft Office Document Imaging has to be installed.)

If you do not have Office 2003 or 2007 like me, then you just have to get it from Microsoft website. Most simple way is to download this, and when you launch the setup click custom install, disable all components and under Office-Tools, enable just Microsoft Office Document Imaging. Then complete the install, and you should be able to add MODI as reference in your Visual Studio Solution. Other then that, in Start menu you can find an api for MODI under Microsoft Office Tools and try how good it is.

At this point, you have all you need to start OCR with MODI. For best results, I suggest you to save your images in TIF format, and then run OCR with  MODI. Let me share my sample code, then you can develop your own methods.

I usually save images to a location and then use OCR so you can do that by web request.


            byte[] imageBytes;

            HttpWebRequest imageRequest = (HttpWebRequest)WebRequest.Create(imageUrl);
            WebResponse imageResponse = imageRequest.GetResponse();
            Stream responseStream = imageResponse.GetResponseStream();
            using (BinaryReader br = new BinaryReader(responseStream))
            {
                imageBytes = br.ReadBytes(1500000);
                br.Close();
            }
            responseStream.Close();
            imageResponse.Close();

            FileStream fs = new FileStream(saveLocation, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            try
            {
                bw.Write(imageBytes);
            }
            finally
            {
                fs.Close();
                bw.Close();
            }


You can directly save downloaded image as tif or png but most ocr libraries requires TIF with no compression method so that we have to manipulate saved image with following code.

First we get saved image into a Bitmap. Then you should do the manipulations those are necessary. For example, I needed to extend image size by 4, and then I choose interpolation mode, smoothing mode and compositing quality to achieve better image quality for OCR.

Then you should pass encoder info as TIFF and in encoder parameters you should select it as last frame and compression none. Actually in a single tiff file you can add several images, so if you select last frame as multi frames then you can add more images into it. I should write about it as well in another day.


                    Bitmap bmp = new Bitmap("savedImage.png");

                    Bitmap dst = new Bitmap((int)(bmp.Width * 4), (int)(bmp.Height * 4));
                    using (Graphics g = Graphics.FromImage(dst))
                    {
                        Rectangle srcRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                        Rectangle dstRect = new Rectangle(0, 0, dst.Width, dst.Height);

                        g.InterpolationMode = InterpolationMode.HighQualityBilinear;
                        g.SmoothingMode = SmoothingMode.AntiAlias;
                        g.CompositingQuality = CompositingQuality.GammaCorrected;

                        g.DrawImage(bmp, dstRect, srcRect, GraphicsUnit.Pixel);
                    }

                    ImageCodecInfo encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");

                    EncoderParameters encoderParams = new EncoderParameters(2);
                    EncoderParameter parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionNone);
                    encoderParams.Param[0] = parameter;
                    parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.LastFrame);
                    encoderParams.Param[1] = parameter;

                    Image tif = (Image)dst;
                    tif.Save("fileName.tif", encoderInfo, encoderParams);


At the end we save our image file with the extension .tif. Here comes the best part where we do OCR. You should initialize MODI and then set our tif file's path and we will be good to go.


                    MODI.Document doc = new MODI.Document();
                    doc.Create("savedImage.tif");
                    doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, true, true);
                    MODI.Image img = (MODI.Image)doc.Images[0];
                    MODI.Layout layout = img.Layout;
                    string text = layout.Text;


Now text variable contains our image content and you can use it as you wish.

Have a nice day.

Mehmet.



Wednesday, July 11, 2012

How to Add Attribute ID to Telerik MVC Window When Creating in Javascript

In my previous post I mostly explained how to open a Telerik window in javascript. I use this function in generic format from all over the application, I simply set url, title and id to pass as arguments and rest is the same. Using ViewInPopup for function name also.

 You may need an id for this popup window since you open it via javascript and in some cases manually closing may be needed. For these cases we will just add .attr('id','id-to-give'); to our window element and the last version of our function will be like,



    function ViewInPopup(url, id, title) {
        $.ajax({
            type: 'POST',
            url: url,
            data: { Id: id },
            dataType: 'html',
            success: function (htmlData) {
                var windowElement = $.telerik.window.create({
                    title: title,
                    html: htmlData,
                    contentUrl: "",
                    actions: ["Maximize", "Close"],
                    modal: true,
                    width: 500,
                    height: 500,
                    resizable: false,
                    draggable: true,
                    scrollable: true,
                    onClose: function () { }
                });
                windowElement.attr('id', 'popupWindow');
                var win = $(windowElement).data('tWindow');
                win.center().open();
            }
        })
    }



Now you can access this window by id. One more thing to mention, you can close window but you may also  need to destroy it.



    function closeWindow(id) {
        $("#" + id).data('tWindow').close();
        $("#" + id).data('tWindow').destroy(); 
    }


If there are any mistakes, let me know.

Regards,
Mehmet.

Tuesday, July 10, 2012

Telerik MVC Treeview, How to Add CRUD (Edit Create Delete) Buttons, With Popup Window

Telerik MVC users may have known this issue but Treeview absolutely needs some modifications to look like rest of the telerik components. So we have decided to add Edit and Delete button like Grid control on each line. Then we will add Create button on the toolbar. And both Create and Edit will work in popup window.

EDIT: Treeview does not include window.js so we need to register it manually.

<%: Html.Telerik().ScriptRegistrar().jQuery(false).DefaultGroup(group => group.Add("telerik.window.min.js").Add("telerik.draganddrop.min.js"))%>

Adding Edit and Delete buttons on each row is a javascript trick, written by Umut Yıldırım. We simply get each item and append button html before or after text div. Normal Treeview item has following <li> structure,



     <li class="t-item">
          <div class="t-mid">
               <span class="t-in">Item Text</span>
               <input class="t-input" name="itemValue" type="hidden" value="7" />
          </div>
     </li>


What we need to do is adding <a> tags before input or before span. If we add before span then icons will appear at the beginning of ItemText, if we add before input then icons will appear at the end each line.

We first add an onLoad event to Treeview,

     events.OnLoad("TreeView_OnLoad");

Then the javascript function which adds our html-to-add before span so it will be at the beginning of item.



     function TreeView_OnLoad(e) {
          var allNodes = $("li", getTreeView().element);
          allNodes.each(function (index) {
               var item = allNodes[index];
               var text = getTreeView().getItemText(item);
               var value = getTreeView().getItemValue(item);
               $(this).find("span:first").before("html-to-add");
          });
     }

If we add before input then it will be at the end, and javascript is as follows,


     function TreeView_OnLoad(e) {
          var allNodes = $("li", getTreeView().element);
          allNodes.each(function (index) {
               var item = allNodes[index];
               var text = getTreeView().getItemText(item);
               var value = getTreeView().getItemValue(item);
               $(this).find("input:first").before("html-to-add");
          });
     }

Then our html-to-add will be as follows, (I changed the classes wrt Gridview button classes so buttons will be same as gridview buttons.)

     <a href="href-address" class="t-button"><span class="t-icon t-edit"></span></a>


     <a href='#' class="t-button" onclick="..."><span class="t-icon t-delete"></span></a>

As you can see the <a> elements are similar but spans make the difference. If span has class t-edit then it will be edit icon, if it has t-delete then it will be delete icon.
You can modify href or onclick attributes as you desired. If we are going to open a window then we need to put href as "javascript:functionName(arguments)". But for delete button just onClick function is also enough.

For Delete, you can use following javascript function, just a simple function that posts to urlm with given Id. You can change Id and add more parameters, of course method in urlm has to have same parameters and return JsonResult with here Message value. In success part, we remove node with javascript so you will not need to post page again.


     function Delete(argument) {
        var con = confirm("...");
        if (con == true) {
            $.ajax({
                type: "POST",
                url: urlm,
                data: { Id:  argument },
                success: function (response) {
                    var treeView = getTreeView();
                    var node = treeView.findByValue( argument );
                    treeView.remove(node);
                    alert(response.Message);
                },
                error: function (xhr, status, error) {
                    alert(error);
                }
            });
        }
    }

For Edit, we need a little more complicated process since we need to open a popup first then load Partial View with given model.
Followint ViewInPopup function opens a telerik window and then post to the given url with given parameters. Then we will load partial view in the given url. Given arguments can be changed but the names have to match with target url's arguments.



    function ViewInPopup(url, id, title) {
        $.ajax({
            type: 'POST',
            url: url,
            data: { Id: id },
            dataType: 'html',
            success: function (htmlData) {
                var windowElement = $.telerik.window.create({
                    title: title,
                    html: htmlData,
                    contentUrl: "",
                    actions: ["Maximize", "Close"],
                    modal: true,
                    width: 500,
                    height: 500,
                    resizable: false,
                    draggable: true,
                    scrollable: true,
                    onClose: function () { }
                });
                var win = $(windowElement).data('tWindow');
                win.center().open();
            }
        })
    }

For edit, we can give url like /Controller/OpenEditPopup to ViewInPopup function and it posts to OpenEditPopup action which is as follows. As you may noticed naming convention of Id is same. We can get model with Id and we will pass to PartialView which expects that type of model.

    public ActionResult OpenEditPopup(int Id)
    {
        ...Get model here and pass to Partialview
        return PartialView("PartialViewName", model);
    }

Above code snippet will load PartialView in our window element.Then you can modify your partial view as you like.

Then we will add Grid-like toolbar and Create button. To achieve this you can inspect Gridview element, and the html tags are as follows. We put this just above Html.Telerik().TreeView().


     <div class="t-widget t-grid" id="GridBox">
            <div class="t-toolbar t-grid-toolbar t-grid-top">
                <a class="t-button t-button-icontext t-grid-add" href="#" onclick="AddNew();">
                    <span  class="t-icon t-add" style="margin-left: 0"></span>Add New</a>
     </div>

Then we close the open div right after treeview by </div>.
Here in toolbar we just added Add New button which will look just the same as normal telerik create button. The <a> element and its inner elements are for creating button. The rest is just for toolbar.

In create, the structure will be like Edit and you can give any function as you wish to onclick event. If you want to open in new window, you can use ViewInPopup and direct it to your OpenCreatePopup function which will load your partial view.

So, I have just explained how to put CRUD operations to Telerik MVC Treeview and how to open Create and Edit in popup with partial view.

If there is any typing errors or any mistakes let me know.

Regards,
Mehmet.

ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

In a transactional connection you might get the error mentioned above. It has a simple solution but we encountered it when switching from Oracle connection to Sql connection.

Oracle Data Access component (ODP Dot Net) actually runs very well without setting command transaction. The following code will work fine with an oracle database (just demonstration, syntax may change)

     using(OracleCommand = oracleConnection.CreateCommand())
     {

          oracleConnection.Open();
          OracleTransaction =  oracleConnection .BeginTransaction();


           OracleCommand.CommandText = "Procedure Name";
           OracleCommand.CommandType = CommandType.StoredProcedure;
           OracleCommand.Parameters.Clear();
           OracleCommand.Parameters.Add(...Add Parameters...);
           OracleCommand.ExecuteNonQuery();
     }

But in sql connection, we get "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction.  The Transaction property of the command has not been initialized." error, since we actually did not set the transaction property.

OdpDotNet actually handles this but SqlConnection and SqlCommand can not. So we change our Sql code block with transaction version. Which is as follows,



     using (SqlConnection conn = new SqlConnection(connectionAddress))
     {
          SqlTransaction trans = null;
          try
          {
               conn.Open();
               trans = conn.BeginTransaction();
               using (SqlCommand comm = conn.CreateCommand())
               {
                    comm.CommandText = item.Sql;
                    comm.Transaction = trans;
                    comm.CommandType = CommandType.StoredProcedure;
                    comm.Parameters.Clear();
                    comm.Parameters.AddWithValue(parametreItem.Key, parametreItem.Value);
                    comm.ExecuteNonQuery();
               }
               trans.Commit();
          }
          catch (Exception ex)
          {
               trans.Rollback();
               throw ex;
          }
          finally
          {
               trans.Dispose();
               conn.Close();
          }
     }


If there is any mistakes let me know, so I can fix :)

Regards,
Mehmet.

Tuesday, June 19, 2012

Grid Row Html Attributes & Row Color in Telerik MVC Grid

There are two ways of get this done in Telerik MVC Grid component.

If you are using server side binding, I think it is a little handy in several cases. You can add this in your aspx page to Grid component:


        .RowAction(row =>
        {
            if (row.DataItem.GridKey == 2012)
            {
                row.HtmlAttributes["style"] = "background:red;";
            }
        })


You can custumize as you wish the string assigned to HtmlAttributes["style"] element. It will work the style element in a html tag.


If you are using Ajax binding that means you have to do the style thing in OnRowDataBound event. It has to be in javascript and sometimes you may not able to access your control attributes. Here is the code:



          .ClientEvents(events => events.OnRowDataBound("Grid_OnRowDataBound"))


         <script type="text/javascript">
          function Grid_OnRowDataBound(e) {
             if (e.dataItem.GridKey == 2012) {
                e.row.style.backgroundColor = "red";
             }
          }
          </script>



We have added the style attribute for each row seperately at OnRowDataBound event. You can add anything like font-size, bold or not, italic, etc.

If there is any mistakes let me know, so I can fix :)


Regards,
Mehmet.

Tuesday, June 12, 2012

Posting Xml to URL with Credentials

Posting an XML to an given URL make me search google over 3 hours but at last I managed to solve the problems and successfully posted my xml.

There are some tricks like length of content, encoding of stream writer, Flush method should be called, etc. Each will be mentioned seperately.

First of all we make a web request to start a post and we will get a web response in return.
Here are our variables,


            System.Net.WebRequest req = null;
            System.Net.WebResponse rsp = null;


You can put the code in a try catch since you will get some undesired responses when you first try. We define the uri and then give it to webrequest as parameter.


            req = System.Net.WebRequest.Create(uri);


We should provide credentials if the uri that we define will request username and password.


            req.Credentials = new NetworkCredential(Username, Password);


Then we define method and  content type of web request,


            req.Method = "POST";
            req.ContentType = "text/xml";


We should set our content length to the length of xml variable which is a string in our case. If you just use the length attribute of string then request will not be able to match the content length and actual length of xml and you will get the exception,

            Bytes to be written to the stream exceed the Content-Length bytes size specified.

We should get the length with an encoding as follows,


            req.ContentLength = System.Text.Encoding.UTF8.GetByteCount(xml);


After defining the length with an encoding, Stream Writer should have the same encoding too.


            StreamWriter sw = new StreamWriter(req.GetRequestStream(), new UTF8Encoding(false));
         
Then we call write method. Until we call flush no data actually will be written to stream and without calling flush, if you close the writer you will get the error,

            Webexception: The Request was aborted: The request was cancelled.

We should use the following order,

             sw.Write(xml);
             sw .Flush();
             sw .Close();

At the end we get response and you can check which type of response is returned.

            rsp = req.GetResponse();


Above code lets you post an xml file via web request to a destination Url.

Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.


Thursday, June 7, 2012

How to Open a Telerik MVC Window Element in Javascipt?

Telerik Window can be managed from javascript function easily. You can check possible function names and descriptions here.

There are different ways to open a window in javascript but important one is to open as centered. Lets assume that we created a window via javascript.


    var windowElement = $.telerik.window.create({
        title: "...",
        html: "<p>I'm a window...</p>"
        contentUrl: "",
        actions: ["Maximize", "Close"],
        modal: true,
        width: 500,
        height: 500,
        resizable: false,
        draggable: true,
        scrollable: false,
        onClose: function () { }
    });

You can open it by just the following line :

    windowElement.center().open();

This will open the window but not centered surprisingly. You will have to get .data element first and then call the open and center functions.

    var window = $(windowElement).data('tWindow');
    window.center().open();


Above code will allow you successfully open a centered window.


Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.

Telerik MVC Grid Detail Popup with Partial View (3)

This post is just an update to my previous post where partial view with Telerik Window is described. We will update just two steps and the rest will be the same but I will post all details including updated parts.

First we need a column command button in our grid.

        .Columns(columns =>
        {
            //Columns here
            columns.Command(commands =>
            {
                //Other commands
                commands.Custom("viewDetails").ButtonType(GridButtonType.Text)
                             .Text("Detail");
            }).Width(60);
        })

This time we need a different event instead of OnRowSelect.

       .ClientEvents(events =>  events.OnRowDataBound("OnRowDataBound"))

Then we need two javascript functions in script tags. First one will handle the OnRowDataBound event, and second one will handle OnClick event of our custom command button. Id is grid's routevalue, and we use custom command's id to locate our element, t-grid-viewDetails.

        function OnRowDataBound(e) {
            var id = e.dataItem.Id;
            $(e.row).find('a.t-grid-viewDetails').attr('href', 'javascript:ViewDetails_OnClick(' + id + ');');
        }

In the older version of this approach, we put window as invisible in the aspx page and then opened it in javascript function. Here, we will create window in the javascipt function and then open it.
As we create window in javascript, we no longer need hardcoded window in the aspx page, you can remove it. 

        function ViewDetails_OnClick(id) {            
            $.ajax({
                type: 'POST',
                url: '<%= Url.Action("Action", "Controller") %>',
                data: { Id:  id },
                dataType: 'html',
                success: function (htmlData) {
                    var windowElement = $.telerik.window.create({
                        title: "...",
                        html: htmlData,
                        contentUrl: "",
                        actions: ["Maximize", "Close"],
                        modal: true,
                        width: 500,
                        height: 500,
                        resizable: false,
                        draggable: true,
                        scrollable: false,
                        onClose: function () {
                             $("#popupWindow").data('tWindow').destroy();
                         }
                     });
                    windowElement.attr('id', 'popupWindow');
                    var window = $(windowElement).data('tWindow');
                    window.center().open();

                }
            })
        }

And at last, our action method did not change.

        public ActionResult Action(int Id)
        {
            //Prepare model for PartialView
            return PartialView("PartialViewName", model);
        }     

Above code pops up a detail window with your partial view when custom command is clicked.

Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.

How to add custom templates in Telerik MVC Dropdownlist/Combobox control?

In Telerik MVC application you can use either Ajax or Server binding for populating comboboxes. Here I did it via Ajax binding but you can do similar thing for Server binding also.

In our controller class we need a method which will return Json object after Ajax call. Telerik combobox/dropdownlist does support html tags inside its text value so we use this feature and replace text column with image tags we fill.


        [HttpPost]
        public ActionResult _AjaxFillCombo()
        {
            //Populate list with your object
            List<OurObject> list =  OurObjectService.GetAll();


            //Customize a column in the list
            foreach ( OurObject obj in  list  )
            {
                obj.ImageLink = //Add custom <img /> tag in here with required fields as src attribute.
            }
           
            return new JsonResult
            {
                //Return list as SelectList, set ImageLink as text attribute.
                Data = new SelectList(list.ToList(), "Id", "ImageLink")
            };
        }


Image tag can be as following,

      <img class='...' style='...' title='...' alt='...' src = '" + obj.imageLocation + "' />

After that we need to tell combobox/dropdownlist that binding will be via Ajax binding,

      .DataBinding(binding => binding.Ajax().Select(" _AjaxFillCombo ", "ControllerName"))


Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.

Wednesday, June 6, 2012

Telerik MVC Grid Detail Popup with Partial View (2)

Like my previous post, I will try to show another way to obtain detail view with partial view and popup. This time we will change button's href attribute and there will be no need for row selection.

First we need a column command button in our grid.



        .Columns(columns =>
        {
            //Columns here
            columns.Command(commands =>
            {
                //Other commands
                commands.Custom("viewDetails").ButtonType(GridButtonType.Text)
                             .Text("Detail");
            }).Width(60);
        })


This time we need a different event instead of OnRowSelect.


       .ClientEvents(events =>  events.OnRowDataBound("OnRowDataBound"))


As in the previous post, we have the same window.


<% Html.Telerik().Window()
        .Name("Window")
        .Modal(true)
        .Width(500)
        .Height(500)
        .Title("Window Detay")
        .Scrollable(true)
        .Draggable(true)
        .Resizable()
        .Visible(false)
        .Render(); 
    %>


Then we need two javascript functions in script tags. First one will handle the OnRowDataBound event, and second one will handle OnClick event of our custom command button. Id is grid's routevalue, and we use custom command's id to locate our element, t-grid-viewDetails.


        function OnRowDataBound(e) {
            var id = e.dataItem.Id;
            $(e.row).find('a.t-grid-viewDetails').attr('href', 'javascript:ViewDetails_OnClick(' + id + ');');
        }




        function ViewDetails_OnClick(id) {            
            $.ajax({
                type: 'POST',
                url: '<%= Url.Action("Action", "Controller") %>',
                data: { Id:  id },
                dataType: 'html',
                success: function (htmlData) {
                    $('#Window ').data('tWindow').content(htmlData);
                    $('#Window ').data('tWindow').center().open();
                }
            })
        }

And at last, our action method did not changed.


        public ActionResult Action(int Id)
        {
            //Prepare model for PartialView
            return PartialView("PartialViewName", model);
        }

       

Above code pops up a detail window with your partial view when custom command is clicked.

Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.





Telerik MVC Grid Detail Popup with Partial View

An easy way to achieve a popup detail window in GridView has to be the following solution (at least the easiest way I manage to find) :

First in the grid we set two properties (you may have set them already):

  •  .ClientEvents(events => events.OnRowSelect("OnRowSelect"))


  • .Selectable(selecting => selecting.Enabled(true))
Secondly we need a window to put our partial view in it. This part can be done in many ways but the trivial one is just put a telerik window on the same page with gridview.

<% Html.Telerik().Window()
        .Name("Window")
        .Modal(true)
        .Width(500)
        .Height(500)
        .Title("Window Title")
        .Scrollable(true)
        .Draggable(true)
        .Resizable()
        .Visible(false)
        .Render(); 
    %>

Later we need the javascript function OnRowSelect, either in a script tag or in a js file.
The Id field in the dataItem represents your routeValue which is set in the gridview. ActionName and ControllerName represents your action which returns PartialView.

         function OnRowSelect(e) {
            var dataItem = $('#GridName').data('tGrid').dataItem(e.row);
            var Id= dataItem['Id'];

            $.ajax({
                type: 'POST',
                url: '<%= Url.Action("ActionName", "ControllerName") %>',
                data: { id: Id},
                dataType: 'html',
                success: function (htmlData) {
                    $('# Window ').data('tWindow').content(htmlData);
                    $('# Window ').data('tWindow').center().open();
                }
            })
        }

As the final part we need the action class which responds our ajax post.

        public ActionResult ActionName(int id)
        {
            //Build model for partial view
            return PartialView("PartialViewName", model);
        }

Above code enables row selection and on row click a detail window pops up with your partial view in it.

Hope it helps.
P.S : If there is any typing or coding mistakes let me know. See you later.