To use timer-driven animation in your application, you must connect the animation manager to the timer and provide a timer event handler. To avoid unnecessary drawing when no animations are playing, you should configure the timer to disable itself automatically.
The following steps continue those in Adding Animation to an Application.
Step 4: Connecting the Animation Manager to the Timer
The UIAnimationManager object implements the IUIAnimationTimerUpdateHandler interface, which allows it to be connected to a UIAnimationTimer object. When the animation manager is connected to a timer, the timer can tell the manager when the animation state should be updated as time progresses. The animation manager can in turn tell the timer when there are animations playing, so the timer can shut itself off during idle periods when redrawing is unnecessary.
Connect the two objects by setting the manager as the timer's update handler.
// Connect the animation manager to the timer.
// UI_ANIMATION_IDLE_BEHAVIOR_DISABLE tells the timer to shut itself
// off when there is nothing to animate.
IUIAnimationTimerUpdateHandler *pTimerUpdateHandler;
hr = m_pAnimationManager->QueryInterface(
IID_PPV_ARGS(&pTimerUpdateHandler)
);
if (SUCCEEDED(hr))
{
hr = m_pAnimationTimer->SetTimerUpdateHandler(
pTimerUpdateHandler
UI_ANIMATION_IDLE_BEHAVIOR_DISABLE
);
pTimerUpdateHandler->Release();
if (SUCCEEDED(hr))
{
...
}
}
If UI_ANIMATION_IDLE_BEHAVIOR_DISABLE is not used, it is also necessary to enable the timer to start it ticking.
Step 5: Define and Register a Timer Event Handler
The application should draw a frame for each timer tick.
First, define a timer event handler COM class. In the example below, the timer event handler invalidates the window's client area to cause a repaint after each update of the animation state.
class CTimerEventHandler :
public IUIAnimationTimerEventHandler
{
public:
static HRESULT CreateInstance
(
CMainWindow *pMainWindow,
IUIAnimationTimerEventHandler **ppTimerEventHandler
)
{
*ppTimerEventHandler = NULL;
CTimerEventHandler *pTimerEventHandler = new CTimerEventHandler(
pMainWindow
);
if (pTimerEventHandler == NULL)
{
return E_OUTOFMEMORY;
}
*ppTimerEventHandler = static_cast<IUIAnimationTimerEventHandler *>(pTimerEventHandler);
(*ppTimerEventHandler)->AddRef();
return S_OK;
}
// IUnknown
...
// IUIAnimationTimerEventHandler
IFACEMETHOD(OnPreUpdate)
(
)
{
return S_OK;
}
IFACEMETHOD(OnPostUpdate)
(
)
{
m_pMainWindow->Invalidate();
return S_OK;
}
IFACEMETHOD(OnRenderingTooSlow)
(
UINT32 /* fps */
)
{
return S_OK;
}
protected:
CTimerEventHandler(CMainWindow *pMainWindow)
: m_pMainWindow(pMainWindow)
{
}
CMainWindow *m_pMainWindow;
};
Then, in the initialization code, create an instance of the timer event handler and pass it to the timer.
IUIAnimationTimerEventHandler *pTimerEventHandler;
hr = CTimerEventHandler::CreateInstance(
this,
&pTimerEventHandler
);
if (SUCCEEDED(hr))
{
hr = m_pAnimationTimer->SetTimerEventHandler(
pTimerEventHandler
);
pTimerEventHandler->Release();
if (SUCCEEDED(hr))
{
...
}
}
Because the timer event handler retains a reference to the main window object, the timer event handler should be cleared (by passing NULL to SetTimerEventHandler) or the timer completely released before the main window is destroyed.
With this code in place, the application can play animations by building and scheduling storyboards.
See Also
- Using Windows Animation
Send comments about this topic to Microsoft
Build date: 10/21/2009