Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

TIP: Managing BindingSource Position in Data Driven WinForms

Posted by Keith Elder | Posted in .Net, Programming, Smart Clients | Posted on 28-06-2006

12

If you are working with a Windows Form where a user can create and edit data in the same form you may run into the problem of trying to set the BindingSource to a given record in a DataSet you want to work with. 

For example let’s say you have a DataGridView in a Smart Client.  When the user double clicks a given row in the DataGridView a form opens so they can edit the data.  More times than not (no matter how many demos you watch) user’s do not edit data values in DataGridViews.  Although this is a supported feature, business objects are too complex.  Imagine having to edit a contact in a single row in Outlook for example, not fun and not very user friendly.  Why every Microsoft demo I watch shows editing in DataGridViews is beyond me.  I digress though.

When the new form is instantiated we need to pass two things:  the dataset we are working with, and the IDof the item we want to edit.  We can pass this information into the constructor of the form without any trouble as seen below. By passing in the DataSet we can add new records, delete records or whatever we need to do.  The other benefit is since the dataset is passed by reference, any changes to it will automatically appear in the row the user just double clicked on.  In order for the form fields to be auto bound to the record the user clicked on we need to set the DataBinding of the controls in the form to a BindingSource.  The BindingSource serves as the go between between the UI and data store.    Here’s a sample “CellDoubleClick” event that would happen in the DataGridView:

    1    int id = Convert.ToInt32(DataGridView.Rows[e.RowIndex].Cells[0].Value);

    2             MyForm myForm = new MyForm(dataSet, id);

    3             myForm.Show();

As the form loads the problem we face is having to tell the BindingSource in the form which record we want to set as the BindingSource.Current item.  At first glance it looks like we would just get the DataRow and then set it as the Current property.  Wrong.  The BindingSource.Current property has only a get accessor.  Instead we need to use the BindingSource.Position property.  Note:  Any change to the position property updates the current property used by the bindingsource.  The problem we face now is the BindingSource.Position property wants to know the index of the item in the underlying DataSource.  

We don’t know the index value used by the BindingSource but we do know the ID we want to use.  This is where the BindingSource.Find() method comes in.  Using the find method we can basically search the underlying datasource and retrieve the index of a given item.  Here’s an example:

contactBindingSource.Position = contactBindingSource.Find(“Id”, 2);

Once the line above runs, it is going to search the column “Id” in the DataSource associated with the BindingSource and return the index of that item. 

What if you use the same form to create a new item?  Simple, call the BindingSource.AddNew() method which will add a new item to the underlying DataSource.  Then move the index to the last item.  Here’s a sample:

      bindingSource.AddNew();
      bindingSource.MoveLast();

Since items are always added at the end of the associated data source the MoveLast() method will set the index to the last item in the underlying datasource.

I hope this makes sense because it is an easy way to have a form bound to a DataSet and use the same form to perform “CRUD” operations with.

Setting Up ClickOnce Certificate Files

Posted by Keith Elder | Posted in .Net, Smart Clients | Posted on 26-06-2006

0

Looks like Brian Noyes stole my thunder for a blog post I was going to do soon.  I get asked the same question.  “How do you sign your ClickOnce program with a valid provider like Versign?”. 

Unfortunately for myself, I had to figure this out the hard way last year during the VS2005 beta when I had to publish the new CRM app out with a Go Live license.  It’s a wonder I was able to piece all of the pieces together.  Call it a true testament to my genius.

Thanks to Brian for putting this together. If I get hit by a bus now at least someone else on my team can figure it out instead of wasting endless hours reading docs.  Why this type of content isn’t standard help on MSDN I have no idea.  I was talking to someone at Tech Ed who was responsible for the content on MSDN (sorry, can’t remember her name) and expressed my concern that they should catalog what blogger’s write about and turn them into docs.  It isn’t that hard to read the forums, newsgroups etc.  If two people have had the same problem, it should be documented and searchable on MSDN.

Video Cast: Building Three Tiered Solutions in Visual Studio and Team Foundation Server

Posted by Keith Elder | Posted in .Net, Asp.Net, Programming, Smart Clients | Posted on 21-06-2006

0

