Friday, December 5, 2008

How to access file share on remote server

In my ASP.NET Application, I must access file share on a remote server by its UNC path, i.e., \\server\folder\subfolder\, using specific username and password.


using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.IO;

namespace RemoteCredentials
{
	class MainClass
	{
		[DllImport( "advapi32.dll", SetLastError = true )]
		private static extern bool LogonUser( string
			lpszUsername, string lpszDomain, string lpszPassword,
			int dwLogonType, int dwLogonProvider, ref IntPtr phToken );

		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		private unsafe static extern int FormatMessage(int
			dwFlags, ref IntPtr lpSource,
			int dwMessageId, int dwLanguageId, ref String lpBuffer, 
			int nSize, IntPtr *arguments);

		[DllImport( "kernel32.dll", CharSet = CharSet.Auto, 
			SetLastError = true )]
		private static extern bool CloseHandle( IntPtr handle);

		[DllImport("advapi32.dll", CharSet = CharSet.Auto, 
			SetLastError = true)]
		public extern static bool DuplicateToken( IntPtr
			existingTokenHandle,
			int SECURITY_IMPERSONATION_LEVEL, 
			ref IntPtr duplicateTokenHandle );


		// logon types
		const int LOGON32_LOGON_INTERACTIVE = 2;
		const int LOGON32_LOGON_NETWORK = 3;
		const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

		// logon providers
		const int LOGON32_PROVIDER_DEFAULT = 0;
		const int LOGON32_PROVIDER_WINNT50 = 3;
		const int LOGON32_PROVIDER_WINNT40 = 2;
		const int LOGON32_PROVIDER_WINNT35 = 1;

		/// 
		/// The main entry point for the application.
		/// 
		[STAThread]
		static void Main(string[] args)
		{
			IntPtr token = IntPtr.Zero;
			IntPtr dupToken = IntPtr.Zero;

			bool isSuccess = LogonUser( 
				"userId", "192.168.1.1", "password", 
				LOGON32_LOGON_NEW_CREDENTIALS,
				LOGON32_PROVIDER_DEFAULT, ref token );
			
			if( !isSuccess )
			{
				RaiseLastError();
			}

			isSuccess = DuplicateToken( token, 2, ref dupToken );
			
			if( !isSuccess )
			{
				RaiseLastError();
			}

			WindowsIdentity newIdentity = new WindowsIdentity( dupToken );
			
			WindowsImpersonationContext impersonatedUser 
				= newIdentity.Impersonate();

			DirectoryInfo dirInfo = new DirectoryInfo(
				@"\\192.19.12.46\sharedfolder" );
			FileInfo[] files = dirInfo.GetFiles();

			impersonatedUser.Undo();

			foreach( FileInfo file in files )
			{
				Console.WriteLine( file.FullName );
			}

			isSuccess = CloseHandle( token );
			if( !isSuccess )
			{
				RaiseLastError();
			}
		}

		// GetErrorMessage formats and returns an error message
		// corresponding to the input errorCode.
		public unsafe static string GetErrorMessage( int errorCode )
		{
			int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
			int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
			int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

			int messageSize = 255;
			string lpMsgBuf = "";
			int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER 
				| FORMAT_MESSAGE_FROM_SYSTEM 
				| FORMAT_MESSAGE_IGNORE_INSERTS;

			IntPtr ptrlpSource = IntPtr.Zero;
			IntPtr ptrArguments = IntPtr.Zero;

			int retVal = FormatMessage(
				dwFlags, ref ptrlpSource, errorCode, 0, 
				ref lpMsgBuf, messageSize, &ptrArguments);
			if( retVal == 0 )
			{
				throw new ApplicationException(
				string.Format( 
					"Failed to format message for error code '{0}'."
					, errorCode ) );
			}

			return lpMsgBuf;
		}

