locked
Windows store app 多线程编程(三) RRS feed

  • 常规讨论

  • 大家好,

    关于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



    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


    2012年10月15日 7:17
    版主