2016-12-17 3 views
2

メッセージボックスクラスを1つに作成しようとしていますが、ボタンを押すのを待つメッセージボックスと同じ方法で動作させたいそれ以降のコードを実行するよりも。私は2つの方法UIスレッドをブロックせずにスレッドが終了するのを待ちます

2つのスレッド

public void TestClick() 
    { 
     Thread thread1 = new Thread(TestMethod); 
     thread1.Start(); 
     thread1.Join(); 
     Debug.Log("Done"); 
    } 

    private void TestMethod() 
    { 
     float time = 0; 
     while (time <= 20) 
     { 
      Thread.Sleep(100); 
      time++; 
      Debug.Log("Im doing heavy work"); 
     } 
    } 

この1つのブロックメインスレッドに参加してTestMethodが完了した後にのみ再開されますが、私ドンでそれを再作成しようとした

 var mbox = MessageBox.Show("Test", "test", MessageBoxButtons.YesNo); 
     var test = mbox == DialogResult.Cancel; <- it will wait here 

ユーザーがその時間中にメッセージボックスとやりとりすることができないため、それが必要です。

非同期アプローチ

public delegate int AsyncTask(); 

    public void TestClick() 
    { 
     RunAsyncAndWait(); 
     Debug.Log("Done"); 
    } 

    public int Method1() 
    { 
     float time = 0; 
     while (time <= 20) 
     { 
      Thread.Sleep(100); 
      time++; 
      Debug.Log("Im doing heavy work"); 
     } 
     return 0; 
    } 


    public void RunAsyncAndWait() 
    { 
     AsyncTask ac1 = Method1; 

     WaitHandle[] waits = new WaitHandle[1]; 
     IAsyncResult r1 = ac1.BeginInvoke(null, null); 
     waits[0] = r1.AsyncWaitHandle; 

     WaitHandle.WaitAll(waits); 

    } 

これはまさに最初のもののように動作しますが、我々はWaitHandle[] waits = new WaitHandle[2];WaitHandle[]の大きさのようないくつかのものを変更した場合、それは不気味に動作します。

これは、以前の方法のように一度に21個のメッセージを投稿するのではなく、コンソールに何かを連続的に書き込むので、これはもっとうまく動作します。プログラムがうまく動作します)、それはコンソールで何かを印刷の上に保持し、私はこのエラーを取得