		private static void RaiseLastError()
		{
			int errorCode = Marshal.GetLastWin32Error();
			string errorMessage = GetErrorMessage(errorCode );

			throw new ApplicationException( errorMessage);
		}
	}
}

Tuesday, December 2, 2008

Đếm số dòng có trong một File

Đoạn code sau đưa ra cách để đếm số dòng trong một file. Nó sẽ đếm cả dòng cuối cùng của một file ngay cả khi dòng cuối cùng không phải là kết thúc của dòng mới.

Cách sử dụng:

C:/>CountLine CountLine.cs
lines = 50

Mã nguồn bằng C#:

namespace Sample
{
   static class LineCount
   {
       /// 
       /// The main entry point for the application.
       /// 
       [STAThread]
       static void Main(string[] args)
       {
           if (args.Length == 0)
               Console.WriteLine("Usage: LineCount File Name");
           else
           {
               string fileName = args[0];

               if (!File.Exists(fileName))
                   Console.WriteLine("File '{0} does not exist. Please try again.", fileName);
               else
               {
                   FileStream fileStream = File.OpenRead(fileName);
                  
                   int ch, prev = '\n' /* so empty files have no lines */, lines = 0;

                   while ( (ch = fileStream.ReadByte()) != -1) /* Read all chars in the file. */
                   {
                       if ( ch == '\n' )
                       {
                           ++lines; /* Bump the counter for every newline. */
                       }
                      
                       prev = ch; /* Keep a copy to later test whether... */
                   }
                  
                   fileStream.Close();
                  
                   if ( prev != '\n' ) /* ...the last line did not end in a newline. */
                   {
                       ++lines; /* If so, add one more to the total. */
                   }
                  
                   Console.WriteLine("lines = {0}", lines);
               }
           }
       }
   }
}

Sunday, November 30, 2008

Cách định dạng mã nguồn được đăng trên BLOGGER

Cách sử dụng trong bài viết này là sử dụng SyntaxHighlighter , nó là một thư viện nguồn mở viết bằng JavaScript .

Nó thực hiện đặt màu và phông chữ phù hợp với đoạn mã nguồn mà bạn trích dẫn bằng các câu lệnh JavaScript.

Tiếp theo là các bước để cài đặt:

1. Download các file thư viện cho SyntaxHighlighter và đưa lên vào host lưu trữ các file trong thư viện này, bạn có thể upload lên Google Code Page.

2. Đăng nhập vào BLOGGER, vào mục Layout –> Edit HTML. Tiếp theo copy đoạn code sau vào template:

</div></div> <!-- end outer-wrapper -->
<link href='http://[YOUR HOST]/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script src='http://[YOUR HOST]/shCore.js' type='text/javascript'/>

<script src='http://[YOUR HOST]/shBrushCpp.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushCSharp.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushCss.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushJava.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushJScript.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushSql.js' type='text/javascript'/>
<script src='http://[YOUR HOST]/shBrushXml.js' type='text/javascript'/>

<script class='javascript'>
//<![CDATA[
function FindTagsByName(container, name, Tag)
{
var elements = document.getElementsByTagName(Tag);
for (var i = 0; i < elements.length; i++)
{
if (elements[i].getAttribute("name") == name)
{
container.push(elements[i]);
}
}
}
var elements = [];
FindTagsByName(elements, "code", "pre");
FindTagsByName(elements, "code", "textarea");

for(var i=0; i < elements.length; i++) {
if(elements[i].nodeName.toUpperCase() == "TEXTAREA") {
var childNode = elements[i].childNodes[0];
var newNode = document.createTextNode(childNode.nodeValue.replace(/<br\s*\/?>/gi,'\n'));
elements[i].replaceChild(newNode, childNode);

}
else if(elements[i].nodeName.toUpperCase() == "PRE") {
brs = elements[i].getElementsByTagName("br");
for(var j = 0, brLength = brs.length; j < brLength; j++) {
var newNode = document.createTextNode("\n");
elements[i].replaceChild(newNode, brs[0]);
}
}
}
//clipboard does not work well, no line breaks
// dp.SyntaxHighlighter.ClipboardSwf =
//"http://[YOUR HOST]/clipboard.swf";
dp.SyntaxHighlighter.HighlightAll("code");
//]]>
</script>

