Click here to Skip to main content
15,867,985 members
Articles / Programming Languages / C#
Article

Enhanced DataSet Quick Watch

Rate me:
Please Sign up or sign in to vote.
4.73/5 (14 votes)
20 Feb 2005CPOL3 min read 134.9K   2.6K   74   23
A VS.NET add-in to visualise standard and typed DataSets, DataTables and DataRows whilst debugging.

Sample Image - DSWatchEx1.png

Introduction

This add-in is essentially an update to Mohammed Barqawi's excellent DataSet Quick Watch add-in. Please reference the article for the original concept and code.

The add-in's implementation was great but notably didn't support typed datasets. I've added a few things to take the original ideas a little further and hopefully make life even easier to visualise a dataset whilst debugging.

What's New?

Typed DataSet support

This allows all Typed DataSets (directly inherited from System.Data.DataSet) to be used with the add-in. This also works with typed DataTables and DataRows.

Support for DataTables and DataRows

This allows you to select a table or row (in code) and load the dataset (selecting that table or row in the output).

Row Filter Support

A free text row filter and 'DataViewRowState' filter has also been added to help with debugging. This functions on a per table basis.

Visual Enhancements

The DataSet Watch form has been amended to use a custom 'EnhancedGrid' control to provide filtering and a slightly more 'colourful' output. If you're not keen on the look of the grid then you can easily change it by changing the EnhancedGrid UserControl.

I didn't quite get round to adding the support for user preferences!

Using the code

Debugger Expressions

The original concept still stands, but I've made a few amendments to the way we get and check debugger expressions. I refactored the construction of each expression to work based on the input language:

C#
private string GetEvaluationExpression(string type, object selectedObject,
                string propOrMethod, string SourceType)
{
    switch (SourceType)
    {
        case LangCSharp:
        {
            return "(" + type + ")" + selectedObject + propOrMethod;
        }
        case LangVB:
        {
            if (type == "int")
                type = "System.Int32";
                //HACK to cope with language differences
            return "ctype(" + selectedObject + ", "
                            + type + ")" + propOrMethod;
        }
        default :
        {
            throw new ApplicationException("Invalid Source Type : "
                                        + "Expected 'cs' or 'vb'");
        }
    }
}

Where str (the selected text in the debugger) == "myDataTable", the line below will assign a language-specific debugger expression string to getTableNameFromTableExpression:

C#
getTableNameFromTableExpression = 
   GetEvaluationExpression(TypeDataTable, str, ".TableName", fileExtension);
  • C# - System.Data.DataTable)myDataTable.TableName
  • VB - ctype(System.Data.DataTable, myDataTable).TableName

This particular expression is used to get the tablename from a selected DataTable.

Typed DataSets

The support for typed datasets comes in when we evaluate an expression that returns an unexpected type. This will happen because the debugger returns the 'actual' type of the expression you've selected - e.g., MyNamespace.MyTypedDataSet.MyTableRow.

If you selected something other than a DataSet, DataTable or DataRow (or anything that derives directly from any of these), the ExpressionHasError method would find the text "error:" in the expression's value.

In the case we return a typed data object (and we return the type name), we then find the base type and evaluate the expression again... If it's a typed dataset, table or row, then we should find the correct (System.Data...) type second time around.

C#
// Calling code.....  Filtering down -
// checking for DataSet, then DataTable, then DataRow

