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

Visual Studio Visualizer:第一部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2013年4月17日

CPOL

5分钟阅读

viewsIcon

72937

本项目展示了一个变通方法,可以使不可序列化的对象可用于自定义可视化工具。

引言

项目网站:http://vsdatawatchers.codeplex.com

添加 Visual Studio 可视化工具以查看数据

  • 数据集;
  • 数据表;
  • 数据行;
  • 数据视图;
  • 数据行视图;
  • 数据行集合。

第二部分可在以下地址找到: https://codeproject.org.cn/Articles/584739/Visual-Studio-Visualizer-Part-2-Entity-Framework 

第三部分可在以下地址找到:https://codeproject.org.cn/Articles/599504/Visual-Studio-Visualizer-Part-3-Collection-visuali

使用代码

访问项目主页,下载您需要的版本(2010 或 2012),解压缩,并将 DLL 放在正确的文件夹中,即 Documents\Visual Studio xxxx\Visualizers

使用 VS 进行调试时,对于 DataSetDataTableDataRowDataView 对象,有一个额外的可视化工具选项。

关注点

出于某种原因,数组不允许在 Visual Studio 调试中进行可视化,但当使用 VisualizerDevelopmentHost 类来测试可视化工具时,数组是允许的。

本项目展示了一个变通方法,可以使不可序列化的对象可用于我们的自定义可视化工具。

创建可视化工具

本项目是使用 Visual Studio Express 创建的,任何版本都可以使用。

首先创建一个类库项目,然后添加对 Visual Studio 可视化工具 API 的引用,该 DLL 可以在以下位置找到:Visual Studio 安装文件夹)\Common7\IDE\ReferenceAssemblies\v2.0 Microsoft.VisualStudio.DebuggerVisualizers.dll

添加可视化工具将接收的对象类型的引用

[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DSVisualizer), typeof(VisualizerObjectSource), 
    Target = typeof(DataSet), Description = "My DataSet Visualizer")]
[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DTVisualizer), typeof(VisualizerObjectSource), Target = typeof(DataTable), 
    Description = "My DataTable Visualizer")]
[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DRVisualizer), typeof(DataRowVisualizerObjectSource), 
    Target = typeof(DataRow), Description = "My DataRow Visualizer")]
[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DVVisualizer), typeof(DataRowVisualizerObjectSource), 
    Target = typeof(DataView), Description = "My DataView Visualizer")]
[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DRVVisualizer), typeof(DataRowVisualizerObjectSource), 
    Target = typeof(DataRowView), Description = "My DataRowView Visualizer")]
[assembly: System.Diagnostics.DebuggerVisualizer(
    typeof(DRCollectionVisualizer), typeof(DataRowVisualizerObjectSource), 
    Target = typeof(DataRowCollection), Description = "My DataRowCollection Visualizer")] 

这可以位于项目中的任何 cs 文件中,但必须在任何命名空间声明之外。如您所见,某些类型使用 VisualizerObjectSource,而其他类型使用 DataRowVisualizerObjectSource,这是因为 DataRow 类型需要一些处理才能使用,这将在后面介绍。

将要获取要可视化对象的类必须继承自 DialogDebuggerVisualizer

这将允许重写 Show 方法

protected override void Show(IDialogVisualizerService windowService, 
          IVisualizerObjectProvider objectProvider) 

objectProvider 将允许获取要可视化对象的实例

DataTable dt = objectProvider.GetObject() as DataTable; 

此代码段用于数据表可视化工具。我遵循的规则是每个对象类型一个类。

windowService 是向用户显示窗体或用户控件的内容

DialogResult dr = windowService.ShowDialog(mainForm); 

mainForm 是一个使用 dt 对象初始化的窗体实例。现在我们可以将其绑定到 DataGridView,以便用户可以查看数据。

数据行

如前所述,数据行类型不能按原样使用,因为它没有实现 ISerializable 接口。那么我们该如何使用它呢?

要获取 dataRow,我们必须创建一个自定义 VisualizerObjectSource,因此我们创建 DataRowVisualizerObjectSource,它继承自 VisualizerObjectSource,现在我们可以重写 GetData 方法