</body>
</html>

3. Bây giờ bạn có thể trích dẫn các đoạn code bằng cách thêm thẻ “pre” hoặc “textarea”. Cách sử dụng cụ thể như sau:

... some code here ...

4. Các ngôn ngữ hổ trợ bao gồm:

C++: cpp, c, c++

C#: c#, c-sharp, csharp

CSS: css

Delphi: delphi, pascal

Java: java

Java Script: js, jscript, javascript

PHP: php

Python: pt, python

Ruby: rb, ruby, rails, ror

SQL: sql

VB: vb, vb.net

XML, HTML: xml, html, xhtml, xslt

Friday, November 28, 2008

How to create a partition for an existing table and index?

Take the following steps to create a partition for an existing table and index:

1. Create File Group:

To create a filegroup named 2003Q3 for the AdventureWorks database, use ALTER DATABASE:

ALTER DATABASE AdventureWorks ADD FILEGROUP [2003Q3]

Once a filegroup exists then you use ALTER DATABASE to add files to the filegroup.

ALTER DATABASE AdventureWorks
ADD FILE
	(NAME = N'2003Q3',
	FILENAME = N'C:\AdventureWorks\2003Q3.ndf',
	SIZE = 5MB,
	MAXSIZE = 100MB,
	FILEGROWTH = 5MB)
	TO FILEGROUP [2003Q3]

2. Create a partition function:

A partition function can be created by using the CREATE PARTITION FUNCTION STATEMENT. An example is given below:

CREATE PARTITION FUNCTION OrderDateRangePFN(datetime)
AS
RANGE LEFT FOR VALUES (
	'20000930 23:59:59.997',
	'20001231 23:59:59.997',
	'20010331 23:59:59.997',
	'20010630 23:59:59.997')

For RANGE LEFT

1st partition is all data <= '20000930 23:59:59.997’

2nd partition is all data >  '20000930 23:59:59.997’ and <= '20001231 23:59:59.997'

3rd partition is all data > '20001231 23:59:59.997' and <= '20010331 23:59:59.997'

4th partition is all data > '20010331 23:59:59.997' and <= '20010630 23:59:59.997'

5th partition is all data > '20010630 23:59:59.997'

For RANGGE RIGHT

1st partition is all data < '20000930 23:59:59.997’

2nd partition is all data >=  '20000930 23:59:59.997’ and < '20001231 23:59:59.997'

3rd partition is all data >= '20001231 23:59:59.997' and < '20010331 23:59:59.997'

4th partition is all data >= '20010331 23:59:59.997' and < '20010630 23:59:59.997'

5th partition is all data >= '20010630 23:59:59.997'

3. Create a partition scheme:

A partition scheme can be created by using the CREATE PARTITION SCHEME statement. An example is given below:

CREATE PARTITION SCHEME OrderDateRangePS
AS PARTITION OrderDateRangePFN
TO ([2000Q3], [2000Q4], [2001Q1], [2001Q2], [PRIMARY])

4. Drop the existing clustered index:

If in your table has clustered index (default for primary keys), you must drop it and recreate nonclustered index with primary keys of table. The clustered index can be dropped by using the DROP INDEX statement. The statement is as follows:

ALTER TABLE [dbo].[Orders] DROP CONSTRAINT [PK_Orders]

ALTER TABLE [dbo].[Orders] ADD CONSTRAINT [PK_Orders] PRIMARY KEY NONCLUSTERED 
(
	[OrderID] ASC
)

5. Create the clustered index on the partition scheme:

The index can be created on a partitioned scheme as follows:

CREATE CLUSTERED INDEX [PartitionIndex_on_OrderDateRangePS] ON [dbo].[Orders] 
(
	[OrderDate]
)
	WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) 
	ON [OrderDateRangePS]([OrderDate])
The table is automatically partitioned according to the partition scheme of the clustered index.
 

Thursday, November 27, 2008

Những bài học từ một dự án phần mềm

Đây là một câu chuyện có thật về một dự án phần mềm trải qua 4 năm và tiêu tốn 35 triệu USD mà không đem lại kết quả nào, và có kế hoạch kéo dài thêm ít nhất là 4 năm nữa.

Dự án này diễn ra tại một công ty sản xuất dụng cụ thể thao vào hàng đầu trên thế giới, doanh thu khoảng hơn chục tỷ USD một năm, có trụ sở tại Tây Bắc Mỹ, tạm gọi là công ty N.

Trên phương diện là một study case, đây là một dự án khá độc đáo, và có thể dùng làm bài học điển hình về nhiều khía cạnh khác nhau của một dự án phần mềm, nhất là dành cho các doanh nghiệp sản xuất, dịch vụ đang có ý định ứng dụng công nghệ thông tin vào quy trình sản xuất và hoạt động của mình. Bài viết này hướng tới các đối tượng là Giám đốc Công nghệ Thông tin của doanh nghiệp (CIO – Chief Information Technology Officer), Quản trị Dự án (Project Manager) và Kiến trúc sư phần mềm (Software Architect), và sẽ phân tích qua các khía cạnh sau đây của dự án: Quy trình Quản lý (Management Process), Quy trình phát triển phần mềm (Software Development Process)  và Kiến trúc phần mềm (Software Architecture).

Chi tiết...

(Trích từ hanoian.com)

Generics in .NET

There are language features that are nothing more than syntactical sugar. For example, C#'s coalesce operator (??) is a short-handed and specialized if-else. Object initializes make it easier to set properties on a newly created objects. Some features though go beyond mere convenience and add real value. I know it seems like we constantly have to learn new things, while at the same time actually produce code to pay our bills. It can be hard to pick and choose what to learn and what can wait. Let me be straight up though: if you haven't mastered generics yet, you're starting to fall dangerously behind.

Read more...

Wednesday, November 26, 2008

Cách phân trang dữ liệu trong SQL Server 2005

Khi tìm kiếm và hiển thị dữ liệu, việc phân trang dữ liệu kết quả tìm kiếm rất quan trọng, nhất là với lượng dữ liệu lớn. Trong SQL Server 2005 có hàm ROW_NUMBER cho phép bạn thực hiện phân trang các bản ghi nhận được.

Ví dụ sau sẽ minh họa cách thực hiện phân trang dữ liệu:

CREATE PROCEDURE dbo.spGetManyProducts 
	@ProducNo VARCHAR(13) = NULL,
	@PageIndex INT, 
	@PageSize INT 
AS 
BEGIN 

	WITH ProductRecords AS ( 
		SELECT ROW_NUMBER() OVER (ORDER BY ProductName) AS RowIndex, 
			ProductNo, ProductName, Description 
		FROM TbProducts
		WHERE (@ProductNo IS NULL OR ProductNo LIKE @ProductNo)
	) , GetTotalRowCount AS ( 
		SELECT MAX(RowIndex) AS TotalRowCount 
		FROM ProductRecords 
	) 
	SELECT ProductNo, ProductName, Description, TotalRowCount 
	FROM ProductRecords, GetTotalRowCount 
	WHERE (RowIndex BETWEEN (@PageIndex - 1) * @PageSize + 1 AND @PageIndex*@PageSize) 
END

Trong đoạn code TSQL ở trên còn cho phép bạn lấy về tổng số dòng dữ liệu có thể nhận được với mỗi kết quả tìm kiếm.

