private void InitializeComponent() { SuspendLayout(); Size = new GDISize(350, 100); StartPosition = WinFormsFormStartPosition.CenterScreen; Text = "サロゲートペアの確認サンプル"; var t = new WinFormsTextBox(); t.Text = "\uD867\uDE3D"; // 魚へんに花という文字。魚のホッケの文字を指定。 var b = new WinFormsButton { Text = "Exec" }; b.Click += (s, e) => { var str = t.Text; WinFormsMessageBox.Show(string.Format("文字:{0}, 長さ:{1}", str, str.Length), "Stringでの表示"); // // サロゲートペアの文字列 // // サロゲートペアの文字列は1文字で // 4バイトとなっている。 // // サロゲートペアの文字列に対して // String.Lengthプロパティで長さを取得すると // 1文字なのに2と返ってくる。 // // これを1文字として認識するには以下のクラスを利用する。 // // System.Globalization.StringInfo // // このクラスの以下のプロパティを利用することで // 1文字と認識することが出来る。 // // LengthInTextElementsプロパティ // var si = new StringInfo(str); WinFormsMessageBox.Show($"文字:{si.String}, 長さ:{si.LengthInTextElements}", "StringInfoでの表示"); }; var contentPane = new WinFormsFlowLayoutPanel { FlowDirection = WinFormsFlowDirection.TopDown, WrapContents = true }; contentPane.Controls.AddRange(new WinFormsControl[] { t, b }); contentPane.Dock = WinFormsDockStyle.Fill; Controls.Add(contentPane); ResumeLayout(); }
protected void InitializeComponent() { SuspendLayout(); var b = new WinFormsButton { Name = "btn01", Text = "btn01" }; b.Click += (s, e) => { WinFormsMessageBox.Show("Click Handler Begin : " + string.Format("{0}-{1}", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId)); var btn = s as WinFormsButton; // この場所でAsyncOprationを作成するとWindowsFormsSynchronizationContextオブジェクトになる。 // (現在のスレッドのコンテキストがWindows Formsのため) // (WindowsFormsSynchronizationContext.AutoInstallの値がデフォルトでtrueになっているので、最初のコントロールが // newされた時にメッセージスレッド (ここではMain Thread)にWindowsFormsSynchronizationContextが読み込まれる) // // SynchonizationContextはSystem.Threading名前空間に存在し、以下の派生クラスを持つ。 // ⇒System.Windows.Forms.WindowsFormsSynchronizationContext (WindowsForms用) // ⇒System.Windows.Threading.DispatcherSynchronizationContext (WPF用) // それそれの派生クラスは、基本機能に加え、各自独自の動作とプロパティを持っている。 WinFormsMessageBox.Show("Click Handler Begin SyncContext : " + SynchronizationContext.Current.ToString()); // AsyncOperationManagerはCreateOperationメソッドが呼ばれた際に現在のSynchronizationContextをコピーして // AsyncOperationのコンストラクタに渡している模様。なので、AsyncOperationのPost,Sendが正確にメッセージスレッドに // 同期できるかどうかは、このAsyncOperationオブジェクトを作成した時点でのスレッドにSynchronizationContextがあるかどうかによる。 // (新規でスレッドを作成した場合はSynchronizationContextはnullとなっている。) // // 尚、SynchronizationContextを直接用いて、Post, Sendを行ってもよい。 // 現在のスレッドのSynchronizationContextを取得するには、SynchronizationContext.Currentで取得できる。 // 存在しない場合は、以下のようにして設定できる。 // // SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); // この場所でAsyncOperationを作成した場合、このスレッド(Main Thread)上では既にWindowsFormsSynchronizationContextが作成されている // ので、それがAsyncOperationに渡る。 // AsyncOperationは自身のPost, PostOperationCompletedが呼ばれた際に内部で保持しているSynchronizationContextに処理を委譲します。 // (なので、正常にメッセージスレッドにてデリゲートが処理される事になる。) var asyncOp = AsyncOperationManager.CreateOperation(btn); // 別スレッド側にも同じSynchronizationContextを利用させる場合は以下のようにして // コピーを作成し、保持しておき、対象のスレッドに設定する。 //SynchronizationContext syncContext = SynchronizationContext.Current.CreateCopy(); var t = new Thread(() => { WinFormsMessageBox.Show("New Thread : " + $"{Thread.CurrentThread.Name}-{Thread.CurrentThread.ManagedThreadId}"); // 新規で別のスレッドを作成した場合は最初SynchronizationContextはnullとなっている。 // 新たに割り当てる場合は以下のようにする。 //SynchronizationContext.SetSynchronizationContext(syncContext); // この場所でAsyncOprationを作成するとSynchronizationContextオブジェクトになる。 // (AsyncOperationManagerは、現在のスレッドにてSynchronizationContextが存在しない場合は新たにSynchronizationContextを // 生成し、設定してからAsyncOperationを生成する。元々SynchronizationContextがAsyncOperationを生成する際に存在している場合は // それをAsyncOperationに渡して生成する。) WinFormsMessageBox.Show("New Thread SyncContext Is Null?? (1) : " + (SynchronizationContext.Current == null)); //AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(btn); WinFormsMessageBox.Show("New Thread SyncContext Is Null?? (2) : " + (SynchronizationContext.Current == null)); // ここで表示されるSynchronizationContextは, AsyncOperationがどのスレッドで作成されたかによって // 出力される値が変わる。 // // ■イベントハンドラ側でAsyncOperationが生成された場合:WindowsFormsSynchronizationContext // ■別スレッド側でAsyncOperationが生成された場合: SynchronizationContext WinFormsMessageBox.Show(asyncOp.SynchronizationContext.ToString()); // Post及びPostOperationCompletedメソッドの呼び出しは、実際にはAsyncOperationが内部で保持しているSynchronizationContext.Postを // 呼び出しているので、対象となるSynchronizationContextによって同期されるスレッドが異なる。 // // ■イベントハンドラ側でAsyncOperationが生成された場合:メッセージスレッド側に同期 (Main Thread) // ■別スレッド側でAsyncOperationが生成された場合: 新たにスレッドが作成されその中で処理 (Thread Pool) asyncOp.Post(state => { var curThread = Thread.CurrentThread; WinFormsMessageBox.Show("AsyncOp.Post : " + string.Format("{0}-{1}-IsThreadPool:{2}", curThread.Name, curThread.ManagedThreadId, curThread.IsThreadPoolThread)); }, asyncOp); asyncOp.PostOperationCompleted(state => { var curThread = Thread.CurrentThread; WinFormsMessageBox.Show("AsyncOp.PostOperationCompleted : " + string.Format("{0}-{1}-IsThreadPool:{2}", curThread.Name, curThread.ManagedThreadId, curThread.IsThreadPoolThread)); }, asyncOp); }); t.Name = "Sub Thread"; t.IsBackground = true; t.Start(); }; var layout = new WinFormsFlowLayoutPanel(); layout.Dock = WinFormsDockStyle.Fill; layout.Controls.Add(b); Controls.Add(layout); ResumeLayout(); }