//Check which worked!
if (ExpressionHasError(exprDataSet, "{System.Data.DataSet}", str))
{
    //Check for DataTable
    if (ExpressionHasError(exprDataTable, "{System.Data.DataTable}", str))
    {
        //Check for DataRow
        if (ExpressionHasError(exprDataRow, "{System.Data.DataRow}", str))
        {
            MessageBox.Show("This is not a DataSet, DataTable or DataRow!",
        "DSWatch",MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return;
        }


//.....

private bool ExpressionHasError(Expression expr,
             string type, string originalContext)
{
    EnvDTE.Debugger debugger = applicationObject.Debugger;

    if (type != null)
        if (expr.Value.IndexOf("error:")>-1)
            return true;
        else
        {
            if (expr.Value != type)
            {
                //Check for base type (only going one level down
                //   - so assume here that every 'typed' dataset
                //is a direct descendent of System.Data.DataSet

                //need to remove any quotes if we're in a recursive call
                Expression baseExpression =
                  debugger.GetExpression(originalContext +
                  ".GetType().BaseType.Name" , true, 500);
                string val = baseExpression.Value.Replace("\"", String.Empty);
                string subType = type.Substring(type.LastIndexOf(".")
                                      +1).Replace("}", String.Empty);
                return (val != subType);
            }
            else
                //All is OK
                return false;
        }
    else
        return expr.Value.IndexOf("error:")>-1;
}

Selecting specific rows

If we've selected a row in the debugger by a variable: myRow or with an indexer: myDataSet.Tables[0].Rows[0], we know we can find the ordinal position of the row (in the table) via the rowID property. We can then use this information in the output form to select the appropriate row (and table).

Row Filtering

Row Filtering

This works with a combination of standard DataView filtering - using a free text row filter, and a DataViewRowState filter (useful to show all rows in a particular state). The following applies a combination of both filters.

C#
private void ApplyFilter(bool showAll)
{
    try
    {
        if (_dataSource == null)
            return;

        //Filter the contents of the grid
        if (showAll || (this.rowStateFilter.SelectedIndex == 0 &&
                        this.rowFilterExpression.Text == String.Empty))
            _view = _dataSource.DefaultView;
        else
        {
            _view = new DataView(_dataSource);
            if (this.rowStateFilter.SelectedIndex != 0)
                _view.RowStateFilter =
                  (DataViewRowState)Enum.Parse(typeof(DataViewRowState),
        this.rowStateFilter.SelectedItem.ToString(), true);

            _view.RowFilter = this.rowFilterExpression.Text;
        }
        this.grid.DataSource = _view;
        if (this.FilterChanged != null)
            this.FilterChanged(this.grid,
                 new FilterChangedEventArgs(_dataSource,
                 _view.Count, _dataSource.Rows.Count - _view.Count));

        this.grid.Refresh();
    }
    catch (Exception ex)
    {
        MessageBox.Show(String.Format("There was a problem" +
           " applying the row filter\n\n{0}", ex.Message),
           "Row Filter", MessageBoxButtons.OK,
           MessageBoxIcon.Exclamation);
    }

}

The EnhancedGrid UserControl defines a FilterChanged event, passing context information to allow the parent form to alter the text in its Status Bar.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Codebureau
Australia Australia
Started with COBOL/CICS/DB2 - ended up with C#/ASP.NET. I'm a half-geek (or so my wife tells me!)

Comments and Discussions

 
QuestionError : This is not a dataset or datatable or datarow Pin
Dilip Baboo12-Mar-09 8:32
Dilip Baboo12-Mar-09 8:32 
GeneralVisual Studio 2005 Framework 2.0 Pin
icedragon4-May-07 3:52
icedragon4-May-07 3:52 
Generalsomething for VS 2005 Pin
fadee2-Jan-07 20:21
fadee2-Jan-07 20:21 
GeneralGOOD WORK Pin
EIHABWADY6-May-06 4:16
EIHABWADY6-May-06 4:16 
Generalfix to DataTable not in DataSet Pin
sharaabi14-Dec-05 23:11
sharaabi14-Dec-05 23:11 
GeneralRe: fix to DataTable not in DataSet Pin
AaronVisser15-Dec-05 13:59
AaronVisser15-Dec-05 13:59 
GeneralRe: fix to DataTable not in DataSet Pin
roberto galbiati26-Feb-06 22:49
professionalroberto galbiati26-Feb-06 22:49 
GeneralERROR: Not a dataset, datatable or datarow Pin
Ihor Bobak1-Dec-05 8:46
Ihor Bobak1-Dec-05 8:46 
GeneralDoesn't work on Typed DataSet.. Pin
Member 17327423-Aug-05 4:11
Member 17327423-Aug-05 4:11 
GeneralRowStateFilter does not work Pin
pinx9-Jun-05 2:35
pinx9-Jun-05 2:35 
GeneralMethod not found : void System.Windows.Forms.set_location(...) Pin
nghadiri8-Jun-05 18:31
nghadiri8-Jun-05 18:31 
GeneralInvalid Data at root level Pin
CKurmann29-Mar-05 20:17
CKurmann29-Mar-05 20:17 
GeneralRe: Invalid Data at root level Pin
CodeBureau - Matt Simner6-Apr-05 3:32
CodeBureau - Matt Simner6-Apr-05 3:32 
GeneralRe: Invalid Data at root level Pin
ttrfanatic12-Apr-05 19:30
ttrfanatic12-Apr-05 19:30 
GeneralRe: Invalid Data at root level Pin
User 9372314-May-05 2:44
User 9372314-May-05 2:44 
GeneralRe: Invalid Data at root level Pin
fixerfrasse13-Jun-05 1:55
fixerfrasse13-Jun-05 1:55 
Generaldoesnt work with dataviews Pin
kevin herring4-Mar-05 3:10
susskevin herring4-Mar-05 3:10 
Generalvery kewl but doesn't work Pin
Maestrocity2-Mar-05 12:01
Maestrocity2-Mar-05 12:01 
GeneralRe: very kewl but doesn't work Pin
CodeBureau - Matt Simner3-Mar-05 23:30
CodeBureau - Matt Simner3-Mar-05 23:30 
GeneralRe: very kewl but doesn't work Pin
pinx8-Jun-05 4:10
pinx8-Jun-05 4:10 
GeneralGDI+ Error Pin
Big Cheese23-Feb-05 4:48
Big Cheese23-Feb-05 4:48 
GeneralRe: GDI+ Error Pin
CodeBureau - Matt Simner23-Feb-05 16:39
CodeBureau - Matt Simner23-Feb-05 16:39 
GeneralRe: GDI+ Error Pin
Big Cheese24-Feb-05 5:22
Big Cheese24-Feb-05 5:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.