Đây là cách chỉ được sử dụng trên SQL Server 2005 hoặc mới hơn. Còn với SQL Server 2000, bạn có thể sử dụng bảng tạm để lấy toàn bộ kết quả tìm kiếm, sau đó lấy ra các dòng cần thiết với câu lệnh phù hợp. Tôi có 1 cách khác để phân trang trên SQL Server 2000 sẽ đưa ra trong một dịp khác.

Thursday, October 16, 2008

Sử dụng IMessageFilter để khóa các sự kiện

 

Khi bạn cần thực hiện các process cần nhiều thời gian, ví dụ như việc gọi đến một service trên Internet, thì ngoài việc hiển thị progress bar, bạn cần khóa không cho người sử dụng thao tác trên màn hình, gồm các sự kiện liên quan đến con chuột và bàn phím. Ví dụ sau đây sẽ sử dụng khả năng lọc các message mà Windows gửi đến ứng dụng để thực hiện yêu cầu trên.

Đầu tiên, bạn cần cài đặt các phương thức được đưa ra trong Interface IMessageFilter.

/// <summary>
/// Lớp cài đătn Interface để lọc các message mà Windows sẽ gửi đến ứng dụng
/// </summary>
public class FilterMessageSample : IMessageFilter
{
    public const int WM_MOUSEFIRST = 0x0200,//Message bắt đầu có sự kiện chuột
                     WM_MOUSELAST = 0x020A,//Message kết thúc có sự kiện chuột
                     WM_KEYFIRST = 0x0100,//Message bắt đầu có sư kiện phím
                     WM_KEYLAST = 0x0108;//Message kết thúc có sự kiện phím
 
    /// <summary>
    /// Cài đặt phương thức lọc message của IMessageFilter
    /// </summary>
    /// <param name="m"></param>
    /// <returns></returns>
    public bool PreFilterMessage(ref Message m)
    {
        //Nếu các message nằm trong khoảng message có chứa sự kiện
        //bàn phím hoặc chuột
        if (m.Msg >= WM_MOUSEFIRST || m.Msg <= WM_MOUSELAST 
            || m.Msg >= WM_KEYFIRST || m.Msg <= WM_KEYLAST)
        {
            return true;//Không gửi message đến ứng dụng
        }
 
        return false;
    }
}

Cuối cùng, khi bạn muốn khóa ứng dụng hay hủy bỏ khóa, bạn hãy cài đặt đoạn code sau:

//Tạo một instance thực hiện filter các sự kiện bàn phím và chuột
FilterMessageSample filterMessageSample = new FilterMessageSample();
...
//Khi bạn thực hiện khóa các sự kiện với ứng dụng
Application.AddMessageFilter(filterMessageSample);
...
//Và khi bạn muốn ứng dụng trở lại hoạt động bình thường
Application.RemoveMessageFilter(filterMessageSample);

Ngoài ví dụ đơn giản trên, bạn còn có thể sử dụng khả năng của IMessageFilter để bắt toàn bộ các message trước khi nó được gửi đến chương trình.

Saturday, September 20, 2008

Cách thiết lập sẳn sàng nhập tiếng Nhật cho IME control

Với các ứng dụng dành cho người Nhật, một yêu cầu tất yếu trên Microsoft Windows là bạn phải thiết lập ngầm định nhập chữ Hiragana cho IME control. Đoạn code sau đây sẽ thực hiện yêu cầu này.

using System.Runtime.InteropServices;
...
[DllImport("user32.dll")]
private static extern long LoadKeyboardLayout(string language, uint flag);
...
LoadKeyboardLayout("00000411", 1);

Thursday, August 21, 2008

Phân biệt chữ hoa và chữ thường trong SQL Server 2000

Ngầm định cài đặt của SQL Server không phân biệt chữ hoa và chữ thường, nghĩa là HELLO sẽ giống với hello.

Để buộc SQL Server phân biệt chữ hoa chữ thường trong tìm kiếm, chúng ta sẽ sử dụng chức năng tìm kiếm và so sánh (collate).

