DesignerTransaction 类

定义

提供一种方法来对一系列的设计时操作进行分组,从而提高性能并能撤销大多数类型的更改。

public ref class DesignerTransaction abstract : IDisposable
public abstract class DesignerTransaction : IDisposable
type DesignerTransaction = class
    interface IDisposable
Public MustInherit Class DesignerTransaction
Implements IDisposable
继承
DesignerTransaction
实现

示例

下面的代码示例程序演示如何从设计器创建 DesignerTransaction 。 若要运行此示例,请将源代码编译为类库。 必须添加对 System.Design 程序集的引用。 在新项目中,添加对已编译 DLL 的引用,并将库中的组件添加到 工具箱

Visual Studio 中对此功能提供广泛支持。

另请参阅 演练:使用自定义组件自动填充工具箱

设计器可以选择显示有关设计器事务事件的通知。 如果在设计模式下将 实例 DTComponent 添加到窗体中,则会出现一个消息框,询问是否要接收设计器事务事件通知。 可以使用右键单击 实例 DTComponent时显示的快捷菜单切换这些通知。 使用 属性窗口更改值时,将创建事务。 还可以通过单击组件的快捷菜单上的“ 执行示例事务 ”,让设计器执行事务。

#using <system.dll>
#using <system.design.dll>
#using <system.windows.forms.dll>

using namespace System;
using namespace System::ComponentModel;
using namespace System::ComponentModel::Design;
using namespace System::Windows::Forms;
using namespace System::Windows::Forms::Design;

/*
This sample demonstrates how to perform a series of actions in a designer
transaction, how to change values of properties of a component from a
designer, and how to complete transactions without being interrupted
by other activities.

To run this sample, add this code to a class library project and compile.
Create a new Windows Forms project or load a form in the designer. Add a
reference to the class library that was compiled in the first step.
Right-click the Toolbox in design mode and click Customize Toolbox.
Browse to the class library that was compiled in the first step and
select OK until the DTComponent item appears in the Toolbox.  Add an
instance of this component to the form.

When the component is created and added to the component tray for your
design project, the Initialize method of the designer is called.
This method displays a message box informing you that designer transaction
event handlers will be registered unless you click Cancel. When you set
properties in the properties window, each change will be encapsulated in
a designer transaction, allowing the change to be undone later.

When you right-click the component, the shortcut menu for the component
is displayed. The designer constructs this menu according to whether
designer transaction notifications are enabled, and offers the option
of enabling or disabling the notifications, depending on the current
mode. The shortcut menu also presents a Perform Example Transaction
item, which will set the values of the component's StringProperty and
CountProperty properties. You can undo the last designer transaction using
the Undo command provided by the Visual Studio development environment.
*/

private ref class DTDesigner: public ComponentDesigner
{
private:
   bool notification_mode;
   int count;
   void LinkDTNotifications( Object^ /*sender*/, EventArgs^ /*e*/ )
   {
      if (  !notification_mode )
      {
         IDesignerHost^ host = dynamic_cast<IDesignerHost^>(GetService( IDesignerHost::typeid ));
         if ( host != nullptr )
         {
            notification_mode = true;
            host->TransactionOpened += gcnew EventHandler( this, &DTDesigner::OnDesignerTransactionOpened );
            host->TransactionClosed += gcnew DesignerTransactionCloseEventHandler( this, &DTDesigner::OnDesignerTransactionClosed );
         }
      }
   }

   void UnlinkDTNotifications( Object^ /*sender*/, EventArgs^ /*e*/ )
   {
      if ( notification_mode )
      {
         IDesignerHost^ host = dynamic_cast<IDesignerHost^>(GetService( IDesignerHost::typeid ));
         if ( host != nullptr )
         {
            notification_mode = false;
            host->TransactionOpened -= gcnew EventHandler( this, &DTDesigner::OnDesignerTransactionOpened );
            host->TransactionClosed -= gcnew DesignerTransactionCloseEventHandler( this, &DTDesigner::OnDesignerTransactionClosed );
         }
      }
   }

   void OnDesignerTransactionOpened( Object^ /*sender*/, EventArgs^ /*e*/ )
   {
      MessageBox::Show( "A Designer Transaction was started. (TransactionOpened)" );
   }

   void OnDesignerTransactionClosed( Object^ /*sender*/, DesignerTransactionCloseEventArgs^ /*e*/ )
   {
      MessageBox::Show( "A Designer Transaction was completed. (TransactionClosed)" );
   }

   void DoTransaction( Object^ /*sender*/, EventArgs^ /*e*/ )
   {
      IDesignerHost^ host = static_cast<IDesignerHost^>(GetService( IDesignerHost::typeid ));
      DesignerTransaction^ t = host->CreateTransaction( "Change Text and Size" );
      
      /* The code within the using statement is considered to be a single transaction.
              When the user selects Undo, the system will undo everything executed in this code block.
              */
      if ( notification_mode )
            MessageBox::Show( "Entering a Designer-Initiated Designer Transaction" );

      // The .NET Framework automatically associates the TypeDescriptor with the correct component
      PropertyDescriptor^ someText = TypeDescriptor::GetProperties( Component )[ "StringProperty" ];
      someText->SetValue( Component, "This text was set by the designer for this component." );
      PropertyDescriptor^ anInteger = TypeDescriptor::GetProperties( Component )[ "CountProperty" ];
      anInteger->SetValue( Component, count );
      count++;

      // Complete the designer transaction.
      t->Commit();
      if ( notification_mode )
            MessageBox::Show( "Designer-Initiated Designer Transaction Completed" );
   }

public:
   property DesignerVerbCollection^ Verbs 
   {
      // The Verbs property is overridden from ComponentDesigner
      virtual DesignerVerbCollection^ get() override
      {
         DesignerVerbCollection^ dvc = gcnew DesignerVerbCollection;
         dvc->Add( gcnew DesignerVerb( "Perform Example Transaction",gcnew EventHandler( this, &DTDesigner::DoTransaction ) ) );
         if ( notification_mode )
                  dvc->Add( gcnew DesignerVerb( "End Designer Transaction Notifications",
                     gcnew EventHandler( this, &DTDesigner::UnlinkDTNotifications ) ) );
         else
                  dvc->Add( gcnew DesignerVerb( "Show Designer Transaction Notifications",
                     gcnew EventHandler( this, &DTDesigner::LinkDTNotifications ) ) );

         return dvc;
      }
   }
   virtual void Initialize( IComponent^ component ) override
   {
      ComponentDesigner::Initialize( component );
      notification_mode = false;
      count = 10;
      IDesignerHost^ host = dynamic_cast<IDesignerHost^>(GetService( IDesignerHost::typeid ));
      if ( host == nullptr )
      {
         MessageBox::Show( "The IDesignerHost service interface could not be obtained." );
         return;
      }

      if ( MessageBox::Show( "Press the Yes button to display notification message boxes for the designer transaction opened and closed notifications.", "Link DesignerTransaction Notifications?", MessageBoxButtons::YesNo, MessageBoxIcon::Question, MessageBoxDefaultButton::Button1, MessageBoxOptions::RightAlign ) == DialogResult::Yes )
      {
         host->TransactionOpened += gcnew EventHandler( this, &DTDesigner::OnDesignerTransactionOpened );
         host->TransactionClosed += gcnew DesignerTransactionCloseEventHandler( this, &DTDesigner::OnDesignerTransactionClosed );
         notification_mode = true;
      }
   }

public:
   ~DTDesigner()
   {
      UnlinkDTNotifications( this, gcnew EventArgs );
   }
};

// Associate the DTDesigner with this component

[DesignerAttribute(DTDesigner::typeid)]
public ref class DTComponent: public System::ComponentModel::Component
{
private:
   String^ m_String;
   int m_Count;
   void InitializeComponent()
   {
      m_String = "Initial Value";
      m_Count = 0;
   }

public:
   property String^ StringProperty 
   {
      String^ get()
      {
         return m_String;
      }

      void set( String^ value )
      {
         m_String = value;
      }
   }

   property int CountProperty 
   {
      int get()
      {
         return m_Count;
      }

      void set( int value )
      {
         m_Count = value;
      }
   }
};
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

/*
    This sample demonstrates how to perform a series of actions in a designer 
    transaction, how to change values of properties of a component from a 
    designer, and how to complete transactions without being interrupted 
    by other activities.

    To run this sample, add this code to a class library project and compile. 
    Create a new Windows Forms project or load a form in the designer. Add a 
    reference to the class library that was compiled in the first step.
    Right-click the Toolbox in design mode and click Customize Toolbox.  
    Browse to the class library that was compiled in the first step and 
    select OK until the DTComponent item appears in the Toolbox.  Add an 
    instance of this component to the form.  
    
    When the component is created and added to the component tray for your
    design project, the Initialize method of the designer is called. 
    This method displays a message box informing you that designer transaction
    event handlers will be registered unless you click Cancel. When you set 
    properties in the properties window, each change will be encapsulated in 
    a designer transaction, allowing the change to be undone later.  
    
    When you right-click the component,	the shortcut menu for the component 
    is displayed. The designer constructs this menu according to whether 
    designer transaction notifications are enabled, and offers the option
    of enabling or disabling the notifications, depending on the current 
    mode. The shortcut menu also presents a Perform Example Transaction 
    item, which will set the values of the component's StringProperty and 
    CountProperty properties. You can undo the last designer transaction using 
    the Undo command provided by the Visual Studio development environment.
*/

namespace DesignerTransactionSample
{
    // Associate the DTDesigner with this component
    [DesignerAttribute(typeof(DTDesigner))]
    public class DTComponent : System.ComponentModel.Component
    {
        private string m_String;
    private int m_Count;
            
    public string StringProperty
    {
        get
            { return m_String; }
        set
        { m_String = value; }
    }
            
    public int CountProperty
    {
        get
        { return m_Count; }
        set
        { m_Count = value; }
    }

    private void InitializeComponent()
    {
        m_String = "Initial Value";
        m_Count = 0;
    }
    }
    
    internal class DTDesigner : ComponentDesigner
    {
    private bool notification_mode = false;
    private int count = 10;
        
    // The Verbs property is overridden from ComponentDesigner
    public override DesignerVerbCollection Verbs
    {
        get
        {				
            DesignerVerbCollection dvc = new DesignerVerbCollection();				
        dvc.Add( new DesignerVerb("Perform Example Transaction", new EventHandler(this.DoTransaction)) );
        if(notification_mode)
            dvc.Add(new DesignerVerb("End Designer Transaction Notifications", new EventHandler(this.UnlinkDTNotifications)));
        else
            dvc.Add(new DesignerVerb("Show Designer Transaction Notifications", new EventHandler(this.LinkDTNotifications)));				return dvc;
        }
    }
        
        public override void Initialize(System.ComponentModel.IComponent component)
        {
            base.Initialize(component);

            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));			
            if(host == null)
            {
                MessageBox.Show("The IDesignerHost service interface could not be obtained.");
                return;
            }

