Thursday, August 20, 2009

WPF binding to a typed dataset

I having been learning WPF and came across a problem trying to use typed datasets and the Visual Studio wizard for generating the xsd file. Once I created the dataset (xsd file) I couldn't find a way to actually bind it to anything or get the data. After some trial and error, the following seems to work well. I am populating an Xceed datagrid but the code is generic. I want to provide a 'blank' row for adding new records as well.


public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{

// Customers table (dataset is 'dsCustomers' as found in the ...Designer.cs file)
m_customer = new dsCustomers.TblCustomers();
//Create data adapter and fill from the source table
(new dsCustomersTableAdapters.TblCustomersTableAdapter()).Fill(m_customer );

m_customer.Rows.Add(m_customer.NewRow()); // Add a blank row

// Likewise for Address table (more verbose)

m_Addresses= new dsCustomers.TblAddresses();
dsCustomersTableAdapters.TblAddressesTableAdapter tblAdap = new dsCustomersTableAdapters.TblAddressesTableAdapter();

tblAdap.Fill(m_Addresses);
DataRow dr = m_Addresses.NewRow(); // generate a new row
m_Addresses.Rows.Add(dr); // append back to the table

base.OnStartup(e);
}

private dsCustomers.TblCustomers m_customer ;

public dsCustomers.TblCustomers Customers
{
get
{
return m_customer ;
}
}
private dsCustomers.TblAddresses m_Addresses;

public dsCustomers.TblAddresses Addresses
{
get
{
return m_Addresses;
}
}
}





Meanwhile the xaml is ..

< Grid.Resources>

< xcdg:DataGridCollectionViewSource
x:Key="Tblmycustomers"
Source="{Binding Source={x:Static Application.Current},
Path= Customers}"/ >

< xcdg:DataGridCollectionViewSource
x:Key="TblLocations"
AutoCreateForeignKeyDescriptions="true"
Source="{Binding Source={x:Static Application.Current},
Path= Addresses}"/ >
< /Grid.Resources >

Saturday, January 17, 2009

Cookies and the problems they cause

I often use the Ext state manager to automatically manage cookies for Ext widgets. This allows the application to 'remember' user settings such as window size, location etc. The only code required is :

Ext.state.Manager.setProvider(new Ext.state.CookieProvider());


This is very powerful and simple to add to an application BUT it can cause a mountain of problems. I've been bitten twice. What sometimes happens is the cookies can end up being applied to the incorrect objects. It seems that when Ext creates DOM objects, if there is no explicit dom id, an id is created. This id is used by the cookie 'manager' to reference the objects that are monitored. This is fine, except when items are added or removed from the application. The auto generated id numbers are changed and the cookies are now referencing different objects. This problem occurs during the development process or when new application versions are released (widgets are added and removed).

How do we avoid this? Its quite simple. Just assign explicit id properties to ALL items you create. Just do this as a 'best practice'. By doing this, there are no auto generated ids and no danger of the manager referencing the wrong objects.

Using Ext.extend to extend user classes.

While learning javascript, I've fallen into the copy/paste trap of code creation. Rather than using OO constructs, I often copy a block of code, paste it and modify it slightly. This is bad bad bad so I thought I would figure out how to use Ext.Extend to take my own base class and use inheritance to extend the base functionality. There is no rocket science here but I can use this now as a template for inheriting. Code ...

// ----------- Base class (extending 'object' )  ------------------
genericBase = Ext.extend(Object, {
basevar1: 1,
constructor: function(args) {
this.basevar1 = 2;
},

baseFunc1: function(testArg) {
alert("test Arg is " + testArg + " basevar = " + this.basevar1);
}
});

// ----------- Derived class (extending 'genericBase'class ) -------
genericDerived = Ext.extend(genericBase, {
derVar: 444, // class property
constructor: function(args) {
// Call the base constructor
genericDerived.superclass.constructor.call(this, args);
},

derivedFunc1: function(testArg) {
alert("derivedFunc1 called " + testArg );
},
getBaseval: function() {
return this.basevar1;
}

});


// -------- Code to instantiate and test the classes

// First, create the object
var myobj = new genericDerived({prop1: '123', prop2: 'abc' });

// displays basevar with a get method
alert("Derived class, method call ==>" + myobj.getBaseval());

// also displays basevar, but with direct property reference
alert("explicit reference to property basevar1 ==> " + myobj.basevar1);

myobj.baseFunc1('Calling base method');
myobj.derivedFunc1('Calling derived class method');


Tuesday, December 2, 2008

How to modify Ext tooltips dynamically

