询问者
Windows store app 多线程编程(三)

常规讨论
-
大家好,
关于Windows Streo多线程编程的问题,我们会用通过一个系列的文章来介绍。这个系列的文章会贯穿一个例程,并向大家展示,有哪些多线程的API可以使用,如何创建线程,如何去做线程同步。
这篇文章作为这个系列的第三篇,会向大家介绍,如何在Windows Runetime 中使用委托和事件。
Jesse Jiang [MSFT]
MSDN Community Support | Feedback to us
2012年10月15日 7:09版主
全部回复
-
接下来我们想让小球在边界内运动,刚才我们设计了向一个方向走的函数,我们以同样的思路设计向另一个方向走的函数。在运动的过程中,我们会做边界检测。如果超出边界我们就调用向相反方向走的函数。那如何调用向相反方向走的函数呢,我们用事件来做。
我们再添加一个小球<Ellipse x:Name="round2" Height="100" Canvas.Left="579" Canvas.Top="254" Stroke="Black" Width="100" Fill="YellowGreen"/> <Ellipse x:Name="round1" Fill="Turquoise" Height="100" Canvas.Left="393" Stroke="Black" Canvas.Top="254" Width="100"/>
现在我们只考虑水平方向的运动,然后我们通过事件来触发向不同方向运动的函数。
首先我们要声明一个委托,
public delegate void MoveElement(Windows::UI::Xaml::UIElement^ shapes,int index);
两个事件
event MoveElement^ AgainstLeft; event MoveElement^ AgainstRight;
我们向两个方向走的函数要跟委托的声明一样
void Moveleft(Windows::UI::Xaml::UIElement^ shapes,int index); void Moveright(Windows::UI::Xaml::UIElement^ shapes,int index);
一个DispatcherTimer数组
Platform::Array<Windows::UI::Xaml::DispatcherTimer^>^ dispatcherarr;
两个 Windows::Foundation::EventRegistrationToken cookierarr[THREADNUM]; 这个的作用我们待会再讲。
在MainPage的初始化函数里面,我们初始化DispatcherTimer数组,注册向左走和向右走的事件AgainstLeft+=ref new MoveElement(this,&MainPage::Moveright); AgainstRight+=ref new MoveElement(this,&MainPage::Moveleft); dispatcherarr=ref new Platform::Array<Windows::UI::Xaml::DispatcherTimer^>(THREADNUM);
Jesse Jiang [MSFT]
MSDN Community Support | Feedback to us
- 已编辑 Jesse JiangModerator 2012年10月22日 8:45
2012年10月15日 7:13版主 -
向左走向右走的代码如下
void MainPage::Moveleft(Windows::UI::Xaml::UIElement^ shapes,int index) { Windows::UI::Xaml::DispatcherTimer^ dispatchertimer=dispatcherarr->get(index); auto runwithTimer = [this,shapes,index](Object^ e,Object^ ags) { auto uiDelegate = [this,shapes,index]() { double x=Canvas::GetLeft(shapes); // WaitForSingleObjectEx函数用于两球碰撞检测,在边界检测的例程中请删除 if(x<0||(WAIT_OBJECT_0==WaitForSingleObjectEx(ghSemaphore,1,TRUE))) { Windows::UI::Xaml::DispatcherTimer^ dispatchertimer=dispatcherarr->get(index); dispatchertimer->Tick-=cookierarr[index]; AgainstLeft(shapes,index); return; } Canvas::SetLeft(shapes,x-5); }; Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler(uiDelegate)); }; cookierarr[index] = dispatchertimer->Tick+=ref new EventHandler<Object^>(runwithTimer); } void MainPage::Moveright(Windows::UI::Xaml::UIElement^ shapes,int index) { Windows::UI::Xaml::DispatcherTimer^ dispatchertimer=dispatcherarr->get(index); auto runwithTimer = [this,shapes,index](Object^ e,Object^ ags) { auto uiDelegate = [this,shapes,index]() { double x=Canvas::GetLeft(shapes); FrameworkElement^ eshape1=safe_cast<FrameworkElement^>(shapes); // WaitForSingleObjectEx函数用于两球碰撞检测,在边界检测的例程中请删除 if(x+eshape1->Width>this->canvas->ActualWidth||(WAIT_OBJECT_0==WaitForSingleObjectEx(ghSemaphore,1,TRUE))) { Windows::UI::Xaml::DispatcherTimer^ dispatchertimer=dispatcherarr->get(index); dispatchertimer->Tick-=cookierarr[index]; AgainstRight(shapes,index); return; } Canvas::SetLeft(shapes,x+5); }; Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler(uiDelegate)); }; cookierarr[index] = dispatchertimer->Tick+=ref new EventHandler<Object^>(runwithTimer); }
这两个函数的逻辑就是当小球超出边界之后,激发相反运动的事件。
dispatchertimer->Tick-=cookierarr[index];
这一段代码就是移除cookie,这个cookie就是dispatchertimer->Tick+=ref new EventHandler<Object^>(runwithTimer);的返回值
我们在添加dispatchertimer句柄的时候,会返回这个cookie,当这个函数不用的时候,我们就把这个cookie减掉。这样如果dispatchertimer不停止的话,之前的cookie函数就不会再被执行。
如果我们没有减掉这个cookie的话,dispatchertimer里面同时有向左走和向右走的函数,或者是都是相同方向的函数。这样小球要么不动,要么两倍速度运动。
然后我们写一个函数调用向左走和向右走的函数
void MainPage::Usetwodispatchertimer() { Windows::UI::Xaml::DispatcherTimer^ tempdispatchertime; Windows::Foundation::TimeSpan time; time.Duration =10000; // 移动第一个小球 if(dispatcherarr->get(0)==nullptr) { tempdispatchertime=ref new DispatcherTimer(); tempdispatchertime->Interval=time; dispatcherarr->set(0,tempdispatchertime); Moveleft(this->round1,0); } dispatcherarr->get(0)->Start(); // 移动第二个小球 if(dispatcherarr->get(1)==nullptr) { tempdispatchertime=ref new DispatcherTimer(); tempdispatchertime->Interval=time; dispatcherarr->set(1,tempdispatchertime); Moveright(this->round2,1); } dispatcherarr->get(1)->Start(); }
这样编译运行之后,我们就可以看到两个小球在两侧边界内运动。
如果想让小球停止,我们加一个按钮然后在里面写
for(int i=0;i<THREADNUM;i++) { if(dispatcherarr->get(i)!=nullptr) { dispatcherarr->get(i)->Stop(); } }
Jesse Jiang [MSFT]
MSDN Community Support | Feedback to us
- 已编辑 Jesse JiangModerator 2012年10月22日 8:48
2012年10月15日 7:17版主