            if( MessageBox.Show("Press the Yes button to display notification message boxes for the designer transaction opened and closed notifications.","Link DesignerTransaction Notifications?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign) == DialogResult.Yes )
            {							
            host.TransactionOpened += new EventHandler(OnDesignerTransactionOpened);
                host.TransactionClosed += new DesignerTransactionCloseEventHandler(OnDesignerTransactionClosed);
                notification_mode = true;
            }
        }
        
        private void LinkDTNotifications(object sender, EventArgs e)
        {
            if(notification_mode == false)
            {
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));							
                if(host != null)
            {
            notification_mode = true;
                   host.TransactionOpened += new EventHandler(OnDesignerTransactionOpened);
                   host.TransactionClosed += new DesignerTransactionCloseEventHandler(OnDesignerTransactionClosed);
            }
        }
        }

        private void UnlinkDTNotifications(object sender, EventArgs e)
        {
        if(notification_mode)
            {
                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));							
            if(host != null)
                {				
            notification_mode = false;
                    host.TransactionOpened -= new EventHandler(OnDesignerTransactionOpened);
                    host.TransactionClosed -= new DesignerTransactionCloseEventHandler(OnDesignerTransactionClosed);
                }
            }
        }

        private void OnDesignerTransactionOpened(object sender, EventArgs e)
        {			
        System.Windows.Forms.MessageBox.Show("A Designer Transaction was started. (TransactionOpened)");
        }

        private void OnDesignerTransactionClosed(object sender, DesignerTransactionCloseEventArgs e)
        {			
        System.Windows.Forms.MessageBox.Show("A Designer Transaction was completed. (TransactionClosed)");
        }   

        private void DoTransaction(object sender, EventArgs e) 
        {			
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));			
            DesignerTransaction t = host.CreateTransaction("Change Text and Size");

            /* The code within the using statement is considered to be a single transaction.
           When the user selects Undo, the system will undo everything executed in this code block. */
            using (t)
            {
            if(notification_mode)
                System.Windows.Forms.MessageBox.Show("Entering a Designer-Initiated Designer Transaction");
                
                // The .NET Framework automatically associates the TypeDescriptor with the correct component
            PropertyDescriptor someText = TypeDescriptor.GetProperties(Component)["StringProperty"];
                someText.SetValue(Component, "This text was set by the designer for this component.");

                PropertyDescriptor anInteger = TypeDescriptor.GetProperties(Component)["CountProperty"];
            anInteger.SetValue(Component, count);
            count++;

                // Complete the designer transaction.
            t.Commit();
                
            if(notification_mode)
                System.Windows.Forms.MessageBox.Show("Designer-Initiated Designer Transaction Completed");
            }
        }
        
    protected override void Dispose(bool disposing)
    {
        UnlinkDTNotifications(this, new EventArgs());
        base.Dispose(disposing);
    }
    }
}
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

'   This sample demonstrates how to perform a series of actions in a designer 
'   transaction, how to change values of properties of a component from a 
'   designer, and how to complete transactions without being interrupted 
'   by other activities.

'   To run this sample, add this code to a class library project and compile. 
'   Create a new Windows Forms project or load a form in the designer. Add a 
'   reference to the class library that was compiled in the first step.
'   Right-click the Toolbox in design mode and click Customize Toolbox.  
'   Browse to the class library that was compiled in the first step and 
'   select OK until the DTComponent item appears in the Toolbox.  Add an 
'   instance of this component to the form.  

'   When the component is created and added to the component tray for your
'   design project, the Initialize method of the designer is called. 
'   This method displays a message box informing you that designer transaction
'   event handlers are being registered unless you click Cancel. When you set 
'   properties in the properties window, each change will be encapsulated in 
'   a designer transaction, allowing the change to be undone later.  

'   When you right-click the component, the shortcut menu for the component 
'   is displayed. The designer constructs this menu according to whether 
'   designer transaction notifications are enabled, and offers the option
'   of enabling or disabling the notifications, depending on the current 
'   mode. The shortcut menu also presents a Perform Example Transaction 
'   item which will set the values of the component's StringProperty and 
'   CountProperty properties. You can undo the last designer transaction using 
'   the Undo command provided by the Visual Studio development environment.	

