正确操作windows窗体的Timer事件

[原文作者]Jared Parsons                                       
 
     Windows窗体的时间(Timer)类允许用户在一个时间段内执行特定的操作。时间对象会在设定的时间内开始一个Tick事件,用户可以容易的响应这个事件。如果软件开发者想在在一个指定的时间段内检查一个特定的条件(比如2秒钟,我会在这篇文章中用两秒作为范例),这时这个事件就会非常有用。
 
     偶尔用户会惊奇的发现Tick事件会比期望当中的更快地被触发。比较在两个调用期间等待两秒钟而言,取而代之的是Tick事件几乎是在一个被调用的过程完成后就被立即被触发了。
 
     这里所发生的是这个事件在事件循环机制作用下所产生的状态变化。时间事件的间隔期是由现实世界的时间来计算的。所以直白的讲,每隔两秒钟windows将认为时间间隔结束,然后发送一个新的Tick事件消息。下一时间段的windows窗体事件就不会再执行代码,一个tick事件会被触发【1】。
 
     现在我们可以想象一下我们已经有如下的代码。
 
     Private Sub OnTimerTick () Handles m_timer.Tick
         RunSomeOperation ()
     End Sub
 
     考虑一下如果 RunSomeOperation 用时超过2秒钟将发生什么。Tick事件会在RunSomeOperation过程当中被实时的触发,另外一个Tick事件会等候处理。一旦我们离开OnTimerTick过程,我们会回到Windows窗体代码,这些代码会巡视到Tick事件并且促使触发它,让我们重新回到OnTimerTick过程。
 
     这是与大多数人的期望矛盾的。大多数人会期望Tick事件应该在窗体代码完成后的两秒被触发。
 
     要想解决这个矛盾,开发者可以在处理一个timer事件的时候停止时间计数器的计数。然后再退出事件处理程序后从新激活计数器。这会使windows从激活计数器时才开始计算时间间隔。这样做的结果是使得timer事件在代码停止执行后的两秒钟才被触发。请参考以下代码:
 
    Private Sub OnTimerTick () Handles m_timer.Tick
      M_timer.stop ()
      Try
             RunSomeOperation ()
       Finally
             M_timer.Start ()
       End Try
    End Sub
 
 
 
      【1】这不是100%正确。不过这确实是无论什么时候应用程序开始又一次的循环事件时的情况。循环事件(更加确切的说是当循环事件发生或没有发生的时候)也与我们的这篇讨论相关联。

使用Visual Studio插件浏览Office2007 文档

[原文链接]:Handy Visual Studio Add-In to View Office 2007 Files

[原文作者]:Beth Massi

      上个月我在Redmond的时候向一个同事提起过我真的非常欣赏Office 2007正在应用的Open XML的格式Opem XML 是继如doc、.dot、.xls 和 .ppt等二进制 文件后一种全新的office文件格式)和我是如何应用这种格式及”LINQ toXML” 的.他也向我介绍了VSTO Power Tools,这个工具包含了称作Open XML Package Editor 的Visual Studio 插件。 这个工具可以让用户通过简洁小巧的树状菜单在Word,PowerPoint和Excel中浏览Office2007 文档,这可以使得用户操纵Open XML 文件和XML中的其它各个部分。在安装了VSTO Power Tools 后, 只要从Visual Studio项目中直接双击Office 2007 文件打开这个工具就可以使用了。

<来自VSTO Power Tool文档>
      打开XML Package Editor
      这是一个Visual Studio2008插件,它允许分析和编辑Open Packaging Conventions的文件, 包括Word, Excel and PowerPoint 文档。它的特性如下:
  • 在Visual Studio里直接打开Office 2007 Open XML Package 文件或者 XPS Package 文件。 (Office XML 格式是针对 Office Word 2007、Office Excel 2007 和 Office PowerPoint 2007 的完全可编辑文件格式,XPS 是为 Microsoft Windows Vista 操作系统推出的标页码的固定文档格式。)
  • 直观和易于浏览的Package 文件树状结构。
  • 可以在Visual Studio的rich XML 编辑器里直接打开文件所包含的XML部分。
  • 易于使用的用户接口去添加和移除文件的相关部分部件和关连。
  • 对文件导入导出所包含的各个部分的内容。
  • 探测在Visual Studio中打开的文件是否在外部被更改了。并提示用户重载文件在不需要关闭任何打开的XML 部件编辑器。
  • 通过Visual Studio 的新建对话框提供的一套模板来创建新的Office Packages

      图一:显示了Visual Studio中打开的Open XML Package文件树形结构:

      图二:如果您双击任何文件中的XML组成部分,被点击的部分将在标准的Visual Studio XML编辑其中打开。
 