CREATE procedure sp_AuthenticateUser
    @username varchar(200),
    @password varchar(50)
   As
BEGIN TRANSACTION
    IF EXISTS (SELECT 1 FROM dbo.TableName WHERE username = @username COLLATE SQL_Latin1_General_CP1_CS_AS 
        AND Password = @ password COLLATE SQL_Latin1_General_CP1_CS_AS)
        BEGIN
            Print 'Success'
            // Do your database queries here
        END
    ELSE
        BEGIN
            Print 'Unsuccessful'
        END
 
        IF @@Error <>0
            BEGIN
                ROLLBACK TRANSACTION
                RETURN (1)
            END
        ELSE
            BEGIN
                COMMIT TRANSACTION
                RETURN (0)    
            END
GO

Saturday, July 19, 2008

Velocity: Microsoft's Distributed In-Memory Cache

Distributed in-memory caches have been rather popular over the last few years in everything from mainstream Java applications to the fringe languages like Erlang. Continuing its rather frantic efforts to catch up with technologies predominately found in the open source world, Microsoft has introduced its own distributed cache.

Velocity is a distributed cache designed specifically for the .NET platform. Many of the features will be recognizable to those familiar with other distributed in-memory caches. It is currently available as a community tech preview.

There are two types of clients for Velocity. Simple clients only know about a single cache server. If the requested object is not available on that cache server, the cache server will fetch it from the appropriate server. Routing clients are much more involved. They always know where a particular object lives so they can query that cache server directly. The performance impact of sending all of the cache location data to a routing client hasn't been discussed. In addition to the cache servers, both types of clients support a local cache option. This still requires checking the server for stale data, but should reduce network traffic when dealing with large cache objects.

For concurrency two options exist. With optimistic concurrency, the first update wins and any further updates to the now stale object will fail. With pessimistic locking, a lock handle is returned. Until unlocked, or the timeout expires, all attempts to gain a lock will fail. Failure to obtain a lock is a non-blocking operation.

Objects can be removed from the cache explicitly, via a expiration date, or whenever memory pressure is exceeded. This last method, known as eviction, uses a least recently used algorithm.

In addition to a key, objects may have a collection of tags associated with them. There are methods to retrieve one or all objects that match a list of tags.

http://www.infoq.com/news/2008/06/Velocity;jsessionid=1A186B573B980B4638C65CDEDF143B60

Wednesday, July 16, 2008

Cách tạo shortcut trên Desktop cho ứng dụng được triển khai bằng ClickOnce

Khi thực hiện triển khai ứng dụng bằng ClickOnce, nó chỉ tạo ra shortcut trên All Programs menu với đường dẫn là <CompanyName>/<ProductName>, trong đó <CompanyName> và <ProductName> đã được đăng ký trong Assembly của ứng dụng. Đoạn code sau đây sẽ thực hiện việc tự động copy shortcut từ trên menu Programs vào Desktop. Bạn nên đưa phương thức này vào Form Main của ứng dụng.

//    Khi đưa vào chương trình nên chú ý kiểm tra xem bạn có đang debug trên Visual Studio hay không?
//    #if (!debug)
//        CheckForShortcut();
//    #endif
 
//Namespace Referrence
// using System.Deployment.Application;
// using System.Reflection;
 
void CheckForShortcut()
{
    ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
 
    if (ad.IsFirstRun)
    {
        Assembly code = Assembly.GetExecutingAssembly();
 
        string company = string.Empty;
        string productName = string.Empty;
 
        if (Attribute.IsDefined(code, typeof(AssemblyCompanyAttribute)))
        {
            AssemblyCompanyAttribute ascompany = (AssemblyCompanyAttribute)Attribute.GetCustomAttribute(
                code, typeof(AssemblyCompanyAttribute));
 
            company = ascompany.Company;
        }
 
        if (Attribute.IsDefined(code, typeof(AssemblyProductAttribute)))
        {
 
            AssemblyProductAttribute asProductName = (AssemblyProductAttribute)Attribute.GetCustomAttribute(
                code, typeof(AssemblyProductAttribute));
 
            productName = asProductName.Product;
        }
 
        if (company != string.Empty && productName != string.Empty)
        {
 
            string desktopPath = string.Empty;
 
            desktopPath = string.Concat(Environment.GetFolderPath(
                Environment.SpecialFolder.Desktop), "\\", productName, ".appref-ms");
 
            string shortcutName = string.Empty;
 
            shortcutName = string.Concat(
                Environment.GetFolderPath(Environment.SpecialFolder.Programs),
                "\\", company, "\\", productName, ".appref-ms");
 
            System.IO.File.Copy(shortcutName, desktopPath, true);
        }
    }
}

Tuesday, July 8, 2008

Tài liệu tham khảo nhanh dành cho .NET Developer

    Cách thiết lập focus cho một control khác sau khi sử lý sự kiện AfterSelect của TreeView

    TreeView control có thể gây cho bạn khó khăn trong trường hợp này, nó cập nhật lại Node được lựa chọn và thực hiện focus trở lại Node này sau khi xử lý sự kiện. Cách thực hiện cho trường hợp này là làm trễ việc thực thi đoạn code của bạn cho đến khi hoàn thành việc xử lý sự kiện trên control TreeView. Dưới đây là sample cho việc xử lý trường hợp này:

    private delegate void FocusAfterSelect(TreeNode node);
     
    private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) 
    {
        this.BeginInvoke(new FocusAfterSelect(HandleAfterSelect), e.Node);
    }
     
    private void HandleAfterSelect(TreeNode node) 
    {
        textBox1.Text = node.Text;
        textBox1.Focus();
    }

    Monday, July 7, 2008

    Truy cập các phương thức private sử dụng Reflection trong .NET.

    Để truy cập vào các phương thức hoặc thuộc tính private của một lớp, ta sẽ sử dụng gói Reflection được xây dựng bên trong .NET Framework. Để minh họa cho khả năng của của Reflection trong .NET Framework, tôi xin đưa ra một ví dụ bên dưới:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Reflection;
     
    namespace ReflectionSamples
    {
        public class ReflectionSample
        {
            private void Method1()
            {
                Console.WriteLine("Method 1 called");
            }
            
            private int Method2(int x, int y)
            {
                Console.WriteLine("Method 2 called {0}, {1}", x, y);
                return x*y;
            }
            
            internal string RedAlert
            {
                get
                {
                    Console.WriteLine("Red Alert");
                    return "Red Alert";
                }
            }
        }
        
        internal class Program
        {
            private static void Main(string[] args)
            {
                //Tạo instance của lớp mà ta sẽ thực hiện truy cập các hàm private
                MyClass instance = new MyClass();
                
                //Get Type of class
                Type t = typeof (MyClass);
                
                //Lấy thông tin của phương thức Method1
                MethodInfo method1 = t.GetMethod("Method1",
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
     
                //Gọi phương thức trên đối tượng được tham chiếu bằng instance và truyền tham số
                method1.Invoke(instance, null);
                
                //Truy cập thông tin của Properties
                PropertyInfo property = t.GetProperty("RedAlert", 
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty);
                
                //Gọi Properties tương ứng và truyền tham số
                string str = (string)property.GetValue(instance, null);
                
                //Truy cập thông tin của phương thức Method2
                MethodInfo method2 = t.GetMethod("Method2", 
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
     
                //Gọi phương thức và truyền 2 tham số (các tham số được truyền thông qua danh sách đối tượng
                object o = method2.Invoke(instance, new object[] {2, 3});
                
                //Với trường hợp phương thức có giá trị trả lại
                if (o != null)
                {
                    Console.WriteLine("Method 2 returned: " + o.ToString());
                }
                
                Console.ReadKey();
            }
        }
    }