public override void GetData(object target, Stream outgoingData)
{
    if (target != null)
    {
        if (target is DataRow)
        {
            DataRow row = target as DataRow;
            DataTable table;

            if (row.Table == null)
            {
                table = new DataTable("DataRowDebuggerTableObjectSource");

                for (int i = 0; i < row.ItemArray.Length; i++)
                {
                    table.Columns.Add(string.Format("Col{o}", i.ToString()), typeof(string));
                }
            }
            else
            {
                table = row.Table.Clone();
            }

            table.LoadDataRow(row.ItemArray, true);

            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(outgoingData, table);
        } 

诀窍是将数据行包装在数据表中,因为数据表实现了 ISerializable 接口。

所以现在我们已经包装了数据行,我们可以简单地调用

DataTable dt = objectProvider.GetObject() as DataTable; 

在我们自定义的 debuggerVisualizer DRVisualizer 中,并将其传递给 mainForm

使可视化工具准备好进行编辑

如果对象是可编辑的,我们可以使可视化工具将用户在可视化工具中所做的更改刷新到 Visual Studio 中正在调试的对象。

objectProvider 可以告诉我们对象是否可编辑,在变量 objectProvider.IsObjectReplaceable 中,因此我们可以用已更改的对象替换它

DialogResult dr = windowService.ShowDialog(main);
if (objectProvider.IsObjectReplaceable && dr == DialogResult.OK)
    objectProvider.ReplaceObject(ds); 

ReplaceObject 方法是可用于将更改持久化到调试变量的方法之一,这些方法是:ReplaceData()ReplaceObject()TransferData()TransferObject()

MSDN 文档关于这些方法

“使用 Replace 方法之一会在调试器中创建一个新的数据对象,该对象将替换正在可视化的对象。如果要更改原始对象的内容而不替换它,请使用 Transfer 方法之一。”

TransferObject()ReplaceObject() 方法发送正在可视化的对象,但对象必须实现 ISerializable

TransferData()ReplaceData() 方法用于我们需要实现自定义序列化时,这些方法接收一个流,在我们的自定义 VisualizerObjectSource 中,我们可以重写 ReplaceData()TransferData()

因此,在可视化工具中的 DataRow 的情况下,我们有

if (objectProvider.IsObjectReplaceable && dr == DialogResult.OK)
{
    //DataRow is not serializable, so we serialize the item array,
    //in the TransferData override of the DataRowVisualizerObjectSource we deserialize the
    //itemArray and update the values od the original DataRow
    objectProvider.TransferData(StreamSerializer.ObjectToStream(null, dt.Rows[0].ItemArray)); 
}   

StreamSerializer.ObjectToStream 是一个辅助函数,它接收一个对象并创建一个流,在这种情况下是 DataRow 的 itemArray,但它也可以是一个包含该数据行的 datatable。

public static Stream ObjectToStream(Stream outgoingData, object data)
{
    if (outgoingData == null)
        outgoingData = new MemoryStream();

    BinaryFormatter formatter = new BinaryFormatter();
    formatter.Serialize(outgoingData, data);

    return outgoingData; 
} 

因此,在我们的自定义 VisualizerObjectSource 中,我们可以重写 TransferData() 方法并更新已更改的值

public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
    if (target is DataRow)
    {
        DataRow row = target as DataRow;
        var itemArray = StreamSerializer.StreamToObject(incomingData) as object[];

        //the first column was added on the visualizer form, is the status column
        for (int i = 1; i < itemArray.Length; i++)
        {
            if (!(target as DataRow).Table.Columns[i - 1].ReadOnly && 
                            !CompareData.Compare(row, itemArray, i - 1, i))
                 row[i - 1] = itemArray[i];
        }
     }    

目标是原始对象,因此更改它将把更改传递给用户正在调试的变量。

测试可视化工具

为了测试可视化工具,我们必须在自定义可视化对象中创建一个公共方法,例如测试数据集可视化工具

public static void TestShowVisualizer(object objectToVisualize)
{
    VisualizerDevelopmentHost visualizerHost = 
           new VisualizerDevelopmentHost(objectToVisualize, typeof(DSVisualizer)); 
    visualizerHost.ShowVisualizer();
}  

VisualizerDevelopmentHost 对象构造函数有三个重载,上面的重载适用于简单的可视化工具,如果我们必须使用自定义 VisualizerObjectSource,就像在 DataRow 可视化工具中使用的那样,我们有

public static void TestShowVisualizer(object objectToVisualize)
{
    VisualizerDevelopmentHost visualizerHost = 
      new VisualizerDevelopmentHost(objectToVisualize, 
      typeof(DRVisualizer), typeof(DataRowVisualizerObjectSource));
    visualizerHost.ShowVisualizer();
}

这里的第三个参数是 VisualizerObjectSource 类型。还有一个重载,我们可以在其中定义 objectToVisualize 是只读还是非只读。

我没有设法使用 TestShowVisualizer 测试 ReplaceObject,在 VS 中调试并传递给测试方法的 dataset 从未更新。这仅在使用编译后的 DLL 并将其放置在 VS visualizers 文件夹中时才有效。

在 VS 中使用可视化工具

要在 Visual Studio(2010 或 2012)中使用可视化工具,请参阅“使用代码”。

当在调试中观察变量时,有一个放大镜允许您选择注册到该类型变量的多个可视化工具。

如果 DLL 在正确的位置,应该有两个 dataset 可视化工具,一个是 Visual Studio 自带的,一个是我们的。

选择 FR DataSet Visualizer 将打开可视化工具

在这里,我们可以在树视图中看到所有数据表,并在网格视图中看到所选数据表的数据。

将鼠标悬停在单元格上,我们可以看到更多信息

在属性选项卡上,我们可以看到树视图中选定对象的所有属性

在选项选项卡上,我们可以过滤可见的列或显示的数据,要过滤列,我们可以只显示包含某些字符串的列,用“;”分隔

或者我们可以隐藏包含某些字符串的列,用“;”分隔

要过滤数据,我们可以设置绑定源过滤器字符串

还有一个包含更多选项的菜单,例如接受或拒绝更改(如果对象可编辑)。我们还可以查看估计的数据大小

此项目有一个选项可以将数据导出到 Excel 文件,这是使用 EPPlus 库完成的。

历史

  • 2013-04-17:当前支持 Visual Studio 2010 和 Visual Studio 2012。
  • 2013-04-24:测试和使用可视化工具。
  • 2013-04-25:持久化未实现 ISerializable 的对象的更改。
  • 2013-06-10:链接已更新。
© . All rights reserved.