我正在努力获取Silverlight 4应用的数据。 My View需要获取一些信息,因此它会调用我的DataProvider。我的DataProvider调用了Oracle。这是一个需要回调的异步调用,因此我的DataProvider方法需要等待它。但是,如果我在异步调用后在我的DataProvider方法中放置一个Thread.Sleep循环,则回调永远不会发生。如果我删除Thread.Sleep循环,回调就会命中,但到那时我的DataProvider方法已经完成,没有任何东西可以返回。
异步性对观点没有价值;它必须在此时拥有这些数据才能继续前进。我希望能够弄清楚的是我如何让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并退出。
答案 0 :(得分: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" );
} );
答案 1 :(得分:-1)
您应该使用异步回调
http://www.enterpriseetc.com/post/Three-Ways-to-Handle-Silverlight-Asynchronous-Service-Calls.aspx
然后当作业完成后,它将触发您告诉它的下一部分代码