0

Silverlight 4 アプリのデータの取得に苦労しています。My View は何らかの情報を取得する必要があるため、DataProvider を呼び出します。My DataProvider が Oracle を呼び出します。これはコールバックを必要とする非同期呼び出しであるため、DataProvider メソッドはそれを待つ必要があります。ただし、非同期呼び出しの後に DataProvider メソッドに Thread.Sleep ループを配置すると、コールバックはヒットしません。Thread.Sleep ループを削除すると、コールバックがヒットしますが、それまでに DataProvider メソッドは何も返さずに終了しています。

非同期性は、View にとっては何の価値もありません。次に進むには、この時点でこのデータが必要です。私が理解したいと思っているのは、ビューからの 1 つの要求に応答して DataProvider クラスに多数のデータベース呼び出しを行わせ、準備が整うまで戻らないようにする方法です。この場合、ビューが応答しないことは気にしません。しかし、私がやっている方法は、アプリを完全にロックすることです。

これは私が持っているものです:

ビューは次の呼び出しを行います。

m_Data = m_DataProvider.GetMyStuffData( some parameters to filter the data );

DataProvider はパラメーターを認識し、m_Data オブジェクトの構築を開始します。これにはいくつかの呼び出しが必要で、そのうちの 1 つが次のようになります。

public override List<MyStuff> GetMyStuff( DateTime _startDay, DateTime _endDay )
{
    var rc = new List<MyStuff>( );
    m_WaitingForData = true;
    var query = MyQueryString;
    var parameters = new string[ ] { "My Parameter" };
    getOracleData(parameters, query, "My Query ID");
    while (m_WaitingForData)
    {
        Thread.Sleep( 20 );
    }
    // process Data which asynchronous call put into a member variable.
    return rc;
}

getOracleData は非同期呼び出しを行い、コールバックを GetTable に接続します。

コールバック メソッド GetTable は、GetMyStuff が予期しているメンバー変数にデータを抽出し、m_WaitingForData をオフにして終了します。

4

2 に答える 2

0

私はこの小さなクラスを開発することになりました:

using System;
using System.Linq;
using System.Windows;
using System.Collections.Generic;

namespace MyNamespace
{
    public class AsyncDataManager
    {
        // This dictionary will help handle waiting for asynchronous data callbacks.
        private Dictionary<string, int[ ]> m_ExpectedData;
        private Action m_FinalProcess;
        private object m_Locker = new object( );
    public AsyncDataManager( Action _finalProcess )
    {
        m_ExpectedData = new Dictionary<string, int[ ]>( );
        m_FinalProcess = _finalProcess;
    }

    public void SetExpectation( string _key, int _occurrances = 1 )
    {
        m_ExpectedData[ _key ] = new[ ] { _occurrances, 0 };
    }

    public void ManageCallbacks( string _key, Action _action = null )
    {
        lock ( m_Locker )
        {
            m_ExpectedData[ _key ][ 1 ]++;
            if ( _action != null )
            {
                _action( );
            }
            // Once all the expected callbacks have been handled, using a 
            // Dispatcher gets us back onto the UI thread and out of the scope of the lock.
            if ( !m_ExpectedData.Values.Any( v => v[ 0 ] != v[ 1 ] ) )
            {
                Deployment.Current.Dispatcher.BeginInvoke( m_FinalProcess );
            }
        }
    }

    // Without requiring that all expected async calls are complete, we can check for a certain set.
    public bool TestForSubsetComplete( params string[ ] _items )
    {
        return ( !m_ExpectedData.Keys.ToList( )
            .Where( k => _items.Contains( k ) )
            .Any( v => m_ExpectedData[ v ][ 0 ] != m_ExpectedData[ v ][ 1 ] ) );
    }
}

}

2 つの呼び出しを行う場合の例:

var asyncMgr = new AsyncDataManager( ( ) =>
{
    // Code to run after all the async processes are complete
} );
asyncMgr.SetExpectation( "Data1" );
asyncMgr.SetExpectation( "Data2" );
m_DataProvider.GetData1( /* arguments for the call */, ( results ) =>
{
    // store the results, then tell asyncMgr that this process is complete
    asyncMgr.ManageCallbacks( "Data1" );
} );
m_DataProvider.GetData2( /* arguments for the call */, ( results ) =>
{
    // store the results, then tell asyncMgr that this process is complete
    asyncMgr.ManageCallbacks( "Data2" );
} );
于 2013-06-21T14:41:25.283 に答える