65.9K
CodeProject 正在变化。 阅读更多。
Home

增强型DataSet Quick Watch

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (14投票s)

2005年2月21日

CPOL

3分钟阅读

viewsIcon

138004

downloadIcon

2609

一个 VS.NET 插件,用于在调试时可视化标准和类型化的 DataSet、DataTable 和 DataRow。

Sample Image - DSWatchEx1.png

引言

这个插件本质上是对 Mohammed Barqawi 的优秀DataSet 快速监视插件的更新。 请参考该文章了解原始概念和代码。

该插件的实现非常棒,但明显不支持类型化的数据集。 我添加了一些东西,使原始想法更进一步,并希望使调试时可视化数据集的生活更加轻松。

有什么新功能?

类型化 DataSet 支持

这允许所有类型化的 DataSet(直接继承自 System.Data.DataSet)与该插件一起使用。 这也适用于类型化的 DataTableDataRow

支持 DataTables 和 DataRows

这允许您(在代码中)选择一个表或行,并加载数据集(在输出中选择该表或行)。

行筛选器支持

还添加了自由文本行筛选器和“DataViewRowState”筛选器,以帮助进行调试。 此功能基于每个表。

视觉增强

DataSet Watch 窗体已修改为使用自定义“EnhancedGrid”控件,以提供筛选和稍微“色彩缤纷”的输出。 如果您不喜欢网格的外观,可以通过更改 EnhancedGrid UserControl 轻松更改它。

我还没有完全完成添加用户首选项支持!

使用代码

调试器表达式

最初的概念仍然存在,但我对我们获取和检查调试器表达式的方式进行了一些修改。 我重构了每个表达式的构造,使其基于输入语言工作

    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'");
            }
        }
    }

其中 str(调试器中选定的文本) == "myDataTable",下面这行将为 getTableNameFromTableExpression 分配一个特定于语言的调试器表达式字符串

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

这个特定的表达式用于从选定的 DataTable 获取表名。

类型化的 DataSets

当我们评估返回意外类型的表达式时,会提供对类型化数据集的支持。 发生这种情况是因为调试器返回您选择的表达式的“实际”类型 - 例如,MyNamespace.MyTypedDataSet.MyTableRow

如果您选择的不是 DataSetDataTableDataRow(或任何直接派生自这些类型的),则 ExpressionHasError 方法会在表达式的值中找到文本 "error:"

如果返回一个类型化的数据对象(并且我们返回类型名称),则我们找到基类型并再次评估该表达式...如果它是一个类型化的数据集、表或行,那么我们应该第二次找到正确的 (System.Data...) 类型。

    // 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;
    }

选择特定行

如果我们在调试器中通过变量选择了行:myRow 或使用索引器:myDataSet.Tables[0].Rows[0],我们知道可以通过 rowID 属性找到该行(在表中)的序号位置。 然后,我们可以使用此信息在输出窗体中选择相应的行(和表)。

行筛选

Row Filtering

这与标准 DataView 筛选(使用自由文本行筛选器)和 DataViewRowState 筛选器(用于显示特定状态下的所有行)结合使用。 以下应用了两个筛选器的组合。

    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);
        }

    }

EnhancedGrid UserControl 定义了一个 FilterChanged 事件,传递上下文信息以允许父窗体更改其状态栏中的文本。

© . All rights reserved.