Namespace DesignerTransactionSample

    ' Associate the DTDesigner with this component
    <DesignerAttribute(GetType(DTDesigner))> _
    Public Class DTComponent
        Inherits System.ComponentModel.Component
        Private m_String As String
        Private m_Count As Integer

        Public Property StringProperty() As String
            Get
                Return m_String
            End Get
            Set(ByVal Value As String)
                m_String = Value
            End Set
        End Property

        Public Property CountProperty() As Integer
            Get
                Return m_Count
            End Get
            Set(ByVal Value As Integer)
                m_Count = Value
            End Set
        End Property

        Private Sub InitializeComponent()
            m_String = "Initial Value"
            m_Count = 0
        End Sub

    End Class

    Friend Class DTDesigner
        Inherits ComponentDesigner

        Private notification_mode As Boolean = False
        Private count As Integer = 10

        ' The Verbs property is overridden from ComponentDesigner
        Public Overrides ReadOnly Property Verbs() As DesignerVerbCollection
            Get
                Dim dvc As New DesignerVerbCollection()
                dvc.Add(New DesignerVerb("Perform Example Transaction", AddressOf Me.DoTransaction))
                If notification_mode Then
                    dvc.Add(New DesignerVerb("End Designer Transaction Notifications", AddressOf Me.UnlinkDTNotifications))
                Else
                    dvc.Add(New DesignerVerb("Show Designer Transaction Notifications", AddressOf Me.LinkDTNotifications))
                End If
                Return dvc
            End Get
        End Property

        Public Overrides Sub Initialize(ByVal component As System.ComponentModel.IComponent)
            MyBase.Initialize(component)

            Dim host As IDesignerHost = CType(GetService(GetType(IDesignerHost)), IDesignerHost)
            If host Is Nothing Then
                MessageBox.Show("The IDesignerHost service interface could not be obtained.")
                Return
            End If

            If MessageBox.Show("Press the Yes button to display notification message boxes for the designer transaction opened and closed notifications.", "Link DesignerTransaction Notifications?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign) = DialogResult.Yes Then
                AddHandler host.TransactionOpened, AddressOf OnDesignerTransactionOpened
                AddHandler host.TransactionClosed, AddressOf OnDesignerTransactionClosed
                notification_mode = True
            End If
        End Sub

        Private Sub LinkDTNotifications(ByVal sender As Object, ByVal e As EventArgs)
            If notification_mode = False Then
                Dim host As IDesignerHost = CType(GetService(GetType(IDesignerHost)), IDesignerHost)
                If (host IsNot Nothing) Then
                    notification_mode = True
                    AddHandler host.TransactionOpened, AddressOf OnDesignerTransactionOpened
                    AddHandler host.TransactionClosed, AddressOf OnDesignerTransactionClosed
                End If
            End If
        End Sub

        Private Sub UnlinkDTNotifications(ByVal sender As Object, ByVal e As EventArgs)
            If notification_mode Then
                Dim host As IDesignerHost = CType(GetService(GetType(IDesignerHost)), IDesignerHost)
                If (host IsNot Nothing) Then
                    notification_mode = False
                    RemoveHandler host.TransactionOpened, AddressOf Me.OnDesignerTransactionOpened
                    RemoveHandler host.TransactionClosed, AddressOf Me.OnDesignerTransactionClosed
                End If
            End If
        End Sub

        Private Sub OnDesignerTransactionOpened(ByVal sender As Object, ByVal e As EventArgs)
            System.Windows.Forms.MessageBox.Show("A Designer Transaction was started. (TransactionOpened)")
        End Sub

        Private Sub OnDesignerTransactionClosed(ByVal sender As Object, ByVal e As DesignerTransactionCloseEventArgs)
            System.Windows.Forms.MessageBox.Show("A Designer Transaction was completed. (TransactionClosed)")
        End Sub

        Private Sub DoTransaction(ByVal sender As Object, ByVal e As EventArgs)
            Dim host As IDesignerHost = CType(GetService(GetType(IDesignerHost)), IDesignerHost)
            Dim t As DesignerTransaction = host.CreateTransaction("Change Text and Size")

            ' The code within the using statement is considered to be a single transaction.
            ' When the user selects Undo, the system will undo everything executed in this code block. 
            Try
                If (notification_mode) Then
                    System.Windows.Forms.MessageBox.Show("Entering a Designer-Initiated Designer Transaction")
                End If

                Dim someText As PropertyDescriptor = TypeDescriptor.GetProperties(Component)("StringProperty")
                someText.SetValue(Component, "This text was set by the designer for this component.")
                Dim anInteger As PropertyDescriptor = TypeDescriptor.GetProperties(Component)("CountProperty")
                anInteger.SetValue(Component, count)
                count = count + 1

                Exit Try
            Finally
                t.Commit()                
            End Try
            If (notification_mode) Then
                System.Windows.Forms.MessageBox.Show("Designer-Initiated Designer Transaction Completed")
            End If
        End Sub

        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            UnlinkDTNotifications(Me, New EventArgs())
            MyBase.Dispose(disposing)
        End Sub

    End Class
End Namespace 'DesignerTransactionSample

注解

事务可以跟踪以后可以撤消的操作。 可以通过取消事务来撤消事务期间所做的更改,该事务会自动尝试通过将每个已更改属性设置为其更改前值来撤消每个更改。 事务还可以通过在一系列操作期间将更新延迟到事务完成,来提高性能。

当事务正在进行时,某些组件会通过侦听 TransactionOpeningTransactionClosed 事件来延迟其处理,直到事务完成。 例如,在事务关闭之前,属性窗口不会在事务打开后更新其显示。

若要将事务用于可逆操作或多个操作,请让设计器为每个操作或应可逆的操作系列创建一个 DesignerTransaction 。 请注意,不要在事务外部执行可能会阻止一系列撤消事件成功完成的操作。

可以通过调用 CreateTransactionIDesignerHost方法获取新的 DesignerTransaction 。 请务必从活动IDesignerHost中获取每个 DesignerTransaction ,以便与设计器事务处理机制正确集成,而不是直接创建新的 DesignerTransaction

若要在事务中执行操作,必须先创建一个事务。 然后,必须在每次更改或更改集发生之前调用 方法,并在OnComponentChanged每次更改或更改集发生后调用 OnComponentChanging 方法。 最后,通过调用 Commit 方法完成并关闭事务。

注意

更改属性值时,请使用 SetValuePropertyDescriptor方法,该方法调用 的 IComponentChangeService 组件更改方法,并自动创建表示 DesignerTransaction 更改的 。

若要执行事务,请完成以下步骤:

  1. 调用 CreateTransaction 以获取 DesignerTransaction 可用于控制事务的 。

  2. try在 块中,对于要使用 跟踪DesignerTransaction的每个操作,调用 OnComponentChanging 方法,进行更改或更改,然后调用 OnComponentChanged 方法以指示已进行更改或更改。

  3. 若要完成事务,请从 块内finally调用 Commit

在 C# 中,可以使用 using 语句而不是 try/finally 块,如以下示例所示。

using (host.CreateTransaction() {  
// Insert your code here.  
}  

若要在提交事务之前取消并尝试回滚事务,请调用 Cancel 方法。 Cancel调用 方法时,将DesignerTransaction反向跟踪的操作以尝试回滚更改。 若要撤消作为早期事务的一部分发生的操作,必须使用开发环境提供的撤消命令。

构造函数

DesignerTransaction()

在不使用说明的情况下初始化 DesignerTransaction 类的新实例。

DesignerTransaction(String)

使用指定的事务说明初始化 DesignerTransaction 类的新实例。

属性

Canceled

获取一个值,该值指示是否已取消事务。

Committed

获取一个值,该值指示是否已提交事务。

Description

获取事务的说明。

方法

Cancel()

取消事务并尝试回滚由事务的事件作出的更改。

Commit()

提交此事务。

Dispose(Boolean)

释放由 DesignerTransaction 占用的非托管资源,还可以另外再释放托管资源。

Equals(Object)

确定指定对象是否等于当前对象。

(继承自 Object)
Finalize()

释放与此对象关联的资源。 如果此事务尚未提交,则此重写方法将提交此事务。

GetHashCode()

作为默认哈希函数。

(继承自 Object)
GetType()

获取当前实例的 Type

(继承自 Object)
MemberwiseClone()

创建当前 Object 的浅表副本。

(继承自 Object)
OnCancel()

引发 Cancel 事件。

OnCommit()

执行提交事务的实际工作。

ToString()

返回表示当前对象的字符串。

(继承自 Object)

显式接口实现

IDisposable.Dispose()

释放由 DesignerTransaction 使用的所有资源。

适用于

另请参阅