例外ArgumentNullException:NULLハンドル パラメータ名:waitHandles System.Threading.WaitHandle.CheckArray(System.Threading.WaitHandle [ ]ハンドル、ブールwaitAll)(/Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Threading/WaitHandle.cs:77) System.Threading .WaitHandle.WaitAll(System.Threading.WaitHandle [] waitHandles)(/Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Threading/WaitHandle.cs:109) Assets.Scripts.Test。 RunAsyncAndWait()(Assets/Scripts/Test.cs:40) Assets.Scripts.Test.TestClick()(Assets/Scripts/Test.cs:16) UnityEngine.Events.InvokableCall.Invoke(System.Object [ ] args)(C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:153) UnityEngine.Events.InvokableCallList.Invoke(System.Object [] parameters)(C:/ buildslave/unity/buildにあります) /Runtime/Export/UnityEvent.cs:630) UnityEngine.Events.UnityEventBase.Invoke(System.Object [] parameters)(C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:765) UnityEngine .Events.UnityEvent.Invoke()(C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:53)(C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35) UnityEngine.UI.Button.OnPointerClick(UnityEngine。 (IPointerClickHandlerハンドラ、UnityEngine.EventSystems)。(EventSystems.PointerEventData eventData)(C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44) UnityEngine.EventSystems.ExecuteEvents.Execute BaseEventData eventData)(C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52) UnityEngine.EventSystems.ExecuteEvents.Execute [IPointerClickHandler](UnityEngine.GameObjectターゲット、UnityEngine.EventSystems .BaseEventData eventData、UnityEngine.EventSystems.EventFunction`1 functor)(C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269) UnityEngine.EventSystems。EventSystem:私はすぐにちょうど

IAsyncResult r1 = ac1.BeginInvoke(ar => Debug.Log("Done"), null); 

をそれをテストしかし、運の何も変わっていないとのために何かを追加しましたので、私はここでコールバック関数が必要になることがありますように更新()

最初の行は、私には思えました。

どのように私は全体として(メッセージボックスを作る、ボタンが押されるまでスレッドをブロックする)この問題に近づくことができますか?

+1

またはMicrosoftがこれをどのように実装しているかについての情報... _ [ここにソースがあります](http://www.dotnetframework.org/default.aspx/4.0/[email protected]/DEVDIV_TFS/Dev10/Releases)/RTMRel/wpf/src/Framework/System/Windows/MessageBox @ cs/1305600/MessageBox @ cs)を使用してください。 – txtechhelp

+0

メッセージボックスにスレッドをブロックするかブロックしないようにしますか? – CodingYoshi

答えて

3

WinFormsとUnityには大きな違いがあります。 WinFormsには、モーダルフォームでブロックされるUI用のスレッドが1つあります。 Unityでは、スクリプトの実行順序といくつかのエンジン機構が各フレームでどのように実行されるべきかを決定する、複数のメソッドを持つ複数のオブジェクトを持っています。

Unityでモーダルメッセージボックスを使用する場合は、ブールチェックを追加するかスクリプトを無効にすることで、特定のスクリプトのUpdateまたはFixedUpdateの実行をブロックすることができます。最初の方法はもっと多くのオプションを提供しますが、2番目の方法は簡単です。ただし、スクリプトを無効にすると、以外のすべてが中止されることに注意してください。コルーチンを呼び出します。

単純なSpriteRendererまたはImageをその上に置くことで、ユーザーの基本的なオブジェクトとのやりとりをブロックできます。このマスクの透明度はゼロにすることができます。フルスクリーンサイズで、Raycast Targetを有効にする必要があります。

私は=アルファを持つシンプルな黒のスプライトを持ってその背後にあるフルスクリーンマスクを使用して他のすべてのスクリプトは、それにもかかわらず、実行することを0.1

public GameObject ModalMessageBox;//game object of message box with a mask 

public void TestClick() 
{ 
    StartCoroutine(TestMethod); 
    ModalMessageBox.setActive(true); 
} 

IEnumerator TestMethod() 
{ 
    float time = 0; 
    while (time <= 20) 
    { 
     yield return new WaitForSeconds(.1f); 
     time++; 
     Debug.Log("Im doing heavy work"); 
    } 
    ModalMessageBox.setActive(false); 
} 

void Update() 
{ 
    if(ModalMessageBox.activeSelf) 
    { 
     //handle message box 
    } 
    else 
    { 
     //handle normal update stuff 
    } 
} 

ノートをメッセージボックスを好むだろう。他のスクリプトの実行をブロックする必要がある場合は、それを1つずつ実行する必要があります。

注:スクリプトを無効にすることが開始コルーチンを停止しないので

、あなたにもスクリプト自体Script1,2,3はシングルトンクラスである

public Script1 script1; 
public Script2 script2; 
public Script3 script3; 

void BlockScripts(bool block) 
{ 
    //for singleton scripts: 
    Script1.Instance.enabled = !block; 
    Script2.Instance.enabled = !block; 
    Script3.Instance.enabled = !block; 
    //for referenced scripts: 
    script1.enabled = !block; 
    script2.enabled = !block; 
    script3.enabled = !block; 

    //self 
    enabled = !block; 
} 

public void TestClick() 
{ 
    StartCoroutine(TestMethod); 
    ModalMessageBox.setActive(true); 

    BlockScripts(true); 
} 

IEnumerator TestMethod() 
{ 
    float time = 0; 
    while (time <= 20) 
    { 
     yield return new WaitForSeconds(.1f); 
     time++; 
     Debug.Log("Im doing heavy work"); 
    } 

    ModalMessageBox.setActive(false); 

    BlockScripts(false); 
} 

void Update() 
{ 
} 

を無効にするかもしれませんscript1,2,3は、ブロックしたいスクリプトの参照です。

+0

これは完全な答えではありません、少し詳しく教えてください' IsModalMessageIsOpen'とUpdateとFixedUpdateのメソッドをブロックすることによって、ユーザーがメッセージボックスを呼び出した場所は依然として実行されます。 –

+0

あなたが正しいです、私はいくつかの詳細を追加 – Bijan

3

スレッドやその他の.NET非同期の概念を使用して、使用したい方法でUnityを使用しようとしないでください。ポップアップウィンドウが表示されているかを確認するカスタムCustomYieldInstructionを作成します。

class WaitWhile: CustomYieldInstruction { 
    Func<bool> m_Predicate; 

    public override bool keepWaiting { get { return m_Predicate(); } } 

    public WaitWhile(Func<bool> predicate) { m_Predicate = predicate; } 
} 

あなたがStartCoroutine経由DialogExample()を起動するか、別のコルーチンからのyield retrunを実行

public GameObject window; //the window that will be shown. 

IEnumerator DialogExample() 
{ 
    window.SetActive(true); 
    yield return new WaitWhile(() => window.activeInHierarchy); 

    //Code here does not run till after the window is deactivated. 
} 

のように使用されます。

+0

これは、表示されている場合に機能しますが、これはコルーチン内のコードが終了するまで待つだけですが、より重要なことは実際にhttpが呼び出されている外で**コード**を待つことです://prntscr.com/dkohw9ボタンが押されていなくても、ユーザーコードは実行され、実行されますが、回避策がありますか? –

+0

それについてのヒント? –

+0

@ dB.Employeeはい、私は最後の文章で言ったように、あなたは 'DialogExample()'で 'yield return'を行い、呼び出しサイトをブロックします。これを使用できるようにするには、呼び出し関数をコルーチンにする必要があります。これは、.NET 4.5のasync/awaitと非常によく似ています。これは感染コードです。 –

関連する問題