Welcome to MSDN Blogs Sign in | Join | Help

Data Binding - What are NullValue and DataSourceNullValue properties?

Are you confused about what is NullValue and DataSourceNullValue properties on the Binding class? Are you confused about how Binding behaves when formatting or parsing when either of these is set? If you answered YES to any of these above then read on for a simple explanation of what these properties are and how they can be used!

 

The Binding class exposes 2 properties: NullValue and DataSourceNullValue. Let’s look at each of these:

 

1)      NullValue simply specifies what a control should display when it needs to display a null value. E.g. Say you have Textbox control that is bound to a column of a DataTable. Consider that some values in the DataTable are DBNull.Value. In this case, if you would like DBNull.Value to be displayed by the TextBox as say, “(null)” then you would achieve this by setting NullValue property of the binding to “(null)”.

 

Note: TextBox will display the NullValue if following conditions are met:

a)      Value in the DataTable is either DBNull.Value, null or DataSourceNullValue (read more about this below) AND

b)      Formatting is enabled.

 

Here is a code snippet:

 

            DataTable dt = new DataTable();

            dt.Columns.Add("Name");

            dt.Rows.Add("foo");

            dt.Rows.Add("dsnv");

            dt.Rows.Add("nv");

            dt.Rows.Add(new object[] { null });

            dt.Rows.Add(DBNull.Value);

 

            Binding b = new Binding("Text", dt, "Name", true);

            b.NullValue = "nv";

            this.textBox1.DataBindings.Add(b);

 

TextBox now displays “nv” for all rows in the DataTable except the first two rows.

 

 

2)      DataSourceNullValue specifies what value of the data source is considered a null value and also specifies what value should be written back to the data source for a null value.

e.g. Say just like above you have the DataTable. Say you want to consider string “dsnv” as a null value. To do so you would set DataSourceNullValue property on the Binding to “dsnv”. If you set this property to “dsnv”, then "dsnv" is considered as a null value and the TextBox displays this value as value specified by the NullValue property.

 

Here is a code snippet:

 

            Binding b = new Binding("Text", dt, "Name", true);

            b.NullValue = "nv";

b.DataSourceNullValue = "dsnv";

            this.textBox1.DataBindings.Add(b);

 

In this case, note that all rows except only the first one are shown as “nv”.

 

Also, if you set the Text of the Textbox to any of the “logical nulls” (i.e. to null or NullValue) then it would get stored back in the data source as DataSourceNullValue. Say for example, if the TextBox is showing the first row i.e. showing the text “foo”. Now if you type in NullValue i.e. string “nv” then it would be stored back in the data table as string “dsnv” i.e. as DataSourceNullValue.

 

 

These 2 properties are very powerful and make formatting and parsing null values extremely simple.

 

As always, let me know if you have any questions. Happy Binding!

Posted by dchandnani | 3 Comments

PropertyManager - cool trick

It always amazes me to see the cool tricks one can do using Data binding. Be it simply binding a property of a control or complex binding master/child views with data entry, etc. So, here's a small cool trick about property binding.

In Winforms, you can bind any property of any control to another property of a control - just a 1 line code. e.g. Say, you have a Textbox on the form where a user can enter some text. Below the Textbox say you have a Label that shows a count of the number of characters the user has typed already. One way to do this would be to hook on to the TextChanged event of the textBox and calculate the length of the Text in the Textbox and then update the Label text. Another "cooler" way to do this would be through binding. This line does the trick:

         label.DataBindings.Add("Text", textBox, "Text.Length");

This line binds the Text property of the label to the Length of the Text property of the textBox! Typing in text in the textBox will update the text of the Label. It's that simple!

How does this work? For this kind of simple property binding, there is a PropertManager that manages this binding. The PropertyManager hooks on to the *Changed event internally and is notified of any changes.

Happy Binding!

Posted by dchandnani | 0 Comments

BindingSource - A Closer Look...

In my previous posts I have spoken about how databinding works in Whidbey and some simple scenarios of binding in Whidbey using BindingSource and BindingList<T>. Now, let’s take a closer look at the BindingSource.

 

BindingSource can be bound to any of the following:

-          Object

-          System.Type

-          IEnumerable

-          ICollection

-          IList

-          IListSource

-          IBindingList

-          IBindingListView

 

Please note that the ListChanged event on the BindingSource is the main event and will be referenced below. Binding to each of these objects mentioned above has a subtle difference. Let’s go through each of these:

 

Binding to an Object:

You can arbitrarily set the DataSource of BindingSource to any System.Object. When this is done, BindingSource internally creates a BindingList<T> of that Object type and adds the item to this list. You can then add objects to this list by calling BindingSource.Add(…).

 

e.g. Say you have a Customer object. You can do the following:

 

            BindingSource bs = new BindingSource();

            bs.DataSource = new Customer();

 

This will create a BindingList<Customer> internally with one object.

 

Binding to a System.Type:

BindingSource can be bound to a System.Type. When you do this, the BindingSource creates an empty BinidngList<T> of that Type. When you add new items to the BindingSource, it makes sure it is of the correct Type, and if so the item is added, else it will throw. The cool thing is that you can very easily bind any business object this way.

 

e.g. Say you want to bind to a list of Controls (TextBox, CheckBox, Button, etc). If you set the DataSource of the BindingSource to an instance of a control then it will not work correctly. Consider you do this:

 

            BindingSource bs = new BindingSource();

            bs.DataSource = new TextBox();  // BindingSource will create a BinidngList<TextBox> internally

            bs.Add(new Button()); // This will throw since the type is not TextBox

 

The correct way to do this would be to set the DataSource to type of control and then add items:

 

            BindingSource bs = new BindingSource();

            bs.DataSource = typeof(Control);            // BindingSource creates a BindingList<Control> internally

            bs.Add(new TextBox());

            bs.Add(new Button());

 

This will add the TextBox and Button to the list correctly.

 

Binding to IEnumerable and ICollection:

When DataSource of BidningSource is set to IEnumerable or ICollection the BindingSource creates a BindingList internally. What this means is that the BindingSource creates a copy of the list and uses it; so it is not aware of any changes you make to the original list.

 

Consider this:

 

            BindingSource bs = new BindingSource();

            bs.DataSource = MyCollection; // BindingSource create BindingList internally

            MyCollection.Add(newObject);

 

BindingSource does not fire ListChanged events in this case since it is unaware of any changes to the underlying list. Also, any changes to the items in the list itself (e.g. if this is a collection of Customers, and if you change say the Name property of a Customer object in the collection), BindingSource will be unaware of these changes since it only references it’s copy. The way to make the BindingSource “aware” of these changes is to set the DataSource of BindingSource again.

So, doing:

            bs.DataSource = MyCollection;

 

Will refresh the BindingList that the BindingSource uses internally.

 

Binding to IList and IListSource

When DataSource of BindingSource is set to IList or IListSource, BindingSource does not create its internal copy. It will always reference the underlying list for Data. However since IList and IListSource does not have ListChanged events, BindingSource will not be aware when items are added or removed from the list.

 

Typical case is Binding the BindingSource to ArrayList or List<T> (IList) and DataTable (IListSource). One thing to note though, is that DataTable’s IList.GetList() method returns a DataView which is an IBindingListView and not a pure IList. That’s why DataTable would behave differently from an IListSource that returns a pure IList instead. More information on IBindingListView below.

 

e.g.

            List<Customer> list = new List<Customer>();

            // Fill the list

 

            BindingSource bs = new BindingSource();

            bs.DataSource = list;

           

            DataGridView dgv = new DataGridView();

            dgv.DataSource = bs;

 

This will bind DGV to BindingSource which is bound to List<T>.

 

            list.Add(new Customer()); // Add a new Customer to the list

 

BindingSource is not aware of this change and so does not fire ListChanged event. Thus, DGV does not show a new row. If you refresh the DGV then it will get the data from the BindingSource which will get it from the underlying list and then the new row will appear.

 

To show the changes of items added and removed to the list, you can use BindingList<T> instead. Details below.

 

Binding to IBindingList and IBindingListView

When DataSource of BindingSource is set to IBindingList or IBindingListView, the BindingSource does not create internal copy of the list (just as it does in the case of IList and IListSource). It always references the underlying list for the Data. Also, since IBindingList and IBindingListView have the ListChanged event, the BindingSource hooks on to those events and so it is aware of any items added or removed from the list.

 

Consider this:

 

e.g.

 

            BindingList<Customer> bList = new BindingList<Customer>();

            // Fill the list

 

            BindingSource bs = new BindingSource();

            bs.DataSource = bList;

           

            DataGridView dgv = new DataGridView();

            dgv.DataSource = bs;

 

This will bind DGV to BindingSource which is bound to List<T>.

 

            bList.Add(new Customer()); // Add a new Customer to the list

 

BindingList<T> fires ListChanged event when a new item is added to the list. Since BindingSource hooks on to the ListChanged event of BindingList<T> it also is “aware” of these changes and so the BindingSource fires the ListChanged event. This will cause the new row to appear instantly in the DataGridView or make any controls listening to the BindingSource “aware” about this change.

 

