当使用 WinForms 提取数据时,XML 会转换为纯文本。有没有办法维护 XML,或将其转换回 C#?

Posted

技术标签:

【中文标题】当使用 WinForms 提取数据时,XML 会转换为纯文本。有没有办法维护 XML,或将其转换回 C#?【英文标题】:XML converts to plaintext when data is pulled using WinForms. Is there a way to maintain the XML, or convert it back in C#? 【发布时间】:2020-04-21 00:23:24 【问题描述】:

我正在创建一个程序,在 SQL Server 中输出 SP_WhoIsActive 的相关列,以便我更广泛的团队中无权访问服务器的其他成员可以查看目前是否有任何昂贵的查询正在运行。

我已经设法创建了一个提取数据的 WinForm,但不幸的是 XML Query 已转换为纯文本,这实际上使其无用,因为一行中的文本太长了。

如何将其保留为 XML,将 XML 的第一行作为指向 XML 的链接,或者在需要时将其重新转换回 XML?

提前感谢您的帮助。

    connection = new SqlConnection(builder.ConnectionString))
                        
    connection.Open();
    Console.WriteLine("Connected.");

    //Query
    Console.WriteLine("Executing Query");
    String sql = @"Truncate table [Reporting].dbo.Active_Processes
                    use master
                    EXEC sp_WhoIsActive
                        @output_column_list = '[[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]',
                        @destination_table = '[Reporting].dbo.Active_Processes'

                    IF OBJECT_ID('TEMPDB..#temp') IS NOT NULL
                    DROP    TABLE   #temp
                    select  session_id [SP ID]
                            , [dd hh:mm:ss.mss] Duration
                            , start_time [Start Time]
                            , database_name as [Database]
                            , @@SERVERNAME as [Server]
                            , login_name [Login]
                            , sql_text [Query]
                            , CPU 
                    --      , blocking_session_id [Blocked By]
                    into #temp
                    from    [Reporting].dbo.active_processes ap
                    --where [dd hh:mm:ss.mss] > '00 00:03:00.000'

                    select  [SP ID] as [Process]
                            ,c.[Name] as Project
                            ,convert(nvarchar,t.[Start Time],113) as [Query Start]
                            ,t.Duration as [Dy H M S Ms]
                            ,ISNULL(CPU,0) as CPU
                            ,t.Query
                    from #temp t
                    INNER JOIN   LPFOR1.EDDS.eddsdbo.[Case] c
                    on              'EDDS' + CAST(c.artifactid as varchar) = t.[Database]
                    --INNER JOIN   LPFOR1.EDDS.eddsdbo.ResourceServer rs
                    --on              rs.artifactid = c.serverid
                    order by [Dy H M S Ms] desc";


    using (SqlCommand command = new SqlCommand(sql, connection))

    
        DataTable dt = new DataTable();
        // create data adapter
        SqlDataAdapter da = new SqlDataAdapter(command);
        // this will query your database and return the result to your datatable
        da.Fill(dt);
        this.grdSQLreport.DataSource = dt;
        da.Dispose();

谢谢。

Image of XML Issue

【问题讨论】:

我不太熟悉这个存储过程(一直使用 sp_who),假设它是定制的?将结果作为 DataSet 读取然后相应地显示/操作会不会更容易?您还可以提供一些示例代码并显示 XML 转换为纯文本的位置吗? 嗨,瑞安,感谢您的快速回复。 sp_whoisactive 是我发现的似乎是 sp_who/who2 的升级:whoisactive.com。通过DataSet,你的意思是DataGridView吗?如果是这样,这就是我目前正在使用的。我添加了包含 XML 的代码(sql_txt [Query] 然后 t.Query)。在服务器上运行 SQL 脚本仍然会输出为 XML。 填充后的 DataTable (dt) 看起来是否正确?所有的 XML 都在那里吗?我想是吗?我认为将数据显示为文本可能是 datagridview 的限制。我会看看我是否能想出一个合适的解决方案。 :) 是的,DataTable 填充后看起来是正确的,所有的列都在那里,只有查询列超长。我在上面附上了一张图片来说明。太好了,非常感谢您的帮助! 【参考方案1】:

根据我们在 cmets 中的对话,问题在于 DataGridView 显示文本的限制。

现在我要做的是在设计模式下手动创建列 - 您可以使用 DataPropertyName 绑定到数据集/对象中的列(如果您需要帮助,请告诉我)

然后我将创建一个带有“Query”或类似标题的按钮(或链接 - 取决于您喜欢的样式)列,然后您可以处理 DataGridView CellContentClick 方法以显示带有 RichTextEdit 控件或类似控件的新弹出窗口显示 XML。然后,您可以将其绑定到 xml 列并限制大小,以便单击以显示完整,或者将它们全部设置为“单击查看”或类似内容。

下面是乱七八糟的例子,你应该整理一下。

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
    
        var senderGrid = (DataGridView)sender;

        if (senderGrid.Columns[e.ColumnIndex].Name == "queryButtonColumn" &&
            e.RowIndex >= 0)
        
            var xml = ((WhoIsActive)dataGridView1.CurrentRow.DataBoundItem).XmlCol;
            Form2 display = new Form2(xml);
            //Show dialog or normally accordingly...
            //display.Show();
            display.ShowDialog();

        
    

要在将字符串放入弹出表单中的 RichTextBox 时将字符串格式化为 XML,您可以这样做。

public Form2(string text)
    
        InitializeComponent();
        richTextBox1.Text = System.Xml.Linq.XDocument.Parse(text).ToString(); //This doesn't actually parse with your data from the query so just set it to the variable.
    

同样,我可能不会在这里直接使用数据表,我会为 WhoIsActive 结果创建一个类,然后创建一个该类型的 List 变量并将其用作 DataGridView 的 DataSource。

为此创建一个类并添加适当的属性。

public class WhoIsActive

    public string XmlCol  get; set; 
    public string Random  get; set; 

然后在您的主窗体中创建一个变量,它是这些列表的列表。

List<WhoIsActive> results = new List<WhoIsActive>();

然后,当您从数据库中读取数据时,您可以填充此对象并将其绑定到数据网格。

adp.Fill(dt);

                foreach (DataRow item in dt.Rows)
                
                    var plop = new WhoIsActive
                    
                        Random = item["Random"].ToString(),
                        XmlCol = item["XmlCol"].ToString(),
                    ;
                    results.Add(plop);
                

                dataGridView1.DataSource = results;

很高兴编辑此内容,如有需要,请提供更详细的示例。

【讨论】:

嗨瑞恩,非常感谢你。我现在会好好尝试一下,但如果我遇到困难,我可能会寻求进一步的帮助。感谢您帮助我,非常感谢! 当然不用担心。我已经更新了我的答案以使用 WhoIsActive 结果的类表示,希望这会更好。 为了进一步改进我在 CellContentClick 中的答案,您可以将 if 语句更改为 if (senderGrid.Columns[e.ColumnIndex].Name == "queryButtonColumn") 假设您为列指定了一个合理的名称。 :) 如果您喜欢这种样式,也可以使用 LinkColumn 代替 Button。这将允许您实现与 SSMS 类似的样式,方法是具有固定宽度,然后单击它以显示完整。 为垃圾邮件道歉!我还有一个示例项目,我可以上传到某个地方,如果您遇到困难并且会发现这很有用。【参考方案2】:

它在 SQL Server Management Studio 中显示为可单击的 XML,因为 SSMS 以这种方式自动检测和格式化 XML。默认的DataGridView 没有这样的功能,因此您需要编写custom cell renderer 来实现相同的功能。

【讨论】:

以上是关于当使用 WinForms 提取数据时,XML 会转换为纯文本。有没有办法维护 XML,或将其转换回 C#?的主要内容,如果未能解决你的问题,请参考以下文章

在 Winforms 控件中显示 XML 数据

当标签的url部分时如何提取Oracle XML

Laravel AJAX 分页从旧数据中提取行

当 DataSource 值更改时,WinForms ComboBox 中的项目不会更新

在WinForms中使用XML配置文件持久化数据(保存和恢复用户和应用程序数据)

使用本地数据库为 winForms 创建安装程序