0

我正在努力获取 Silverlight 4 应用程序的数据。我的视图需要获取一些信息,因此它会调用我的 DataProvider。我的 DataProvider 调用 Oracle。这是一个需要回调的异步调用,所以我的 DataProvider 方法需要等待它。但是,如果我在异步调用之后在我的 DataProvider 方法中放置一个 Thread.Sleep 循环,则回调永远不会命中。如果我删除 Thread.Sleep 循环,回调会命中,但到那时我的 DataProvider 方法已经完成,没有任何东西可以返回。

异步性对 View 没有价值;它此时必须拥有这些数据才能继续前进。我希望能够弄清楚的是,如何让 DataProvider 类进行多次数据库调用以响应来自视图的一个请求,并且在它准备好之前不返回。在这种情况下,我不介意视图没有响应;但我这样做的方式是完全锁定应用程序。

这就是我所拥有的:

该视图进行此调用:

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

DataProvider 识别参数并开始构建 m_Data 对象。这需要多次调用,其中一个如下所示:

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 ] ) );
    }
}

}

我有两个电话要打的一个例子:

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 回答
-1

您应该使用异步回调

http://www.enterpriseetc.com/post/Three-Ways-to-Handle-Silverlight-Asynchronous-Service-Calls.aspx

然后当工作完成时,它会触发你告诉它的下一段代码

于 2012-10-12T13:19:19.603 回答