Next I will talk about making changes to properties of an item in the list (e.g. changing the Name property of a Customer), rather than changing the list by adding and removing items, and we can take a closer look at how the BindingSource deals with these changes.

Posted by dchandnani | 15 Comments

BindingSource and BindingList Of T - DataBinding made simple!

In Whidbey we have new classes: BindingSource and BindingList<T> which should make DataBinding really easy even when binding to business objects. Main advantages are:

-          BindingSource hooks on to property changes of the current item and fires ListChanged events when the underlying event changes

-          BindingList<T> is the new generic implementation of IBindingList which fires ListChanged event when items are added/removed/inserted/etc. from the list. bindingSource hooks on to these events and is thus “aware” of these changes and can notify controls bound thos this BindingSource.

 

Let’s take some common case scenarios and see hpow BindingSource and BindingList<T> can be used for these:

 

1) DataGridView bound to DataTable

 

            DataGridView dgv = new DataGridView();

            BindingSource bs = new BindingSource();

            DataTable dt = GetDataTableFromSomeWhere(); // Gets the DataTable

 

            bs.DataSource = dt;

            dgv.DataSource = bs;

 

That’s it. You are done! DataGridView is now bound to the DataTable.

 

Ofcourse you can bind the DataGridView to the DataTable directly and bypass the BindingSource, but BindingSource has certain advantages:

-          It exposes properties to Sort the list, Filter the list, etc. which would other wise be a pain to do. (i.e. if you bind the DataGridView to the DataTable directly then to Sort the DataTable you need to know that DataTable is an IListSource which knows the underlying list which is a DataView and a DataView can be sorted, filtered, etc.).

-          If you have to set up master/child views then BindingSource does a great job of doing this (more details in my previous post)

-          Changes to the DataTable is hidden (also in my previous post)

 

2) DataGridView bound to business objects

 

Say you want to bind the DataGridView to a list of Customers. Customer is a class you have created and has properties like ID, Name, etc. To do this you can simple do:

 

            DataGridView dgv = new DataGridView();

            BindingSource bs = new BindingSource();

            BindingList<Customer> bList = new BindingList<Customer>();

           

            // Fill bList with Customers

 

            bs.DataSource = bList;

            dgv.DataSource = bs;

 

That’s it. You are done! DataGridView will show all the Customers in the BindingList and display columns for each of the properties on Customer i.e. it will have columns for ID, Name, etc. Also, advantages of BindingList<T> are that as you add, remove, insert Customers into this BindingList the DataGridView will show up the changes and correspondingly add, remove and insert rows!

 

3) TextBox bound to business objects

 

Say you want to bind a TextBox (or any other control) to a list of Customers and show up the Name of the Customer in the TextBox. You can simply do:

 

            TextBox tb = new TextBox();

            BindingSource bs = new BindingSource();

            BindingList<Customer> bList = new BindingList<Customer>();

           

            // Fill bList with Customers

 

            bs.DataSource = bList;

            tb.DataBindings.Add(“Text”, bList, “Name”);

 

That’s it. This will bind the TextBox to the Name property of the Customer in the list. Initially it will show the Name of the first customer in the list. As you change the Position property of the BindingSource, it will show the Name of the “current” Customer (current item is whatever the Position points to).

 

You can do a similar thing by using DataTable instead and bind to one of the Columns in the DataTable.

 

4) ComboBox bound to business objects

 

Say you want to bind a ComboBox (or one of the list controls like ListView, etc) to a list of Customers and show up a list of Names of the Customers in the list. You can simply do:

 

            ComboBox cb = new ComboBox();

            BindingSource bs = new BindingSource();

            BindingList<Customer> bList = new BindingList<Customer>();

           

            // Fill bList with Customers

 

            bs.DataSource = bList;

            cb.DataSource = bList;

            cb.DisplayMember = “Name”;

 

That’s it. This will bind the ComboBox and it’s items will be the Name of all the Customers in the BindingList.

 

You can do a similar thing by using DataTable instead and bind to one of the Columns in the DataTable.

 

In all these 4 cases you get all the advantages of BindingSource and BindingList<T> mentioned above. Simple isn’t it? Happy Binding! J

 

Posted by dchandnani | 9 Comments

DataBinding – DataGridView/BindingSource

Many folks I know find DataBinding a complex thing and try to stay away from it. Here is a quick overview of DataBinding and how it relates to DataGridView (a BIG feature in Whidbey!) and BindingSource (will make life simple!).

 