I have a requirement to dynamically change tool-tips as content gets refreshed and modified. There were a couple of suggestions in the forums, but the following works great for me:
var mydom = Ext.get('mydomelement');       // get element
var tip = Ext.getCmp(mydom.dom.id + '_tip'); //get element's tooltip

if ( tip ) {// tool tip already exists, so modify

tip.title = 'new title';
tip.html = 'new text';
}

else { // tip does not exist. Create it with unique id.

new Ext.ToolTip({
target: mydom.dom.id,
id: mydom.dom.id + '_tip',
title: 'title here', html: 'original text'
});
}
I am giving every tooltip a unique id, based on the id of the dom element it decorates.

Wednesday, November 26, 2008

Creating Charts and Graphs

Microsoft has released a chart control with .net framework 3.5. I believe it is licensed from Dundas and certainly has the Dundas look and feel. The functionality looks good but in my travels there are two graphing systems I have used, one for the client side and one for the server side.

On the server side I usually pre-generate graphs so that if there is lots of user traffic, database access is minimized. The client does not get one of those pesky 'loading data' messages. The server side graphic files are recreated on a periodic basis, with the web page referencing the image file (PNG, GIF etc). The package I have used is ZedGraph. It is open source however there doesn't seem to have been any project activity in over a year. It is easy to use and I had the samples up and running in about 5 minutes.

On the client side interactivity rules. There are a few open source packages around ( flot, plotkit ) but they are fairly basic. I paid the few dollars for Emprise Charts and have been very happy. The interactive features are great, especially the zoom and mouse-over features. I believe there is a free version that gives limited use and a watermark on graph backgrounds. I highly recommend Emprise Charts. I've combined Ext, .Net web services and Emprise in a complete solution that is quite slick. I basically loop through an Ext datastore and load up the graph points.

Deciding on whether to render on server or on client really depends on what your users will be looking at. If your db queries are expensive in terms of time to get the data, server side is best however if you can do it, client side rendering with Ajax will give your users a better interactive experience.

Wednesday, September 17, 2008

Using Intellisense with Visual Web Dev Express

I use Visual Web Developer Express - 2008 for all my development now, although most of my projects are still .NET 2.0.

Recently I discovered how to use javascript intellisense which helps a ton. You need to have SP1 of Visual Web Developer :
http://www.microsoft.com/downloads/details.aspx?FamilyId=7B0B0339-613A-46E6-AB4D-080D4D4A8C4E&displaylang=en

Once you have SP1, just add the following to the top of each JS file:

/// < reference path="lib/ext/adapter/ext/ext-base.js">
/// < reference path="lib/ext/ext-all-debug.js">
/// < reference path="myotherfile.js">


Not only do I get Ext intellisense, but also for objects from my own javascript files. Works great!

Tuesday, April 15, 2008

Minimizing server requests : multiple tables per request

The following example shows how to return multiple tables in one ajax request. Of course, minimizing server traffic allows for a snappy client experience. My requirement was to retrieve two data tables in a single server call. The Web service makes two distinct SQL calls, merges the datasets on the server and returns an XML document.

The client establishes a single data connection and then reads the results into two separate data stores using MemoryProxy data stores. The net effect is exactly the same result as making two (expensive) server requests.


Server Side

 [WebMethod]
public XmlDocument getPlannerDetail(String plannerid)
{
// SQL Query #1
String str = " select * from TblPlanners where plannerid = '" + plannerid + "'";
Filldt("plannerDetail", (int)Servers.nweb1, str);

DataSet localds = new DataSet();
localds.Merge(dt);

// SQL Query #2
str = "select plannerid_Owner, plannerid_Changer from TblPlanners_permission where plannerid_Owner = '" + plannerid + "'";
Filldt("Permits", (int)Servers.nweb1, str);

localds.Merge(dt);

XmlDocument doc = new XmlDocument();
xmlDoc.LoadXml(localds.GetXml());
return xmlDoc;

}

Client Side

var getdata = new Ext.data.Connection();

getdata.request({
url: "Service.asmx/getPlannerDetail",
params: {
plannerid: '123'
},
method: 'POST',
scope: this,

callback: function(options, success, response){

if (success) {
var xml = response.responseXML;

dsDetails = new Ext.data.Store({
proxy: new Ext.data.MemoryProxy(xml),
reader: new Ext.data.XmlReader({
record: 'plannerDetail',id: 'plannerid'
}, ['plannerid', 'centerid', 'LongName', 'DefaultViewRange'])
});

dsPermits = new Ext.data.Store({
proxy: new Ext.data.MemoryProxy(xml),
reader: new Ext.data.XmlReader({
record: 'Permits',
id: 'plannerid_Owner'
}, ['plannerid_Owner', 'plannerid_Changer'])
});

dsDetails.load();
dsPermits.load();
}
}
});