Wednesday, January 30, 2008

Delegate.Invoke VS Control.Invoke(ZT)

 

Return          Work Thread
Control.Invoke                  完成工作        强制於 UI Thread
Control.BeginInvoke             立即            强制於 UI Thread
[delegate].Invoke               完成工作        Call Invoke 的 Thread
[delegate].BeginInvoke          立即            新的背景 Thread
-------------------------------------------------------------------------
1、Button = button1
2、TextBox = textBox1 (请设 multiline)
然後把 button1 的 OnClick 连到下面 source code 里的 button1_Click
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        public delegate void testDelegate(string text);
        public Form1()
        {
            InitializeComponent();
        }
        private void UpdateTextBox(string text)
        {
            textBox1.Text += string.Format("{0}{1}", text, Environment.NewLine);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            testDelegate t = new testDelegate(UpdateTextBox);
            this.Invoke(t, "Control.Invoke");
            this.BeginInvoke(t, "Control.BeginInvoke");
            t.Invoke("[delegate].Invoke");
            // 建议先 comment 掉下面这行跑一次,再拿掉 comment 跑一次
            // 下面这行就是所谓的 [delegate].BeginInvoke
            // 但是当你 call 了之後,在 UpdateTextBox 里会出现 exception
            // 因为它使用新的背景 thread 来跑这个工作
            // 但是 Form 不允许由别的 thread 来 access Form 上的任何 control
            // t.BeginInvoke("[delegate].BeginInvoke", null, null);
        }
    }
}

Delegate.Invoke
Delegate.Invoke is used to execute a delegate on the current thread. A delegate is just a reference to a function or method, and Delegate.Invoke is the mechanism to call this function or method (similar to a normal function call).
Delegate.BeginInvoke
Delegate.BeginInvoke is used to execute a delegate asynchronously, that is, on a separate thread. That means that you can start an operation which won't block your current thread, it will be executed on it's own thread. Delegate.BeginInvoke the operation will be performed "in the background", that is, on a separate thread. Note that you need to call EndInvoke at some time after BeginInvoke to avoid resource leaks.
As its a seperate thread you must not update any property or call any method of a Windows Forms user that potentially update the UI. If you want to update a progress bar, fill a list, or do somehting similar while the operation is performed, you have to use a different mechanism: Control.Invoke or Control.BeginInvoke.
Control.Invoke
Control.Invoke is used to execute a delegate on the UI thread of that control. If you have a delegate which updates the user interface, you can call Control.Invoke from your other thread to execute the update operation on the UI thread.
Control.BeginInvoke
Control.BeginInvoke does the same, but in an asynchronous way. This means that, while Control.Invoke waits until the UI thread has finished executing the delegate, Control.BeginInvoke returns immediately.
Notes to remember:
Control.Invoke, Control.BeginInvoke, and Control.InvokeRequired are exceptions and can use these from other threads than the UI thread.

Monday, January 14, 2008

IDispose Sample (ZT)

using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
...{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
...{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;

// The class constructor.
public MyResource(IntPtr handle)
...{
this.handle = handle;
}

// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
...{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
...{
// Check to see if Dispose has already been called.
if(!this.disposed)
...{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
...{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
}
disposed = true;
}

// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);

// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
...{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
...{
// Insert code here to create
// and use the MyResource object.
}
}