Before Whidbey a typical data bound app would have an Adapter (that would talk to the back end), a DataSet (which would be filled up by the Adapter) and some controls (like DataGrid, TextBox, ComboBox, etc.) which would talk to a DataSet. This would work most of the time but there were certain problems:

1.       Folks would bind say, a DataGrid to a DataTable. Then somewhere the DataTable would be updated i.e. say you contacted some WebService or whatever else you want, to get the new DataTable. Expectation was that databinding should still work. Well, this would not work since the DataTable has now been changed. A snippet of this is:

 

DataGrid dg = new DataGrid();

DataTable dt = MyWebService.GetDataTable();

dg.DataSource = dt; // works fine

 

dt = MyWebService.GetDataTable(); // breaks since this is a new datatable

 

2.       Other problem was with setting up Master/Child views. Say we have a DataSet that has two tables: CustomerTable called “Customers” and OrderTable called “Orders” and a relation called “CustOrders”. Typically to set up Master/Child DataGrids,

 

The correct ways to do this would be (DataSource for both grids should be same):

 

Correct Way 1:

           

dgMaster.DataSource = ds;

dgMaster.DataMember = “Customers”;

 

dgChild.DataSource = ds;

dgChild.DataMember = “Customers.CustOrders”;

 

Correct Way 2:

           

dgMaster.DataSource = CustomerTable;

 

dgChild.DataSource = CustomerTable;

dgChild.DataMember = “CustOrders”;

 

 

Other ways to do this would be incorrect, such as (DataSource for grids are different which would result in Master/Details not working correctly):

 

Incorrect Way 1:

           

dgMaster.DataSource = ds;

dgMaster.DataMember = “Customers”;

 

dgChild.DataSource = CustomerTable;

dgChild.DataMember = “CustOrders”;

 

Incorrect Way 2:

           

dgMaster.DataSource = CustomerTable;

 

dgChild.DataSource = ds;

dgChild.DataMember = “Customers.CustOrders”;

 

To mitigate these and other issues, we have introduced the new component BindingSource. BindingSource has DataSource and DataMember properties that you can set and then bind to the BindingSource. You can also change the DataSource of BindingSource and the binding will work fine.

 

e.g. Say you are using the new DataGridView control of Whidbey and want to show the Customers table (using BindingSource in this case is an overkill, but it demonstrates how to use the BindingSource):

 

            DataGridView dgv = new DataGridView();

            BindingSource bs = new BindingSource();

            bs.DataSource = CustomerTable;

            dgv.DataSource = bs;

 

To set up Master/Child views, you can do the following:

 

            bsMaster.DataSource = ds;

            bsMaster.DataMember = “Customers”;

 

            bsChild.DataSource = bsMaster;             // Note: DataSource is the master BindingSource

            bsChild.DataMember = “CustOrders”;      // Note: DataMember is the relation

 

            dgvMaster = bsMaster;

            dgvChild = bsChild;

 

This hooks up the master/child views correctly. J

 

Please let me know if you have any comments or questions.

Posted by dchandnani | 3 Comments

Creating controls/components from Toolbox and Initializing

I got this question today and wanted to write on it:

How does creation of controls from toolbox work? A related question is - how do we initialize the control’s properties when it gets created? A more advanced scenario is – how can we create multiple controls/components when double-clicking just a single item in the toolbox (e.g. in a Windows Forms Application double-clicking say the a DataGridView in the ‘Data Sources’ window also creates the DataSet, DataConnector and DataAdapter components along with DataGridView control on the Form. How does that work? The magic lies in interfaces IToolboxUser and ToolboxItem. IToolboxUser is an interface that is implemented by any designer that supports adding controls from the toolbox. DocumentDesigner and ComponentDocumentDesigner implement the IToolboxUser interface. When we double-click an item (control/component) in the toolbox IToolboxUser.ToolPicked() method gets called. If we drag-drop the item then the drag drop handler gets called. In either case when the control/component is about to be created, the flow of execution is as follows:

·          ToolboxItem.CreateComponents()  Note: in most cases the toolbox item creates just one component. E.g. double-clicking button in the toolbox only creates a single control Button, but in the advanced scenario mentioned above we can potentially create multiple components and parent them to the DesignerHost’s RootComponent. So, if you create a custom ToolboxItem and associate it with a control (through a ToolboxItem attribute) then you could create multiple components

·          Toolbox item then gets the designer for each of the components it created and checks if they implement IComponentInitialize. If they do then IComponentInitialize.InitializeNewComponent is called. Note: This method can be overridden to initialize the properties on the component being created

 

As an example consider this code below that creates control on the RootComponent (in this case a Form) by using the IToolboxUser interface of the designer of the RootComponent (FormDocumentDesigner).

 

DesignSurface ds = new DesignSurface();

ds.BeginLoad(typeof(Form)); // loads the Form

IDesignerHost idh = ds.GetService(typeof(IDesignerHost)) as IDesignerHost;

IToolboxUser tbu = idh.GetDesigner (idh.RootComponent as IComponent) as IToolboxUser;

tbu.ToolPicked(new ToolboxItem(typeof(Button));

 

// Show the Form

Control view = ds.View as Control;

Form f = new Form();

f.Controls.Add(view);

view.Dock = DockStyle.Fill;

f.Show();

 

We could instead use a custom toolbox item that would create multiple controls. Below is a snippet of this custom toolbox item that overrides CreateComponentsCore to create 2 controls: TextBox control and MyControl.

 

protected override IComponent[] CreateComponentsCore(System.ComponentModel.Design.IDesignerHost host)

{

TextBox textbox = (TextBox)host.CreateComponent(typeof(TextBox));

            textbox.Parent = host.RootComponent as Control;

            MyControl myControl = (MyControl)host.CreateComponent(typeof(MyControl));

            return new IComponent[] { textbox, myControl };

}

 

Please let me know if you need more information of have specific comments.

 

Posted by dchandnani | 5 Comments

Web Hosting Plans

In a world where pop-ups and banner ads is the rule finding a web host that is free of charge and has no pop-ups or banner ads is not only tough but close to impossible. In my quest to re-juvenate my website I spent a lot of time searching for the optimal one (Used to have a website for quite some time but had stopped updating it). I stumbled across afmu - provides free web hosting provided one buys the domain name from them. So I did just that and am pretty happy with the web hosting so far. Service is pretty cheap as compared other options and they have surprisingly a lot of options - guestbook, slew of scripts, content management, discussion boards, Wiki site builders, etc. A pretty impressive feature set for a company run by a bunch of students! 
Posted by dchandnani | 1 Comments

Designer Hosting

There have been a lot of improvements for designer hosting in Whidbey. The task of creating a host form that hosts other designers in Everett is a huge task requiring probably 100s of lines of code. In Whidbey it is down to <10 lines. More on this further down.
But first - What exactly is designer hosting? Simply put it is hosting designers. To understand how hosting works it is important to understand what a designer is in .Net Framework. Simply stated, a designer in the .NET Framework is an object that only exists at design time, and connects to an object that normally exists at runtime. Consider a Button on a Form. At runtime these two objects are associated with each other only by a parent-child relationshipt. At design time the picture is a little more complex. At design time each of them has a designer. So we now have Form, Form designer, Button and Button designer. They are also connected to a host container. The host container has a lot of responsibilities. It provides various services needed by these objects eg. Selection Service to select these objects, Component change Service, etc. It is also responsible for loading designers from some sort of persistent state, and saving them back to that state.

On a high level, we have 3 parts to host designers: Host container, Designer Loader and Serializers.

Host container is the object that implements IDesignerHost - the most important interface for designer hosting. IDesignerHost provides some organization to the random array of designers that components provide. It also holds a reference to DesignerLoader. DesignerLoader is the piece that is responsible for loading the designers and saving the state back. To do this it uses Serializers.

In Whidbey we have a class called DesignSurface that encapsulates all this. To demonstrate how simple it should be for a third party to host a designer, the following sample code will create a Windows Forms designer and display it:

DesignSurface ds = new DesignSurface();

ds.BeginLoad(typeof(Form)); // loads the Form

IDesignerHost idh = ds.GetService(typeof(IDesignerHost)) as IDesignerHost;

Control view = ds.View as Control; // Gets the View of the DesignSurface

Form f = new Form();

f.Controls.Add(view);

view.Dock = DockStyle.Fill;

f.Show(); // Show the View on a Form

Posted by dchandnani | 6 Comments

Hello World!

Have been reading blogs for some time now and finally decided to have one myself! Blogs is taking the world by storm (:-)) and I thought I should be a part of it too! I am an SDET with .Net Client team and have been in Microsoft for over 2 years now. Here you will find posts, articles related mostly to Windows Forms and some other cool stuff. Thank you for reading this space and feel free to add comments. See you back soon!

Regards,
-Dinesh

 

Posted by dchandnani | 1 Comments
 
Page view tracker