One of the biggest challenges I see team members at work struggling with when trying to learn .Net is “how to get started”.  If you are a developer with lots of experience, coming into VS and .Net things are very different let’s face it.  For example, what’s the right way to setup a project?  What’s the difference between a solution and project?  Everyone knows about n-tiered architecture, but how do you pull it off in Visual Studio?  If you are using TFS how do you setup projects so they can be easily versioned?  How do you organize the name spaces of projects?

I put together this video cast which is about 30 minutes long which I hope addresses some of these questions.  It should serve as a good starting point as how to setup a project when starting out, things to think about like namespaces and how to name your projects.  I’ve built a lot of production apps over my time and what is in the video is all based on experience so if you know of an “easier / better” way please drop me a line.  In the future things like GAT (guidance automation toolkit) will provide an easier way to accomplish what I’ve outlined in the video.  If you haven’t looked at GAT, you should definitely do so. 

Watch The Video Cast

(this is a repost of a post that was lost due to data loss)

Calling Multiple Web Services Asynchronously

Posted by Keith Elder | Posted in .Net, Asp.Net, Programming, Smart Clients | Posted on 16-03-2006

4

There are two ways to call web services:  synchronously and asynchronously.  Below is an example of a syncronous web call.  The HelloWorld() call will not get executed until the ReturnLastCustomer() is completed.  In some cases this is fine.  For example if you need the information from ReturnLastCustomer() to then call the HelloWorld() example.

Syncronous Web Service Call

            localhost.Service proxy = new WindowsApplication3.localhost.Service();

            localhost.MyCustomObject myObject = proxy.ReturnCustomObject();

 

            // Make another call to web service

            string hello =  proxy.HelloWorld();

In the example above we wouldn’t really care if one method completed before another.  There may be code below it that can go ahead and get started processing.  To do this we change this to call the service asynchronously.  The idea behind the asynchronous call is we setup an event that gets notified through a delegate that the web service method is done with processing.  Here is how the synchronous example above would look called asynchronously.  It may look like a little more code, but in Visual Studio as you type this just press tab when it gives you a tooltip help and it will generate the right side of the += as well as the method stub for the call back.

Asyncronous Web Service Call

      public Form1()

        {

            InitializeComponent();

 

            localhost.Service proxy = new WindowsApplication3.localhost.Service();

            proxy.ReturnLastCustomerCompleted += new WindowsApplication3.localhost.ReturnLastCustomerCompletedEventHandler(proxy_ReturnLastCustomerCompleted);

            proxy.ReturnLastCustomerAsync();

 

            // Make another call to web service

            proxy.HelloWorldCompleted += new WindowsApplication3.localhost.HelloWorldCompletedEventHandler(proxy_HelloWorldCompleted);

            proxy.HelloWorldAsync();

        }

 

        void proxy_HelloWorldCompleted(object sender, WindowsApplication3.localhost.HelloWorldCompletedEventArgs e)

        {

            string hello = e.Result;

        }

 

        void proxy_ReturnLastCustomerCompleted(object sender, WindowsApplication3.localhost.ReturnLastCustomerCompletedEventArgs e)

        {

            localhost.MyCustomObject myObject = e.Result;

        }

The Problem

The problem with the above example is depending on the speed of how things get processed we will get random errors that an asynchronous call is currently being processed.  The good news is there is an easy way to address this in .Net 2.0.   There are two overrides for the Async calls.  The first one is it takes the parameters of your web service call.  The second override adds another parameter of type “object userState”.  This allows us to pass in a unique identifier of the call. 

To make sure our asynchronous example above works we need to make sure these calls can run at the same time.  It is a simple change and that would look like this:

Calling Two Asynchronous Calls At the Same Time

            localhost.Service proxy = new WindowsApplication3.localhost.Service();

            proxy.ReturnLastCustomerCompleted += new WindowsApplication3.localhost.ReturnLastCustomerCompletedEventHandler(proxy_ReturnLastCustomerCompleted);

            proxy.ReturnLastCustomerAsync(Guid.NewGuid());

 

            // Make another call to web service

            proxy.HelloWorldCompleted += new WindowsApplication3.localhost.HelloWorldCompletedEventHandler(proxy_HelloWorldCompleted);

            proxy.HelloWorldAsync(Guid.NewGuid());

