Click here to Skip to main content
Click here to Skip to main content

Enhanced DataSet Quick Watch

, 21 Feb 2005 CPOL
Rate this:
Please Sign up or sign in to vote.
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:

    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:

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.

    // 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.

    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)

Share

About the Author

CodeBureau - Matt Simner
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 PinmemberDilip Baboo12-Mar-09 9:32 
GeneralVisual Studio 2005 Framework 2.0 Pinmembericedragon4-May-07 4:52 
Generalsomething for VS 2005 Pinmemberfadee2-Jan-07 21:21 
GeneralGOOD WORK PinmemberEIHABWADY6-May-06 5:16 
Generalfix to DataTable not in DataSet Pinmembersharaabi15-Dec-05 0:11 
GeneralRe: fix to DataTable not in DataSet PinmemberAaronVisser15-Dec-05 14:59 
GeneralRe: fix to DataTable not in DataSet Pinmemberroberto galbiati26-Feb-06 23:49 
GeneralERROR: Not a dataset, datatable or datarow PinmemberIhor Bobak1-Dec-05 9:46 
GeneralDoesn't work on Typed DataSet.. PinmemberEran S3-Aug-05 5:11 
GeneralRowStateFilter does not work PinmemberPinx9-Jun-05 3:35 
GeneralMethod not found : void System.Windows.Forms.set_location(...) Pinmembernghadiri8-Jun-05 19:31 
GeneralInvalid Data at root level PinmemberCKurmann29-Mar-05 21:17 
GeneralRe: Invalid Data at root level PinmemberMatt Simner6-Apr-05 4:32 
GeneralRe: Invalid Data at root level Pinmemberttrfanatic12-Apr-05 20:30 
GeneralRe: Invalid Data at root level PinmemberAngelOfBinolino4-May-05 3:44 
GeneralRe: Invalid Data at root level Pinmemberfrasse5313-Jun-05 2:55 
Generaldoesnt work with dataviews Pinsusskevin herring4-Mar-05 4:10 
Generalvery kewl but doesn't work PinmemberMaestrocity2-Mar-05 13:01 
GeneralRe: very kewl but doesn't work PinmemberMatt Simner4-Mar-05 0:30 
GeneralRe: very kewl but doesn't work PinmemberPinx8-Jun-05 5:10 
GeneralGDI+ Error PinmemberBig Cheese23-Feb-05 5:48 
GeneralRe: GDI+ Error PinmemberMatt Simner23-Feb-05 17:39 
GeneralRe: GDI+ Error PinmemberBig Cheese24-Feb-05 6:22 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 21 Feb 2005
Article Copyright 2005 by CodeBureau - Matt Simner
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid