블로그 이미지
Sunny's

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2009. 9. 2. 18:46 .NET Framework

Summary

This article will show you how to safely get data into a WinGrid using the Background Worker component found in .NET 2.0

Additional Information

Many times an application will need to perform many actions that consume some time before they complete. During this time while the actions are being performed, the user interface becomes what appears to be “frozen” until the actions are complete. Some examples of actions that are performed are fetching data from a database or perhaps a long complex loop to do something. Any of these lengthy processes degrade our application user’s experience and can make a good application hard and frustrating to use. This article will show how we can leverage the really great new Background Worker component to fetch new Customer objects and pass them to the WinGrid. After reading this article please download the included sample that is available in both C# and VB.NET.

Step-By-Step Example

First things first, the new Background Worker component given to us in Visual Studio 2005 / .NET 2.0 wraps up patterns and functionality that we would have otherwise coded ourselves just as we always have back in Visual Studio 200X / .NET 1.X. This component makes the creation of an async process as well as its handling very simple through the three events that fire as well as some simple properties and methods that we use.

In this example, we have a use case where the application loads up and we have a WinGrid bound to an empty collection of Customer objects. Note: the CustomerCollection is simply an implementation of BindingList of type Customer (a custom business object in this project). When we press the “Get Data” button, we are fetching new Customer objects from somewhere, in another thread and then adding them to the WinGrid. We are also updating the user interface (through the UltraProgressBar) to let the users know how much longer there is to go before the process is complete. We can also allow the users to cancel the operation if it is taking too long and they want to go to lunch.

The code to accomplish this is quite simple. To start off, we simply drag and drop an instance of the Background Worker component (located in the “Components” toolbox tab in Visual Studio 2005) and add the event handlers for “DoWork”, “ProgressChanged” and “RunWorkerCompleted”.

Now all that is left for us to do is to fill these event handlers with code to get these customers, update the elements on the user interface and close and clean things up.

Getting the Data:

On the Click event handler of the button we will start this process as follows:

C#
        private void btnGetData_Click(object sender, EventArgs e)
        {
            this.btnGetData.Enabled = false;
            this.lblMessage.Text = "Getting Records, Please Wait...";

            this.bgwData.RunWorkerAsync();
        }

VB.NET

    Private Sub btnGetData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetData.Click
        Me.btnGetData.Enabled = False
        Me.lblMessage.Text = "Getting Records, Please Wait..."

        Me.bgwData.RunWorkerAsync()
    End Sub

Now that we have invoked the process through the “RunWorkerAsync( )” method, we need to handle the “DoWork” event of the Background Worker:

C#

        private void bgwData_DoWork(object sender, DoWorkEventArgs e)
        {
            //This is a new instance of a Customers collection that
            //may have been fetched from a DB or wherever.
            CustomerCollection newCustomers = new CustomerCollection();

            //This simulates the known number of objects that
            //were (or are about to be) returned
            int returnedRecordCount = 100;

            //Here we loop through and add a new instance of
            //a customer object to the collection and each iteration
            //we check to see if someone cancelled the operation
            for (int i = 1; i <= returnedRecordCount ; i++)
            {
                if (this.bgwData.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                Customer theCustomer = new Customer(DateTime.Now.Ticks, Guid.NewGuid().ToString());
                
                newCustomers.Add(theCustomer);

                //Here is where we use this method to pass back
                //information to the UI Thread. Notice how we
                //pass the current progress (limited from 0 to 100)
                //as well as the actual customer object.
                this.bgwData.ReportProgress(i, theCustomer);

                System.Threading.Thread.Sleep(20);
            }
        }

VB.NET

Private Sub bgwData_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwData.DoWork

        'This is a new instance of a Customers collection that
        'may have been fetched from a DB or wherever.
        Dim newCustomers As CustomerCollection = New CustomerCollection()

        'This simulates the known number of objects that
        'were (or are about to be) returned
        Dim returnedRecordCount As Integer = 100


        'Here we loop through and add a new instance of
        'a customer object to the collection and each iteration
        'we check to see if someone cancelled the operation
        For i As Integer = 1 To returnedRecordCount

            If Me.bgwData.CancellationPending Then
                e.Cancel = True
                Return
            End If

            Dim theCustomer As Customer = New Customer(DateTime.Now.Ticks, Guid.NewGuid().ToString())

            newCustomers.Add(theCustomer)

            'Here is where we use this method to pass back
            'information to the UI Thread. Notice how we
            'pass the current progress (limited from 0 to 100)
            'as well as the actual customer object.
            Me.bgwData.ReportProgress(i, theCustomer)

            System.Threading.Thread.Sleep(20)

        Next


    End Sub

The great thing about how this works is that the Background Worker component has the “ReportProgress( )” method which allows us to pass a number between 0 and 100 so that a status bar can be updated easily. Even more important, we can also pass objects so that we can safely get our object instances back to the User Interface thread and do with it as we please. In this case, with each loop iteration, we pass through a Customer object.

..Continued

Samples

wingrid_background_worker.zip
 Sample Application for Background Worker Component and WinGrid

참조 : http://devcenter.infragistics.com/Support/KnowledgeBaseArticle.Aspx?ArticleID=9838
posted by Sunny's
2009. 8. 25. 10:24 .NET Framework

For Click-once deployment

After adding the isl file - "AppStyleGlow.isl" as "Existing Item" from solution bar.

Right click on the properties and set

Build Action = Content

Copy to Output directory = Copy if newer

and then add the following line in form load.

     Infragistics.Win.AppStyling.StyleManager.Load(CurDir() & "\AppStyleGlow.isl")

This should work...

참조 : http://forums.infragistics.com/forums/t/19745.aspx

posted by Sunny's
2009. 8. 18. 16:40 .NET Framework

우리는 늘 Winform 아니면 WPF 중에서 링크 혹은 버튼을 클릭하는 것 만나 어떤 지정의 사이트주소를 열 수 있고, 컴퓨터를 켜야 한 가운데의 어떤 지정의 하드디스크의 파티션 및 파일, 심지어 "제어판"이 관련된 물건이며, 그렇게 어떻게 합니까?

답안이 사용이었다System.Diagnostics.Process.Start().그것의 작용은 외부를 전용한 명령이었다.

먼저 와서 그것의 물자조달의 방법을 본다 :
Process.Start ()
Process.Start (ProcessStartInfo)
Process.Start (String)
Process.Start (String, String)
Process.Start (String, String, SecureString, String)
Process.Start (String, String, String, SecureString, String)

예를 들면:
C# Code:
 System.Diagnostics.Process   ie   =   new   System.Diagnostics.Process();  
  ie.StartInfo.FileName   =   "IEXPLORE.EXE";  
  ie.StartInfo.Arguments   =   @"http://www.brawdraw.com";
  ie.Start();  

간결한 물자조달의 방식 :
System.Diagnostics.Process.Start("http://www.brawdraw.com");

당연하다, 당신이 또한 기타 브라우저를 사용할 수 있다, 만약 여행을 유지하고 그러나 IE에 아니다 :
            string mathonPath = @"C:\Program   Files\Maxthon\\Maxthon.exe";
            System.Diagnostics.Process p = new System.Diagnostics.Process();
           //프로그램명을 설정한다
            p.StartInfo.FileName = mathonPath;
            p.StartInfo.Arguments = @"c:\";
            p.Start();

당신은 만약 탐색기로 C를 열고 싶으면 :\ ,그렇게 이렇게 할 수 있다 :
System.Diagnostics.Process.Start("explorer.exe", @"c:\");

더욱 사람이 아마도 물을 수 있을 것이다 :“나는 “절차를 첨가하고 혹은 삭제하여” 글자판 혹은 제어판 관련 내용을 열어야 한다, 좋다 ?”답안은 확실한 것이었다 !

한다 ?답안은 rundll32.exe를 전용한 것이었다,예를 들면:
“절차를 첨가하고 혹은 삭제하여” 글자판을 연다 :
System.Diagnostics.Process.Start("rundll32.exe", @"shell32.dll,Control_RunDLL appwiz.cpl,,1");
그 중에 뒤쪽" shell32.dll, Control RunDLL appwiz.cpl, 1" 명령을 전용하여 필요로 한 매개 변수

여기가 설명한다, 이것은 Delphi 중에서 사용하는 것에 유사하다 :
ShellExecute(Handle,'open','rundll32.exe','shell32.dll,Control_RunDLL   sysdm.cpl',nil,SW_SHOW);
WinExec('rundll32.exe   shell32.dll,Control_RunDLL   sysdm.cpl',SW_SHOW);

rundll32.exe 용도에 관해

--------------------------------------------------------------------------------

명령이 나열된다 :rundll32.exe user.exe,restartwindows
기능: 시스템 재가동

명령이 나열된다 :rundll32.exe user.exe,exitwindows
기능: 시스템의 닫는다

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL
기능: 제어판을 나타낸다

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL access.cpl,,1
기능: 나타내 “제어판 -보조적인 옵션 -키보드 ”옵션 윈도우

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL access.cpl,,2
기능: 나타내 “제어판 -보조적인 옵션 -보이스”옵션 윈도우

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL access.cpl,,3
기능: 나타내 “제어판 -보조적인 옵션 -나타내” 옵션의 윈도우

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL access.cpl,,4
기능: 나타내 “제어판 -보조적인 옵션 -마우스 ”옵션 윈도우

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL access.cpl,,5
기능: 나타내 “제어판 -보조적인 옵션 -전통 ”옵션 윈도우

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl @1
기능: 집행하여 “제어판 -새 하드웨어를 첨가하여” 길을 안내한다.

명령이 나열된다 : rundll32.exe shell32.dll,SHHelpShortcuts_RunDLL AddPrinter
기능: 집행하여 “제어판 -신 프린터기를 첨가하여” 길을 안내한다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,1
기능: 나타내 “제어판 -첨가/ 삭제의 격식 -설치 /사재하여” 글자판.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,2
기능: 나타내 “제어판 -첨가/ 삭제의 격식 -Windows를 설치하여” 글자판.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,3
기능: 나타내 “제어판 -첨가/ 삭제의 격식 -시동판 ”스킨.

명령이 나열된다 : rundll32.exe syncui.dll,Briefcase_Create
기능: 바탕화면 상에 1개의 새로운 “나의 서류 가방”을 세운다.

명령이 나열된다 : rundll32.exe diskcopy.dll,DiskCopyRunDll
기능: 연 앨범의 윈도우를 복제하는 것 나타낸다

명령이 나열된다 : rundll32.exe apwiz.cpl,NewLinkHere%1
기능: “빨리가기를 세워” 대화상자를 나타낸다, 세운 빨리가기의 위치에서 지나간다 %1 매개 변수가 결정한다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL timedate.cpl,,0
기능: “날짜와 시간”의 옵션의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL timedate.cpl,,1
기능: “표준 시각대”의 옵션의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe rnaui.dll,RnaDial [어떤 전화하여 연결한 이름]
기능: 어떤 전화하여 연결한 다이얼업의 윈도우를 나타낸다. 이미 전화하이게 만약 연결하면, 곧 현재 연결의 상태의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe rnaui.dll,RnaWizard
기능: “전화를 연결하는 것 새로 세운” 안내의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0
기능: 나타내 “디스플레이 특징 -배경”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,1
기능: 나타내 “디스플레이 특징 -개똥벌레의 모니터의 보호” 옵션의 윈도우.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2
기능: 나타내 “디스플레이 특징 -외관 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3
기능: 표시를 나타내 “디스플레이 특징 -속성 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,SHHelpShortcuts_RunDLL FontsFolder
기능: Windows의 “글자체”의 문서가 끼우는 것 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @3
기능: 마찬가지로 Windows의 “글자체”의 문서가 끼우는 것 나타낸 것이었다.

명령이 나열된다 : rundll32.exe shell32.dll,SHFormatDrive
기능: 모식화의 연 앨범의 대화상자를 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL joy.cpl,,0
기능: 나타내 “제어판 -오락 제어기-일반적으로” 옵션의 윈도우.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL joy.cpl,,1
기능: 나타내 “제어판 -오락 제어기-층계에 들어와” 옵션의 윈도우.

명령이 나열된다 : rundll32.exe mshtml.dll,PrintHTML (HTML문서 )
기능: HTML 문서를 인쇄한다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mlcfg32.cpl
기능: Microsoft Exchange의 일반적인 옵션의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @0
기능: 나타내 “제어판 -마우스 ” 옵션 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @1
기능: 나타내 “제어판 -키보드 속성-속도 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @1,,1
기능: 나타내 “제어판 -키보드 속성-언어”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @2
기능: Windows의 “프린터기”의 문서가 끼우는 것 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @3
기능: Windows의 “글자체”의 문서가 끼우는 것 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL main.cpl @4
기능: 나타내 “제어판 -입력 방법 속성-입력 방법 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL modem.cpl,,add
기능: “첨가의 새 모뎀”의 안내를 집행한다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,0
기능: 나타내 “제어판 -멀티미디어속성-오디오” 속성의 페이지.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,1
기능: 나타내 “제어판 -멀티미디어속성-비디오” 속성의 페이지.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,2
기능: 나타내 “제어판 -멀티미디어속성-MIDI” 속성의 페이지.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,3
기능: 나타내 “제어판 -멀티미디어속성-CD 음악” 속성의 페이지.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,4
기능: 나타내 “제어판 -멀티미디어속성-설비” 속성의 페이지.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl @1
기능: 나타내 “제어판 -보이스”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL netcpl.cpl
기능: 나타내 “제어판 -네트워크 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL odbccp32.cpl
기능: ODBC32 자료 관리의 옵션의 윈도우를 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,OpenAs_RunDLL {drive:\path\filename}
기능: 문서(drive: \path\filename)를 지정한 “열기 방식”의 대화상자를 나타낸다 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL password.cpl
기능: 나타내 “제어판 -패스워드”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL powercfg.cpl
기능: 나타내 “제어판 -전원 관리 속성 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,SHHelpShortcuts_RunDLL PrintersFolder
기능: Windows의 “프린터기”의 문서가 끼우는 것 나타낸다. (동rundll32.exe shell32.dll,Control_RunDLL main.cpl @2)

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,0
기능: 나타내 “제어판 -지역에 속성을 설치한다 -지역의 설치” 옵션의 윈도우.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,1
기능: 나타내 “제어판 -지역에 속성을 설치한다 -디지털”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,2
기능: 나타내 “제어판 -지역에 속성을 설치한다 -화폐 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,3
기능: 나타내 “제어판 -지역에 속성을 설치한다 -시간”옵션 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,4
기능: 나타내 “제어판 -지역에 속성을 설치한다 -날짜 ”옵션 윈도우 .

명령이 나열된다 : rundll32.exe desk.cpl,InstallScreenSaver [개똥벌레의 모니터의 보호의 문서의 이름]
기능: 지정의 개똥벌레의 모니터를 보호의 문서는 Windows의 화면모음으로 설치한다, 그리고 개똥벌레의 모니터가 속성의 윈도우를 보호하는 것 나타낸다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,0
기능: 나타내 “제어판 -시스템속성-전통 ”속성 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,1
기능: 나타내 “제어판 -시스템속성-설비 관리기기 ”속성 윈도우 .

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,2
기능: 나타내 “제어판 -시스템속성-하드웨어의 배치의 문서” 속성의 윈도우.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,3
기능: 나타내 “제어판 -시스템속성-성능 ”속성 윈도우 .

명령이 나열된다 : rundll32.exe user.exe,restartwindows
기능: 강제로 모든 격식의 닫고 그리고 기계를 재가동한다.

명령이 나열된다 : rundll32.exe user.exe,exitwindows
기능: 강제로 모든 격식의 닫고 그리고 전원을 끈다.

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL telephon.cpl
기능: “다이얼업의 속성”의 옵션의 윈도우를 나타낸다

명령이 나열된다 : rundll32.exe shell32.dll,Control_RunDLL themes.cpl
기능: “바탕화면 요지”의 옵션 글자판을 나타낸다

사이트소개"rundll32.exe의 용도 " 인용은 자연스럽게 아래와 같아 링크한다 :
http://www.mywd.cn/diannaozhishi/jinchengzhishi/20070208/1075.html

,당신은 1을 들어 3을 돌아갈 수 있다, 당신은 만약 명령식으로 방식을 생각하여 어떤 문서를 열면, 당신이 사용할 수 있다 :Process.Start (String, String) 방식.

기타 내가 더 이상 군말을 하지 않는다, Process.Start에게 (), 청하여 MSDN을 상세히 보아 문서를 돕는다.
http://msdn2.microsoft.com/en-us/library/system.diagnostics.process.start.aspx(영어)
http://msdn2.microsoft.com/zh-cn/library/system.diagnostics.process.start(VS.80).aspx(중국어)


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/johnsuna/archive/2008/01/18/2051742.aspx


posted by Sunny's
2009. 8. 14. 20:56 .NET Framework


  
        public enum RichTextBoxCommand
        {
            AppendText,
            ScrollToCaret
        }

        public delegate void DelegateRichTextBox(RichTextBox rebTextBox, RichTextBoxCommand command, String sAppendText);
        public DelegateRichTextBox dgRichText;

        public void SetRichTextBox(RichTextBox rebTextBox, RichTextBoxCommand command, String sAppendText)
        {
            switch (command)
            {
                case RichTextBoxCommand.AppendText:
                    rebTextBox.AppendText(sAppendText);
                    break;
                case RichTextBoxCommand.ScrollToCaret:
                    rebTextBox.ScrollToCaret();
                    break;
                default:
                    break;
            }

            rebTextBox.ScrollToCaret();
        }


        public void MoveTextBoxScroll()
        {

            txtChatBox.ScrollToCaret();
        }

        public enum ListBoxCommand
        {
            Add,
            AddRange,
            Remove,
            Clear
        }

        public delegate void DelegateListItem(ListBox lstListBox, ListBoxCommand command, String sItem, String[] arrItems);
        public DelegateListItem ListItemDelegate;

        public void SetListBox(ListBox lstListBox, ListBoxCommand command, String sItem, String[] arrItems)
        {
            switch (command)
            {
                case ListBoxCommand.Add:
                    lstListBox.Items.Add(sItem);
                    break;
                case ListBoxCommand.AddRange:
                    lstListBox.Items.Clear();
                    lstListBox.Items.AddRange(arrItems);
                    lstListBox.Items.RemoveAt(lstListBox.Items.Count - 1);
                    break;
                case ListBoxCommand.Remove:
                    lstListBox.Items.Remove(sItem);
                    break;
                case ListBoxCommand.Clear:
                    lstListBox.Items.Clear();
                    break;
                default:
                    break;
            }
           
        }

posted by Sunny's
2009. 8. 11. 13:20 .NET Framework

Introduction

In the previous article, I discussed a chat application using TCP sockets. In this part, I will show how to do it using UDP sockets.

Differences between UDP and TCP

TCP is connection oriented, and provides error and flow control. UDP provides no such services, and relies on the application layer for them. UDP allows sending a packet with or without checksum; no connection is maintained, so each packet is sent independently. If a packet gets lost or the packets arrive out of order, then the application should detect and remedy the situation on its own. Also, UDP doesn�t give the security features of TCP like the three-way handshake.

So what is in UDP that TCP doesn�t do? Firstly, UDP supports multicast � sending a single packet to multiple machines. This is useful as it saves bandwidth, each packet is transmitted only once and the entire network receives it. UDP is also used in places where the overhead (delay) involved with TCP is expensive.

Some applications of UDP are in VoIP, streaming of audio and video, DNS, TFTP, SNMP, online gaming, and etcetera.

Asynchronous UDP sockets

Asynchronous UDP sockets have a Begin and End appended to the standard socket functions, like BeginSendTo, BeginReceiveFrom, EndSendTo, and EndReceiveFrom. Let's take a look at one of them:

Collapse Copy Code
IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size,
 SocketFlags sockflag, ref EndPoint ep, AsyncCallback callback, object state)

The BeginReceiveFrom() method accepts data from any remote host on a connectionless socket. Notice that the BeginReceiveFrom() method is similar to the BeginReceive() method, except that it specifies a reference to an EndPoint object. The EndPoint object defines the remote host IP address and the port number that sent the data.

The AsyncCallback function is called when the function completes. Just as events can trigger delegates, .NET also provides a way for methods to trigger delegates. The .NET AsyncCallback class allows methods to start an asynchronous function and supply a delegate method to call when the asynchronous function completes.

The state object is used to pass information between the BeginAccept and the corresponding AsyncCallback function.

A sample BeginReceiveFrom() method would look like this:

Collapse Copy Code
sock.BeginReceive(data, 0, data.Length, SocketFlags.None, 
                  ref iep, new AsyncCallback(ReceiveData), sock);

The corresponding EndReceiveFrom() method is placed in the appropriate AsyncCallback method:

Collapse Copy Code
void ReceiveData(IasyncResult iar)
{
    Socket remote = (Socket)iar.AsyncState;
    int recv = remote.EndReceiveFrom(iar);
    string stringData = Encoding.ASCII.GetString(data, 0, recv);
    Console.WriteLine(stringData);
}

The EndReceiveFrom() method returns the number of bytes read from the socket, and places the received data in the data buffer defined in the BeginReceiveFrom() method. To access this data, the data buffer should be accessible from both the methods.

Getting Started

The architecture of the application using TCP sockets and the one using UDP sockets is very similar. Both applications use the same data structures to communicate between the server and the client.

For exchange of messages between the client and the server, both of them use the following trivial commands:

Collapse Copy Code
//The commands for interaction between 
//the server and the client
enum Command
{
  //Log into the server
    Login,      
  //Logout of the server
    Logout,
  //Send a text message to all the chat clients     
    Message,    
  //Get a list of users in the chat room from the server
    List
}

The data structure used to exchange between the client and the server is shown below. Sockets transmit and receive data as an array of bytes, the overloaded constructor and the ToByte member function performs this conversion.

Collapse Copy Code
//The data structure by which the server 
//and the client interact with each other
class Data
{
    //Default constructor
    public Data()
    {
        this.cmdCommand = Command.Null;
        this.strMessage = null;
        this.strName = null;
    }

    //Converts the bytes into an object of type Data
    public Data(byte[] data)
    {
        //The first four bytes are for the Command
        this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

        //The next four store the length of the name
        int nameLen = BitConverter.ToInt32(data, 4);

        //The next four store the length of the message
        int msgLen = BitConverter.ToInt32(data, 8);

        //Makes sure that strName has been 
        //passed in the array of bytes
        if (nameLen > 0)
            this.strName = 
              Encoding.UTF8.GetString(data, 12, nameLen);
        else
            this.strName = null;

        //This checks for a null message field
        if (msgLen > 0)
            this.strMessage = 
              Encoding.UTF8.GetString(data, 12 + nameLen, msgLen);
        else
            this.strMessage = null;
    }

    //Converts the Data structure into an array of bytes
    public byte[] ToByte()
    {
        List<byte> result = new List<byte>();

        //First four are for the Command
        result.AddRange(BitConverter.GetBytes((int)cmdCommand));

        //Add the length of the name
        if (strName != null)
            result.AddRange(BitConverter.GetBytes(strName.Length));
        else
            result.AddRange(BitConverter.GetBytes(0));

        //Length of the message
        if (strMessage != null)
            result.AddRange(
              BitConverter.GetBytes(strMessage.Length));
        else
            result.AddRange(BitConverter.GetBytes(0));

        //Add the name
        if (strName != null)
            result.AddRange(Encoding.UTF8.GetBytes(strName));

        //And, lastly we add the message 
        //text to our array of bytes
        if (strMessage != null)
            result.AddRange(Encoding.UTF8.GetBytes(strMessage));

        return result.ToArray();
    }

    //Name by which the client logs into the room
    public string strName;
    //Message text
    public string strMessage;
    //Command type (login, logout, send message, etc)
    public Command cmdCommand;
}

UDP Server

The following are some of the data members used by the server application:

Collapse Copy Code
//The ClientInfo structure holds the 
//required information about every
//client connected to the server
struct ClientInfo
{
    //Socket of the client
    public EndPoint endpoint;
    //Name by which the user logged into the chat room
    public string strName;
}

//The collection of all clients logged into 
//the room (an array of type ClientInfo)
ArrayList clientList;

//The main socket on which the server listens to the clients
Socket serverSocket;

byte[] byteData = new byte[1024];

One important point to note here is that, in UDP, there is no such distinction between the client and server applications. Unlike TCP, UDP servers don�t listen for incoming clients; they just look for data coming from other clients. Once we receive data, we see if it�s a message for login, logout, etc.

Collapse Copy Code
private void Form1_Load(object sender, EventArgs e)
{            
    try
    {
        //We are using UDP sockets
        serverSocket = new Socket(AddressFamily.InterNetwork, 
            SocketType.Dgram, ProtocolType.Udp);

        //Assign the any IP of the machine and listen on port number 1000
        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 1000);

        //Bind this address to the server
        serverSocket.Bind(ipeServer);
        
        IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
        //The epSender identifies the incoming clients
        EndPoint epSender = (EndPoint) ipeSender;

        //Start receiving data
        serverSocket.BeginReceiveFrom (byteData, 0, byteData.Length, 
            SocketFlags.None, ref epSender, 
               new AsyncCallback(OnReceive), epSender);
    }
    catch (Exception ex) 
    { 
        MessageBox.Show(ex.Message, "SGSServerUDP", 
            MessageBoxButtons.OK, MessageBoxIcon.Error); 
    }
}

With IPAddress.Any, we specify that the server should accept client requests coming on any interface. To use any particular interface, we can use IPAddress.Parse (�192.168.1.1�) instead of IPAddress.Any. The Bind function then bounds the serverSocket to this IP address. The epSender identifies the clients from where the data is coming.

With BeginReceiveFrom, we start receiving the data that will be sent by the client. Note that we pass epSender as the last parameter of BeginReceiveFrom, the AsyncCallback OnReceive gets this object via the AsyncState property of IAsyncResult, and it then processes the client requests (login, logout, and send message to the users). Please see the code attached to understand the implementation of OnReceive.

TCP Client

Some of the data members used by the client are:

Collapse Copy Code
public Socket clientSocket; //The main client socket
public string strName;      //Name by which the user logs into the room
public EndPoint epServer;   //The EndPoint of the server

byte []byteData = new byte[1024];

The client firstly connects to the server:

Collapse Copy Code
try
{
    //Using UDP sockets
    clientSocket = new Socket(AddressFamily.InterNetwork, 
        SocketType.Dgram, ProtocolType.Udp);

    //IP address of the server machine
    IPAddress ipAddress = IPAddress.Parse(txtServerIP.Text);
    //Server is listening on port 1000
    IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 1000);

    epServer = (EndPoint)ipEndPoint;
    
    Data msgToSend = new Data ();
    msgToSend.cmdCommand = Command.Login;
    msgToSend.strMessage = null;
    msgToSend.strName = strName;

    byte[] byteData = msgToSend.ToByte();
    
    //Login to the server
    clientSocket.BeginSendTo(byteData, 0, byteData.Length, 
        SocketFlags.None, epServer, 
        new AsyncCallback(OnSend), null);
}
catch (Exception ex)
{ 
    MessageBox.Show(ex.Message, "SGSclient", 
        MessageBoxButtons.OK, MessageBoxIcon.Error); 
}

The client after connecting to the server sends a login message. And, after that, we send a List message to get the names of clients in the chat room.

Collapse Copy Code
//Broadcast the message typed by the user to everyone
private void btnSend_Click(object sender, EventArgs e)
{
    try
    {
        //Fill the info for the message to be send
        Data msgToSend = new Data();
        
        msgToSend.strName = strName;
        msgToSend.strMessage = txtMessage.Text;
        msgToSend.cmdCommand = Command.Message;

        byte[] byteData = msgToSend.ToByte();

        //Send it to the server
        clientSocket.BeginSendTo (byteData, 0, byteData.Length, 
            SocketFlags.None, epServer, 
            new AsyncCallback(OnSend), null);

        txtMessage.Text = null;
    }
    catch (Exception)
    {
        MessageBox.Show("Unable to send message to the server.", 
            "SGSclientUDP: " + strName, MessageBoxButtons.OK, 
            MessageBoxIcon.Error);
    }  
}

The message typed by the user is sent as a Command message to the server which then sends it to all other users in the chat room.

Upon receiving a message, the client processes it accordingly (depending on whether it�s a login, logout, command, or a list message). The code for this is fairly straightforward, kindly see the attached project.

Conclusion

As you would have noticed, the UDP chat application is not very different from the TCP one; in fact, converting the TCP one into UDP was less than a day's work for me. I hope you find these articles useful. Thank you.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


posted by Sunny's
2009. 7. 21. 14:33 .NET Framework

Fast Forward: Visual Studio 2010 and .NET 4.0

This blog entry is all about Visual Studio 2010 and introduces some startup code to play with WPF and the Task Parallel Library.

Here is a rough outline about what this blog entry:

You will learn about:
(1) How to install Visual Studio 2010 and where to watch a video about it
(2) Basic Intro to the Microsoft Concurrency Web Site
(3) What is the whole point of parallel programming efforts
(4) MSDN Article is a good starting point
(5) Concurrency Samples to download and learn
(6) How to start task based threads with Task.Factory.StartNew()
    - Working with ParallelExtensionsExtras (thread-safe data structures)
    - var orders = new ObservableConcurrentCollection<PizzaOrder>();
(7) How to work with XAML (for WPF and Silverlight Apps)
    - How to work with Data Templates, DataContext Objects, and ItemsControls
    - Embedding User Controls into Canvas objects for custom GUI development

 

image_thumb12

If you haven’t done it yet, please start it now

Yes, to maximize the use of this blog, you should follow along. Learn how to install Visual Studio, then do it.

image_thumb15

Remember, Start by installing Visual Studio 2010 

 image_thumb3

Intro - Why Interesting

This is one of the oldest problems in computer science. Humankind is working hard to figure this out, but it is a real challenge.Thinking in terms of doing two or things at once is natural in our day to day lives, but somehow when we start righting code, we think sequential. Good engineers always solve problems one step at a time.

But we are at a crossroads today. The fastest clock speeds are limited to around 3 GHz.

If you aren’t learning about parallelism you are throwing away CPU. There are built in things into the OS and the .NET Framework that try to use your multi-core CPUs. However, everything from kernel mode device drivers to user mode business applications require intelligent use of parallel programming.

image_thumb32

The Big Picture Visual Studio 2010

You can think of the Task Parallel Library as a generic set of parallel capabilities, whereas PLINQ focuses on database (or object) manipulation.

image_thumb38

Parallelism and Concurrency Architecture

.NET Parallel Programming Architecture

 

Hazim Shafi, Principal Architect, Microsoft Corporation tells us the following:

Parallelism is about performance

Step 1: Understand your goals

Step 2: Measure existing performance

Step 3: Performance tuning

  Starts with sequential version

Step 4: Identify opportunities for parallelism

 

Hide latency

Speed up CPU bound phases

Step 5: Express parallelism

Step 6: Tune

Here is a good article on MSDN Magazine

image_thumb34

http://msdn.microsoft.com/en-us/magazine/cc163329.aspx#S1

 Many brilliant people are working on these things

OS resource management, a concurrency runtime, programming models, language extensions, libraries, and tools, which will make it simpler for both native and managed code developers. It is about making manycore architectures simple and accessible to the broad developer community.

Parallel Technologies in Microsoft Visual Studio 2010

Microsoft Visual Studio 2010 leads the first wave of developer tools to simplify the mainstream transition to parallel software development. Learn about Microsoft’s approach to parallel computing and the parallel technologies available in Visual Studio 2010.

What is so darn difficult about threading or concurrency?

· How to express and exploit fine-grain concurrency

· How to coordinate parallel access to shared state

· How to test and debug for correctness and performance

Traditional approaches to threading are difficult

Handling locks, semaphores, and other synchronization mechanisms is difficult, and might thus not be familiar with concepts such as deadlocks or race conditions.

Is it really harder than regular old sequential programming?

Writing programs that express and exploit fine-grain concurrency is inherently more difficult than writing sequential programs because of the extra concepts the programmer must manage and the additional requirements parallelism places on the program.

When I (Bruno) was a field engineer…

I had to fly to customer locations and use WinDBG to find unintended interactions between threads that share memory (“data races”) and the difficulties of locating and fixing such problems should they exist within a program.

The preferred thread debugging tool at Microsoft

Wikipedia says this: WinDbg is a multipurpose debugger for Microsoft Windows, distributed on the web by Microsoft. It can be used to debug user mode applications, drivers, and the operating system itself in kernel mode. It is a GUI application, but has little in common with the more well-known, but less powerful, Visual Studio Debugger.

They are right – that’s what it does.

Task Parallel Library is one option from Microsoft

image_thumb35

Think Sets

LINQ is a set-at-a-time programming model for expressing computations and places an emphasis on specifying what needs to get done instead of how it is to be done. That is perfect for parallelism. It turns out that query languages lend themselves a beautiful to parallelization.  For example, one core could be reading the index, another core could be used to sort the results, and perhaps a third core can be used for some sort of regular expression parsing or syntax within the given language.

Examples of Upcoming Technologies

Task Parallel Library, PLINQ

Upcoming releases of Visual Studio 2010 and .NET 4.0 will include support that allows you to execute for and foreach loop iterations in parallel with only small alterations to your code. Similarly, you can use a parallel version of LINQ to help boost the performance of your queries.

image_thumb39

 

  There are a lot of great samples

image71[1]

image11 

 

image_thumb11[1]

There are a lot of interesting demos here.

 image_thumb41[1]

image

Let’s take a look at AcmePizza

It is a WPF app that shows how to populate a user interface in a background thread. This allows the user to continue to interact with the application.

Watch the video and you can see how update the user interface in the background while the user can interact with other elements on the screen.

What you are supposed to notice

That you can have the GUI updating the main application window while the user can continue to interact with the application by hitting the command button with the caption “Process Next Order”

image_thumb2

Notice in the application above, orders above are streaming into the application as new tickets. But the user can still hit the “Process Next Order” button.

What you should learn

How to create a user interface that do two things at once, allowing the end user to continue to work as other things are being done. Watch this video and see that the main window is updating. Yet we can still click “Process Next Order”
image15

We are talking about “tasks,” not threads

This sample code provides a great starting point for learning WPF and the task parallel library. I will start by talking about the high level data structures. From there we will discuss other architectural decisions that were made for this application.  The main point of understanding this application is for the task of parallel library. 

image_thumb1

 

The code below illustrates the following. <ItemsControl displays an array of PizzaOrders. When this application starts, it populates the m_orders array with a bunch of random PizzaOrder objects. The window object will display these PizzaOrder objects by using the <ItemsControl>. The <ItemsControl> is a child of the window object. The <ItemsControl> will go to it's parent DataContext object, which is the window object. So when the <ItemsControl> needs to render the interface, it effectively uses the m_orders array.

image_thumb2[1]

Line 9 Data Template used in <ItemsControl> in Window1.xaml
Lines 10 - 17 The Canvas that represents our pizza order.
image_thumb11
Lines 18 – 46 These data triggers are used to update the user interface based on conditions. For example, if the pizza order is a delivery, hten color the canvas pink.

If the Order Source is the Internet, then use internetsource.ico as the file.

Here is the application object that illustrates these data template triggers.

   1:  <Application x:Class="AcmePizza.App"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:local="clr-namespace:AcmePizza"
   5:      StartupUri="Window1.xaml">
   6:      <Application.Resources>
   7:          <!--A reusable data template when binding to a collection of pizza orders.  this template is used in both the main window and 
   8:          current order window, where it is scaled larger-->
   9:          <DataTemplate x:Key="PizzaOrderTemplate">
  10:              <Canvas Width="200" Height="200">
  11:                  <Rectangle x:Name="orderRectangle" RadiusX="6" RadiusY="6" Width="200" Height="200" Fill="LightBlue" Opacity="60"/>
  12:                  <TextBlock Margin="10,10,0,0" Text="Phone:"/>
  13:                          <TextBlock Margin="50,10,0,0" FontWeight="Bold"  Text="{Binding Path=PhoneNumber}"/>
  14:                          <local:PizzaSizeCircle x:Name="pizzaSize" Canvas.Right="5" Canvas.Bottom="5" PizzaSize="17"/> 
  15:                          <Image x:Name="sourceIcon" Source="phonesource.ico" Canvas.Left="5" Canvas.Bottom="5"/>
  16:                          <ItemsControl Canvas.Top="40" Canvas.Left="30" ItemsSource="{Binding Path=Toppings}"/>
  17:                      </Canvas>
  18:              <DataTemplate.Triggers>
  19:                  <DataTrigger Binding="{Binding Path=IsDelivery}" Value="true">
  20:                      <DataTrigger.Setters>
  21:                          <Setter Property="Fill" TargetName="orderRectangle" Value="Pink"/>
  22:                      </DataTrigger.Setters>
  23:                  </DataTrigger>
  24:                  <DataTrigger Binding="{Binding Path=Size}" Value="11">
  25:                      <DataTrigger.Setters>
  26:                          <Setter Property="PizzaSize" TargetName="pizzaSize" Value="11"/>
  27:                      </DataTrigger.Setters>
  28:                  </DataTrigger>
  29:                  <DataTrigger Binding="{Binding Path=Size}" Value="13">
  30:                      <DataTrigger.Setters>
  31:                          <Setter Property="PizzaSize" TargetName="pizzaSize" Value="13"/>
  32:                      </DataTrigger.Setters>
  33:                  </DataTrigger>
  34:                  <DataTrigger Binding="{Binding Path=Source}" Value="{x:Static Member=local:OrderSource.Internet}">
  35:                      <Setter Property="Source" TargetName="sourceIcon" Value="internetsource.ico"/>
  36:                  </DataTrigger>
  37:                  <DataTrigger Binding="{Binding Path=Source}" Value="{x:Static Member=local:OrderSource.Phone}">
  38:                      <Setter Property="Source" TargetName="sourceIcon" Value="phonesource.ico"/>
  39:                  </DataTrigger>
  40:                  <DataTrigger Binding="{Binding Path=Source}" Value="{x:Static Member=local:OrderSource.Fax}">
  41:                      <Setter Property="Source" TargetName="sourceIcon" Value="faxsource.ico"/>
  42:                  </DataTrigger>
  43:                  <DataTrigger Binding="{Binding Path=Source}" Value="{x:Static Member=local:OrderSource.WalkIn}">
  44:                      <Setter Property="Source" TargetName="sourceIcon" Value="walkinsource.ico"/>
  45:                  </DataTrigger>
  46:              </DataTemplate.Triggers>
  47:          </DataTemplate>
  48:      </Application.Resources>
  49:  </Application>

 

XAML Programming

You may have noticed that the canvas embeds user control to represent the pizza size. The pizza size is represented by an ellipse and a text box.  We change the diameter of the ellipse based on data triggers.

Its the job of our user controls to represent the pizza size. Notice the “Orange” “Ellipse” below, whose width we can change based on the pizza size being ordered. Note that we just have a grid with an ellipse and a textblock.

image_thumb31[1] 

Here is the code for UserControl

    <!--A user control that changes the appearance of a circle (and text label)
    based on the specified pizza size-->
<UserControl x:Class="AcmePizza.PizzaSizeCircle"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="Auto" Width="Auto">
    <Grid x:Name="layoutRoot" Height="75" Width="75">
        <Ellipse x:Name="circle" Width="75" Height="75" Fill="Orange"/>
        <TextBlock x:Name="label" VerticalAlignment="Center" HorizontalAlignment="Center" Text="17" FontSize="20" Foreground="White"/>
    </Grid>
</UserControl>

Our code-behind is as follows:

Line 9 The property “PizzaSize”. This backed by a dependency property, which manages a callback event called PizzaSizeChangedCallBack.
Line 27 - 56

If PizzaSize changed to 11, 13, or 17, then alter the diameter, change the label's text, so that the user control resizes and reflects the new pizza diameter (pizza size) correctly.

 

Notice on line 58 we define a DependencyProperty that is backed with a property and a “changed” event. Note that when some code changes the “PizzaSize” property, code will run from line 29 to 55.

The callback event gives you access to the actual PizzaSizeCircle object whose size was changed, which then allows you to make additional changes to it, like adjusting the label text and other visually oriented control attributes. The point here is that if someone changes the size of the pizza, we need to make various other changes to the graphical interface. That's why you see the width and the height of the circle being changed to different diameters.

It is the magic of dependency properties that make this possible.

Dependencies properties are needed because we need to enforce the circle redraw. If a data trigger changes the size of the pizza, then we’ll need to draw a smaller or bigger circle. A dependency property connects all the plumbing together. The entire code-behind looks like this:
 
   1:  namespace AcmePizza
   2:  {
   3:      /// <summary>
   4:      /// Interaction logic for PizzaSizeCircle.xaml
   5:      /// </summary>
   6:      public partial class PizzaSizeCircle : UserControl
   7:      {
   8:   
   9:          public PizzaSizeCircle()
  10:          {
  11:              InitializeComponent();
  12:          }
  13:   
  14:          public int PizzaSize
  15:          {
  16:              get
  17:              {
  18:                  return (int)this.GetValue(PizzaSizeProperty);
  19:              }
  20:              set
  21:              {
  22:                  this.SetValue(PizzaSizeProperty, value);
  23:           
  24:              }
  25:          }
  26:   
  27:          static void PizzaSizeChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
  28:          {
  29:              var control = (PizzaSizeCircle)property;
  30:              switch ((int)args.NewValue)
  31:              {
  32:                  case 11:
  33:                      control.circle.Width = 30;
  34:                      control.circle.Height = 30;
  35:                      control.layoutRoot.Width = 30;
  36:                      control.layoutRoot.Height = 30;
  37:                      control.label.Text = "11";
  38:                      break;
  39:                  case 13:
  40:                      control.circle.Width = 50;
  41:                      control.circle.Height = 50;
  42:                      control.layoutRoot.Width = 50;
  43:                      control.layoutRoot.Height = 50;
  44:                      control.label.Text = "13";
  45:                      break;
  46:                  case 17:
  47:                      control.circle.Width = 75;
  48:                      control.circle.Height = 75;
  49:                      control.layoutRoot.Width = 75;
  50:                      control.layoutRoot.Height = 75;
  51:                      control.label.Text = "17";
  52:                      break;
  53:                  default:
  54:                      throw new ArgumentOutOfRangeException();
  55:              }
  56:          }
  57:   
  58:          public static readonly DependencyProperty PizzaSizeProperty =
  59:              DependencyProperty.Register("PizzaSize", typeof(int), typeof(PizzaSizeCircle),
  60:              new UIPropertyMetadata(17, new PropertyChangedCallback(PizzaSizeChangedCallBack)));
  61:          
  62:      }
  63:  }

 

  The data template triggers are defined inside of our application object.  Notice, for example, that we modify the pizzasize.  Pizza size has been implemented as a dependency property.  For the DependencyProperty callback event we make  other modifications to the user control if the pizzasize changes.  For example, we may wish to make the circular graphic display a wider diameter on the screen.

DataTemplate.Triggers
  if IsDelivery = true, then pink rectangle
  if Size = 11, then pizzasize = 11
  if Size = 13, then pizzasize = 13
  if Source = OrderSource.Internet, then sourceIcon = internetsource.ico
  if Source = OrderSource.Phone, then sourceIcon = phonesource.ico
  if Source = OrderSource.Fax, then sourceIcon = faxsource.ico
  if Source = OrderSource.WalkIn, then sourceIcon = walkinsource.ico

 

image19

Our project is a combination of objects. Since we are modeling a pizzeria, the business objects related to processing pizza orders.  These data structures below represent both the business layer, the UI layer, and other useful enumerations.

Let’s start with our main window. Most of the time you will want the grid interface. Notice below we have a two row grid. The second row of the grid will hold incoming pizza orders. As you can see from the diagram below, the first row of the grid is used to display the name of the pizza company (Acme), an image of a smiling slice of pizza, a button to allow the user to process the next order, and the label “current orders.”

Our user interface is mostly a grid with a small amount of controls We have two rows, and two columns in this grid.
Window Properties Notice we have some events wired up. I see the “Window_Loaded” event. The main window starts “Maximized.”

image_thumb4

A simple two row, two column grid. The first row has a couple of textblocks, an image, and a command button,  which reads “Process Next Order.”

All the important action is in row 2of the grid. This is where wehave the <ItemsControl>.The <ItemsControl> is the way we display PizzaOrders in the main window. The <ItemsControl> allows us to link to a data source. And that data source that we link to is a thread safe data structure that 4 threads populate. Each thread represents a source of a PizzaOrder. For example, PizzaOrders can come from the internet, fax, phone, or WalkIn.

The ItemsControl will allow us to display a collection of user controls, where each user control contains a pizza order. 

 

To be more accurate the pink pizza order in the image below is really just a canvas. The UserControl is the lower right graphic of the pink canvas (the orange circle below), which displays the PizzaSize, and whose size changes in diameter based on the size of the pizza. This example leverages data triggers and dependency properties to control the way graphic elements appear on the screen.

 

image_thumb7

Here is where the task library begins. Notice the method calls:

Task.Factory.StartNew() with some lambda expressions. The window loaded event below essentially spawns off four tasks. Each of these fourth tasks generates random pizza orders 10 times. It is these random pizza orders that Kidd added to the ItemsControl collection. Random number generators are used to create pizza orders.

        private void Window_Loaded(object sender, EventArgs e)
        {
            // launch four threads that mimic various sources
            Task.Factory.StartNew(() => { OrdererThread(OrderSource.Fax); });
            Task.Factory.StartNew(() => { OrdererThread(OrderSource.Internet); });
            Task.Factory.StartNew(() => { OrdererThread(OrderSource.Phone); });
            Task.Factory.StartNew(() => { OrdererThread(OrderSource.WalkIn); });
        }

The execution sequence (not including the user clicking “Process Next Order”)

OrdererThread is spun off of the task factory 4 ways.

We would expect that Fax, Internet, Phone, WalkIn gets passed to OrdererThread.

Each of those threads generates a random order.

GenerateRandomOrder() just gets randomly called.
Window_Loaded
OrdererThread , Order Source = Internet
OrdererThread , Order Source = Fax
GenerateRandomOrder(), Order Source = Fax
GenerateRandomOrder(), Order Source = Internet
OrdererThread , Order Source = Phone
GenerateRandomOrder(), Order Source = Phone
GenerateRandomOrder(), Order Source = Fax
GenerateRandomOrder(), Order Source = Internet
OrdererThread , Order Source = WalkIn
GenerateRandomOrder(), Order Source = WalkIn
GenerateRandomOrder(), Order Source = Phone
GenerateRandomOrder(), Order Source = Fax
GenerateRandomOrder(), Order Source = Phone
GenerateRandomOrder(), Order Source = WalkIn

 

How does GenerateRandomOrder() get called?

Remember, 4 threads are spun off. Each of the threads generates 10 random orders as follows:

        private void OrdererThread(OrderSource source)
        {
            System.Diagnostics.Debug.WriteLine("OrdererThread " + ", Order Source = " + source.ToString());
 
            for ( int i = 0; i < 10; ++i )
            {
                // submit random order
                m_orders.TryAdd( GenerateRandomOrder(source));
                // sleep for a random period
                Thread.Sleep(ConcurrentRandomNumberGenerator.Next(1000, 4001));
            }
        }

I added a Debug.WriteLine() to profile the code execution. But notice that the “for()” loop executes a random order 10 times. The thread then sleeps randomly for 1 to 4 seconds.

How the main user interface gets updated

Recall the “m_orders” variable.

image_thumb9

Notice the special data structure that derives from IProducerConsumerCollection, called ObservableConcurrentCollection. Notice that ultimately we assign to:

this.DataContext = orders;

Understanding DataContext is Key

DataContext is how our user interface gets updated. That’s the beauty of WPF – you just assign to the DataContext and everything follows through with minimal code behind.

image_thumb101

By looking at the XAML, we can see how some of it gets built. First, the second row in the grid spans 2 columns. Next, the <ItemsControl> is in the second row of the grid.

<ItemsControl x:Name="ordersList" ItemsSource="{Binding}" ItemTemplate="{StaticResource PizzaOrderTemplate}"
                      Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Top" Margin="0,0,0,0">
 
  <ItemsControl.ItemsPanel>
 
      <ItemsPanelTemplate>
          <WrapPanel/>
      </ItemsPanelTemplate>
 
  </ItemsControl.ItemsPanel>
 
  <ItemsControl.ItemContainerStyle>
 
      <Style>
          <Setter Property="Control.Width" Value="205"/>
          <Setter Property="Control.Height" Value="205"/>
          <Setter Property="Control.Margin" Value="2.5"/>
      </Style>
 
  </ItemsControl.ItemContainerStyle>
 
</ItemsControl>
 

How to add the post-its to the main window?

These are the pizza orders that populate our main window. The layout and how these colored post-it notes appear on the window is largely defined in App.xaml.. the use of DataTemplates makes this possible. Because App.xaml has somewhat of a global scope, the look and feel of these pizza orders can be used elsewhere in the program.

 

image_thumb11

 

Here is how this works.

 

<ItemsControl x:Name="ordersList" ItemsSource="{Binding}" ItemTemplate="{StaticResource PizzaOrderTemplate}"

image_thumb13

Notice the Canvas allows us to do some absolute positioning. DataTriggers later control the attributes of the canvas, such as the color, the size of the pizza, the graphic image in the lower left corner, which can be a phone, internet, fax, walk-in etc.

posted by Sunny's
2009. 5. 27. 13:53 .NET Framework

Managed Code Wrappers for new Windows 7 APIs

Check out Windows® API Code Pack for Microsoft® .NET Framework (v0.85)!!

 

Cope and pasted summary:-

The Windows® API Code Pack for Microsoft® .NET Framework provides a source code library that can be used to access new Windows 7 features (and some related Windows Vista features) from managed code. These features are not available to developers today in the .NET Framework.
The features included in this version (v0.85) of the library are:

  • Support for Windows Shell namespace objects, including the new Windows 7 libraries, Known Folders and non file system containers.
  • Windows Vista and Windows 7 Task Dialogs.
  • Windows 7 Explorer Browser Control supporting both WPF and Windows Forms.
  • Support for Shell property system.
  • Helpers for Windows 7 Taskbar Jumplists, Icon Overlay and Progress bar.
  • Support for Windows Vista and Windows 7 common file dialogs, including custom file dialog controls.
  • Support for Direct3D 11.0 and DXGI 1.0/1.1 APIs.
  • Sensor Platform APIs
  • Extended Linguistic Services APIs
posted by Sunny's
2009. 5. 20. 14:06 .NET Framework

단축키에 연결할 수 있는 동작을 보려면 아래와 같이 합니다.

1. Visual Studio에서 메뉴 -> 도구 -> 옵션을 선택하고, 옵션 창이 나타나면 왼쪽에서 환경 -> 키보드를 클릭합니다.

2. “다음 추가 키보드 매핑 구성표 적용” 리스트박스에서 하나를 고릅니다.

3. “다음 문자열을 포함하는 명령 표시” 글자 밑에 있는 텍스트박스에 글자를 입력하거나 밑에 있는 리스트 박스를 스크롤 하며 살펴봅니다.

단축키에 연결된 명령을 보려면 “바로 가기 키 누르기”에 마우스 초점을 맞추고 단축키를 누르면 됩니다. 연결된 명령이 있다면 바로 아래에 나타납니다.

image image

[Visual Studio 한글 버전 2008 화면]

Sara Ford’s WebLog: http://blogs.msdn.com/saraford/archive/2007/08/16/did-you-know-how-to-create-or-change-visual-studio-keyboard-shortcuts.aspx

posted by Sunny's
2009. 5. 20. 14:05 .NET Framework

디버깅을 하다 코딩 일부분을 주석처리 하는 경우가 많습니다. 이때 필요한 단축키가 Ctrl+E+C 입니다. Ctrl 키와 E를 누른 상태에서 C를 누릅니다. 반대는 Ctrl+E+U 입니다. 불편하다면 이전 포스팅 정보를 이용해 단축키를 변경합니다.

image

[Visual Studio 한글 버전 2008 화면]

Sara Ford’s WebLog: http://blogs.msdn.com/saraford/archive/2007/08/17/did-you-know-how-to-quickly-comment-and-uncomment-code-using-keyboard-shortcuts.aspx


posted by Sunny's
2009. 5. 20. 14:04 .NET Framework

코드를 놓고 얘기할 때, 꼭 필요한 것이 행 번호입니다. 행 번호를 표시하는 방법은 메뉴 -> 도구 -> 옵션을 선택한 다음, 옵션 창 왼쪽 부분에서 텍스트 편집기 -> 모든 언어를 선택하고, 오른쪽에서 줄 번호 체크박스를 클릭합니다.

image


[Visual Studio 한글 버전 2008 화면]

Sara Ford’s WebLog: http://blogs.msdn.com/saraford/archive/2007/08/30/did-you-know-how-to-show-line-numbers-in-the-editor.aspx

posted by Sunny's
prev 1 2 3 4 5 6 7 next