Notice the only difference in how we call the methods is we generate a new Guid as our userState object.  This allows the calls to keep track of the state of each call.  Pretty easy problem to get around but if you don’t explore your overrides of method calls, you may have missed this one.  Being able to call multiple web service methods asynchronously at the same time is pretty important when writing a Smart Client so you’ll probably use this more in this scenario. With larger Smart Clients you typically have things running in the background to check on statuses, update queues, as well as carry calls to save and return data.  This is how you get around that.

Sharing Data with Multiple Windows Forms

Posted by Keith Elder | Posted in .Net, Programming, Smart Clients | Posted on 13-03-2006

1

I see this question a lot on forums, discussion boards and mailing lists.  This question is typically asked in various ways.  Here are a few examples:

  • How do I access a varible in form2 from form1?
  • How do I update a textbox field when a user clicks on a button in form1 to form2?
  • How can form1 be updated with data from form2?
  • How can I share data between two different windows forms?

Whatever the question is the underlying problem is still the same, getting something from A to B or B back to A.  For a developer learning .Net and windows form programming the answer to these questions isn’t so obvious.   Let’s take a look at sharing data such as a strong typed DataSet of Customers between two forms.

To start out with let’s look at the code of a newly created windows form:

namespace KeithElder

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

    }

}

As we see code to a windows form is just an object.  That means if we add a variable in this form that we want to share with another form we would have to make it a public variable.  This is usually what developers try to do at first.  Let’s try this approach first and see where it gets us.

namespace KeithElder

{

    public partial class Form1 : Form

    {

  public CustomerDataSet Customers = new CustomerDataSet();

        public Form1()

        {

            InitializeComponent();

        }

    }

}

Above we added a variable called customers that is public.  This means it can be accessed outside of this form.  If we create another form called Form2 though, how do we easily reference Form1?  In other words we need to get the current running instance of Form1 so we can see the Customers public variable.  Here is one way we could do this:

Form1 myForm = Application.OpenForms[“Form1”] as Form1;

 

This will grab the current open form Form1 and assign it to a variable called myForm.  The first problem with this is we are boxing the Form1 object.  This is costly overhead that we want to avoid.  The other problem is, what if the user closed Form1? Or, what if they never opened Form1?  How do we know?  The answer is we could know, but that would cost us a lot of time developing that logic.  All we REALLY want is the Customers data.  We could care less about the form itself.

 

To solve this problem we can easily create a seperate object that both Form1 and Form2 can access.  This allows us to get data from one location and increase our code reuse factor.  You can call the object whatever you want and even put it wherever you want.  I typically seperate these types of classes out into other class library projects.  The reason is I don’t want any of the objects I reference tied to one single interface.  In the example below I am going to call it “Global.cs”.  Here is how that object would look.

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

 

namespace KeithElder

{

    public static class Global

    {

        private static CustomerDataSet _customers = null;

        public static CustomerDataSet Customers

        {

            get

            {

                if (_customers == null)

                {

                    CustomerDataSetTableAdapters.CustomerTableAdapter ta = new DotNetPimps.CustomerDataSetTableAdapters.CustomerTableAdapter();

                    CustomerDataSet.CustomerDataTable dt =  ta.GetData();

                    _customers = new CustomerDataSet();

                    _customers.Customer.Merge(dt);

                }

                return _customers;

            }

        }

    }

}

 

Notice the class is marked public and static.  This means we do not have to instantiate the class to use the class and we can access it publically in our namespace. There are also two static properties for our customers data.  One is private and one is public.  Having a private static variable allows us to check to see if this variable has ever been accessed and if not, go get the new data.  Otherwise it will return the current data.  You can think of this as sort of a Singleton pattern.

 

The last piece of the puzzle is how do we use this in our Form1 and Form2 scenario.  Let’s look at the code for Form1. There isn’t any need to show Form2 since it will be the same.  That’s the beauty of seperating the data out.

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace KeithElder

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void Form1_Load(object sender, EventArgs e)

        {

            this.customerDataGridView.DataSource = Global.Customers;

            this.customerDataGridView.DataMember = “Customers”;

        }

}

 

On Form_Load we retrieve the customer data and bind that to our DataGridView control.  The same code would apply to Form2.