<文章结束>
      我注意到了一件事情,如果XML编辑器打开着,并且XML内容全部集中在一行上,您可以选择所有内容然后剪切并黏贴回编辑器,这时XML内容会自动进行分行并回到正常显示格式。(Ctrl + A,X,V).
还有其它9个工具包括在VSTO Power Tools 中,我强烈推荐使用如果你正在使用Visual Studio进行Office开发的话。 并且您可以查看VSTO Team BlogVSTO Developer Portal 去了解更多Visual Studio 的Office开发信息。
 
Enjoy!

  

Visual Studio 2008中的新元件TableAdapterManager

[原文作者]: Beth Massi

[原文链接]: The New TableAdapterManager in Visual Studio 2008

        在我以前的TableAdapters and Transactions文章中,我展示了一套关于如何在多层数据表结构的数据集中完成事务内部的分等级更新。我在这里给出的例子演示了Visual Studio 2005如何用数据库事务或者TransactionScope去更新数据。这需要一些代码来管理行的正确更新顺序,TableAdapters上的连接和处理,以及在回滚的情况下,你希望保持数据集中原有的变化。

        幸运的是,在Visual Studio 2008DataSet生成器有了新的提高,它创建了一个新的类通过只有几行代码自动处理所有这些事情!进入TableAdapterManager

        在这篇文章中,我将要借用以前的应用程序同时把它升级到Visual Studio 2008,要清楚的一点是,我将不会去升级它的目标框架,因为我希望程序能继续在NET Framework 2.0上运行。(Visual Studio 2008 可以通过一个叫做Multi-Targeting的特性去开发支持NET 2.0, 3.0 and 3.5 Frameworks的应用程序。关于这方面的更多使用方法,请看这里

    当你在 Visual Studio 2008中打开NorthwindTransaction.sln文件,它将会启动一个升级项目向导,使sln项目文件兼容于Visual Studio 2008. 启动以后,在资源管理器中双击OrdersDataSet 以打开数DataSet Designer。在属性视窗中会看到“分等级的更新” 选择True并保存. 这表示告诉数据集发生器去生成了TableAdapterManager . 注意每当你创建新的数据集时,默认的就是True

 

    现在,展开OrderForm以打开Windows Form设计器,删除工具箱顶部的Dropdown控件(TransactionToolStripDropDownButton)因为我们现在只要有一个简单的Save() 方法。右键点击窗体察看代码,在OrdersBindingNavigatorSaveItemclick事件中移掉Case语句,用Me.Save()代替:

Private Sub OrdersBindingNavigatorSaveItem_Click() Handles OrdersBindingNavigatorSaveItem.Click

    Me.Validate()

    ‘Commit all data to the OrdersDataSet

    Me.OrdersBindingSource.EndEdit()

    Me.Order_DetailsBindingSource.EndEdit()

    If Not Me.OrdersDataSet.HasErrors Then

        If Me.OrdersDataSet.HasChanges Then 

            If Me.Save() Then

                MessageBox.Show(“Your changed have been saved.”, Me.Text, _

                                MessageBoxButtons.OK, MessageBoxIcon.Information)

            Else

                MessageBox.Show(“Your changes could not be saved!”, Me.Text, _

                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

            End If

        Else

            MessageBox.Show(“Please make changes first.”, Me.Text, _

                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

        End If

    Else

        MessageBox.Show(“Please correct the errors with this data first.”, Me.Text, _

                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

    End If

End Sub

    现在到了很有趣的部分。我们将删除所有的Savexxx()方法并且改写成使用新的TableAdapterManager简单的Save()方法。这个代码和以前用的SaveInDatabaseTransaction() 方法的效果是一样的。

''' <summary>
''' Performs an ordered save so that keys are properly updated in
''' the child table and so that deleted child rows are submitted
''' to the database first inside a database transaction automatically. 
''' VS 2008 generates code that takes care of the saving in the proper
''' order in a database transaction.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function Save() As Boolean
    Dim saved As Boolean = False 
    If Me.OrdersDataSet.HasChanges Then
        Try
            Dim manager As New OrdersDataSetTableAdapters.TableAdapterManager 
            'Back up the dataset so that if the transaction fails, then the entire 
            ' dataset is restored to it's original state.
            manager.BackupDataSetBeforeUpdate = True 
            manager.Order_DetailsTableAdapter = Me.Order_DetailsTableAdapter
            manager.OrdersTableAdapter = Me.OrdersTableAdapter 
            saved = (manager.UpdateAll(Me.OrdersDataSet) > 0) 
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End If 
    Return saved
End Function

    发现没有,现在的代码简洁多了。以前我们必须去管理Order的更新,连接和事务处理,以及回卷的状态。现在所有这些都照顾到了。既然我们不再需要用到它,我们也可以在form中移掉MergeAfterSave方法以及TableAdapter partial 类中的AssignConnection方法。注意,如果我们已经创建了一个新的窗体,那么它就已经为我们创建了TableAdapterManager实例,预置了TableAdapter实例。

    运行应用程序选择一个客户的订单,然后在窗体上添加、更新和删除父子行。当我们点击保存按钮,这些行将会被更新和插入到parent-child order中,而在child-parent order删除,所有的这些都在数据库事务内部完成。一旦你打开SQL Server Profiler,我们可以看到:

       你也可以通过设置UpdateOrder属性来指示TableAdapterManager你想先处理更新过程。更多信息请查看TableAdapterManager文档

       TableAdapterManager为我们省去了很多代码,但是你仍需要确认你已经完全地设置好你的数据集去处理foreign-key约束,就像我在这片文章中提到的,TableAdapters按特定的顺序调用Fill方法。更多详细信息请阅读这篇文章,关于在你的数据集中使用foreign-key约束,这样能够通过TableAdapterManager完全更新。我已经附上更新好的程序.

Enjoy!

Attachment(s):NorthwindTransaction2008.zip

Visual Studio – 创建Add-In 工程

[原文作者]: Beth Massi

[原文链接]:  Visual Studio Tip of the Day – Let’s Build an Add-In

我已经开始使用Visual Studio 创建一些Add-In的工程, 这的确是一个比较容易的过程. 真正值得高兴的是,我们不需要去单独安装SDK 去创建Add-in工程,这已经集成在Visual Studio. 我之前写过一个从Sararss feed浏览他的文章的程序.现在我们看看怎么用Visual Studio 2008实现的. 你可以从这里下载代码.

首先我们添加一个新的工程到你的项目中, Add –> New Project, 展开 “Other Project Types”选择”Extensibility” 然后选择”Visual Studio Add-In”.

这会打开一个向导帮助你配置一些你的add-in程序.第一步是选择语言”Create an Add-in using Visual Basic”, 进行到下一步.

下一步选择add-in程序的宿主.在这个程序中我们选择 Visual Studio 2008 Macros”,因为我只想让这个程序起运并显示在工具菜单栏上.

再下一步是Add-in程序的名字和描述. 我们把名字和描述改成 Visual Studio Tip of the Day”.

下一步,向导会问我们怎么样去起运Add-in程序, 在这个程序中我们需要在Visual Studio打开的时候载入,并且提供一个在工具栏上的菜单.选择相应的选项,进行到下一步.

最后一步,向导会我们是否需要一个”About”,我们会跳过这一步, 结束向导.

一个新Add-in工程会被加入到你的项目中.  然后打开Add-in工程的属性页,选择”Compile”, 进入”Advanced Compile Options…”,Target Framework改成 .NET Framework 3.5

我们需要添加引用到我们上文提到的(SaraRssViewer) 工程, 现在我们已经有了引用并且配置好了target framework,打开Connect.vb 文件,” OnStartUpComplete”方法中我们会加入代码去载入窗体.

Public Sub OnStartupComplete(ByRef custom As Array) _

  Implements IDTExtensibility2.OnStartupComplete

 

    Dim frm As New SaraRSSViewer.Form1

    frm.Show()

End Sub

当你从工具菜单选择我们的Add-in的时候, 这个程序会被运行, 我们需要把同样的代码加入Exec方法.

Public Sub Exec(ByVal commandName As String, _

                ByVal executeOption As vsCommandExecOption, _

                ByRef varIn As Object, ByRef varOut As Object, _

                ByRef handled As Boolean) _

           Implements IDTCommandTarget.Exec

 

    handled = False

    If executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault Then

        If commandName = “MyAddin1.Connect.MyAddin1” Then

 

            Dim frm As New SaraRSSViewer.Form1

            frm.Show()

 

            handled = True

            Exit Sub

        End If

    End If

End Sub

 

然后我们按F5运行我们的程序, 这样你就可以看到我们的Add-in程序运行的效果,

你也可以自己定制你的菜单名,OnConnection方法中,定义Command变量,第三个参数是显示菜单名,第四个是改变tolltip.

Dim command As Command = _

    commands.AddNamedCommand2(_addInInstance, _

                              “MyAddin1”, _

                              “Tip of the Day”, _

                              “Display the Visual Studio tips of the day”, _

                              True, 59, Nothing, _

                              CType(vsCommandStatus.vsCommandStatusSupported, Integer) + _

                              CType(vsCommandStatus.vsCommandStatusEnabled, Integer), _

                              vsCommandStyle.vsCommandStylePictAndText, _

                              vsCommandControlType.vsCommandControlTypeButton)

当我们编译Add-in工程的时候,会把.addin 文件添加到Visual Studio 2008\Addins\文件夹下面. 通过这个例子,我们可以看创建一个Add-in程序的确很简单.你也可以一些尝试其他的例子,比如OfficeAdd-in等等.

在以后的文章中,我会写一些关于如何把Add-in程序部属到其他机器的方法.