Este artigo foi traduzido por máquina.

Circulando

Aprimorando os aplicativos Windows Touch para usuários móveis

Gus Class

Baixar o código de exemplo

Windows 7 apresenta toque do Windows, que aprimora a entrada por toque no hardware capaz e fornece uma sólida plataforma para criar aplicativos de toque. Potencialmente, isso significa que você pode desenvolver interfaces intuitivas notavelmente que os usuários de todas as idades e capacidades de computação podem entender com uma quantidade mínima de treinamento ou instrução.

A mágica por trás essa funcionalidade é a API de toque do Windows. Usando essa API, você pode recuperar informações sobre onde um usuário está tocando a tela e sobre um usuário na tela gestos. Você também tem acesso a física do mundo real para elementos de interface do usuário. Movendo na tela objeto torna-se tão fácil como mover um objeto no mundo real. Alongando um objeto é como alongando um pedaço de elastic. Quando os usuários interagem com um aplicativo well-implemented toque, eles se sentir como embora está interagindo com a tecnologia do futuro ou melhor ainda, eles não Observe que estiver usando um aplicativo em todos os. Eles não precisam usar um mouse, uma caneta ou atalho teclas ou selecionar itens de menu para chegar a funcionalidade do aplicativo principal com precisão.

Aplicativos adaptados para uso móvel devem incorporar requisitos específicos para garantir a experiência é bem adequada para o ambiente do usuário. Um aplicativo mal implementado toque completamente pode derrotar o propósito de usando Windows Touch. As diretrizes Windows Touch User Experience (go.microsoft.com/fwlink/?LinkId=156610 ) realce maneiras que os desenvolvedores podem melhorar a experiência dos usuários em trânsito. Essas diretrizes abordam diversos cenários relevantes para os desenvolvedores de aplicativo móvel e tornam mais fácil evitar armadilhas potenciais de desenvolvimento Windows Touch.

Se você retirar apenas uma coisa deste artigo, lembre-se de que, ao criar um aplicativo que os usuários móveis destinos, você precisa considerar aspectos que são específicos para seu tipo de aplicativo. Por exemplo, se seu aplicativo usa controles de Windows, certifique estiverem do tamanho adequado e tem espaçamento suficiente para que os usuários podem toquem-los facilmente. Se você estiver criando um aplicativo pode tirar proveito de movimentos, certifique-se de que as ações de movimento são manipuladas corretamente.

Comecemos pelo princípio

Neste artigo, eu vai levar um exemplo de aplicativo de toque e aprimorar para aplicativos móveis. Suponho que você tenha algum conhecimento de COM e toque do Windows e tiver hardware compatível com o Windows toque. Para instruções elementares no Windows Touch, vá para go.microsoft.com/fwlink/?LinkId=156612 de ou ler o artigo de Yochay Kiriaty em msdn.microsoft.com/magazine/ee336016.aspx de .

O exemplo é no MSDN Code Gallery em code.msdn.microsoft.com/ windowstouchmanip de . Guia downloads contém dois arquivos .zip, a primeira sem aprimoramentos móveis e o segundo com eles. Baixar o arquivo chamado Manipulators.zip múltiplos, expandi-lo e compilar o projeto.

Para ser honesto, usando o exemplo é às vezes como tentar uma agulha de thread enquanto usando mittens: a funcionalidade é diminuída para um ponto frustrates usuários. Por exemplo, se você tentar selecionar objetos sobrepostos em uma região sobreposta, irá selecionar e mover os dois objetos. Você também pode redimensionar um objeto para que seja tão pequeno que não pode redimensioná-la novamente. Mostrarei como corrigir esses problemas e fazer outras alterações que aprimoram a experiência do usuário nas áreas de usabilidade geral, seleção de objeto e o uso de uma interface de usuário natural. Lembre-se de que fazer para cada aplicativo móvel considerações dependem como os usuários irão interagir com ele. Os problemas que tratarei aqui devem ser usados como diretrizes somente para este aplicativo específico.

Usabilidade geral

Quando um usuário está manipulando objetos gráficos em um aplicativo móvel, ele deve ser capaz de executar tarefas sem o uso de um teclado e mouse. Além disso, quando um usuário móvel está usando configurações de DPI altas ou conectado a várias telas, o aplicativo deve comportamento consistente. (Os requisitos de DPI alto são discutidos detalhadamente em go.microsoft.com/fwlink/?LinkId=153387 de ).

Para o aplicativo de exemplo implicitamente Windows Touch aborda o problema de obter entrada do usuário sem um mouse e teclado.  Os usuários podem usar para executar ações como a tradução de objeto de entrada por toque dimensionamento e assim por diante. Uma consideração relacionada está oferecendo suporte a mouse e teclado entrada em um aplicativo projetado para entrada por toque para que um usuário pode unidade o processador de manipulação usando qualquer entrada, incluindo entrada do mouse. Figura 1 mostra como você poderia deixar um usuário simular a entrada por toque através da entrada de mouse adicionando algumas funções de utilitário à classe Drawable do aplicativo de exemplo. Você também tem adicionar manipuladores para WndProc gancho entrada do mouse para o processador de entrada (consulte do Figura 2).

Figura 1 funções de utilitário para simulando Touch entrada com o mouse

VOID Drawable::FillInputData(TOUCHINPUT* inData, DWORD cursor, DWORD eType, DWORD time, int x, int y)
{
    inData->dwID = cursor;
    inData->dwFlags = eType;
    inData->dwTime = time;
    inData->x = x;
    inData->y = y;
}

void Drawable::ProcessMouseData(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
    lParam){
    TOUCHINPUT tInput;
    if (this->getCursorID() == MOUSE_CURSOR_ID){          
        switch (msg){
            case WM_LBUTTONDOWN:
                FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_DOWN, (DWORD)GetMessageTime(),LOWORD(lParam) * 100,HIWORD(lParam) * 100);
                ProcessInputs(hWnd, 1, &tInput, 0);
                break;

            case WM_MOUSEMOVE:
                if(LOWORD(wParam) == MK_LBUTTON)
                {
                    FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_MOVE, (DWORD)GetMessageTime(),LOWORD(lParam) * 100, HIWORD(lParam) * 100);
                    ProcessInputs(hWnd, 1, &tInput, 0);
                }          
                break;

            case WM_LBUTTONUP:
                FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_UP, (DWORD)GetMessageTime(),LOWORD(lParam) * 100, HIWORD(lParam) * 100);            
                ProcessInputs(hWnd, 1, &tInput, 0);
                setCursorID(-1);
                break;
            default:
                break;
        }   
    }     
}

Figura 2 alterações de WndProc

case WM_LBUTTONDOWN:
    case WM_MOUSEMOVE:   
    case WM_LBUTTONUP:
        for (i=0; i<drawables; i++){
          // contact start
          if (message == WM_LBUTTONDOWN && draw[i]->IsContacted(LOWORD(lParam), HIWORD(lParam), MOUSE_CURSOR_ID)){
              draw[i]->setCursorID(MOUSE_CURSOR_ID);
          }
          // contact end
          if (message == WM_LBUTTONUP && draw[i]->getCursorID() == MOUSE_CURSOR_ID){
            draw[i]->setCursorID(-1);      
          }
          draw[i]->ProcessMouseData(hWnd, message, wParam, lParam);
        }        
        InvalidateRect(hWnd, NULL, false);
        break;

Para atender aos requisitos de DPI altos, você pode adicionar um manifesto de projeto para as configurações de compilação para tornar o aplicativo ciente das configurações de PPP. Fazer isso para que o espaço de coordenadas é correto quando você estiver trabalhando em vários níveis de PPP. (Se você estiver interessado em ver como o aplicativo se comporta após ter alterado o nível de PPP, clique com o botão direito do mouse na área de trabalho, clique em Personalizar e alterar seu nível de PPP em vídeo no painel de controle.)

O XML a seguir mostra como esse manifesto poderia ser definido para tornar seu aplicativo compatível com configurações de DPI alto:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" 
   xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns=
"https://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

Depois que o manifesto de projeto é adicionado às propriedades do projeto, o aplicativo corretamente envia informações de entrada por toque para o processador de manipulação, independentemente das configurações de PPP do usuário. Você também pode usar o método ScreenToClient (consulte de go.microsoft.com/fwlink/?LinkID=153391 para obter mais informações) para garantir que o espaço de coordenadas é definido para as coordenadas do aplicativo em vez de para as coordenadas de tela. Figura 3 mostra as alterações para a função de membro ProcessInputs da classe Drawable converter os pontos de tela em pontos do cliente. Agora quando o usuário se conecta a um monitor externo para um PC de Touch–enabled Windows, o espaço de coordenadas de seu aplicativo permanecerão consistente e com reconhecimento de DPI.

Figura 3 Convertendo tela aponta para pontos cliente

POINT ptInput;
void Drawable::ProcessInputs(HWND hWnd, UINT cInputs, 
     PTOUCHINPUT pInputs, LPARAM lParam){
  for (int i=0; i < static_cast<INT>(cInputs); i++){
...
      ScreenToClient(hWnd, &ptInput);
                
      if (ti.dwFlags & TOUCHEVENTF_DOWN){
        if (IsContacted( ptInput.x, ptInput.y, ti.dwID) ){
          pManip->ProcessDownWithTime(ti.dwID, static_cast<FLOAT>
(ptInput.x), static_cast<FLOAT>( ptInput.y), ti.dwTime);                  
          setCursorID(ti.dwID);                  
            
          if (!CloseTouchInputHandle((HTOUCHINPUT)lParam)) {
            // Error handling                
          }
        }
      }
      if (pInputs[i].dwFlags & TOUCHEVENTF_MOVE){
        pManip->ProcessMoveWithTime(ti.dwID, static_cast<FLOAT>
(ptInput.x), static_cast<FLOAT>( ptInput.y), ti.dwTime);                  
      }
      if (pInputs[i].dwFlags & TOUCHEVENTF_UP){
        pManip->ProcessUpWithTime(ti.dwID, static_cast<FLOAT>
(ptInput.x), static_cast<FLOAT>( ptInput.y), ti.dwTime);
        setCursorID(-1);
      }      
      // If you handled the message and don’t want anything else done 
      // with it, you can close it
   
  }
}

Objeto Selection

Para garantir que objeto seleção funções como o usuário espera, o usuário deve poder selecionar os objetos sobrepostos de uma maneira natural e intuitiva e o usuário deve ser capaz de selecionar e transformar facilmente objetos em telas menores fatores de formulário ou telas com resolução de entrada por toque limitado.

Como o aplicativo atualmente opera, quando um usuário seleciona um objeto sobreposto, o aplicativo envia dados de toque para todos os objetos que estão sob o ponto onde o usuário toca a janela. Para modificar o aplicativo parar de tratamento de entrada após o primeiro objeto tocado encontrou por toque, você precisa fechar o identificador de entrada por toque quando um objeto selecionado. Figura 4 mostra como você pode atualizar o manipulador de entrada por toque para interromper a manipulação mensagem toque após o primeiro objeto é contatado.

Figura 4 Atualizando o manipulador de entrada Touch

POINT ptInput;
void Drawable::ProcessInputs(HWND hWnd, UINT cInputs, 
     PTOUCHINPUT pInputs, LPARAM lParam){
  BOOL fContinue = TRUE;
  for (int i=0; i < static_cast<INT>(cInputs) && fContinue; i++){
...                
      if (ti.dwFlags & TOUCHEVENTF_DOWN){
        if (IsContacted( ptInput.x, ptInput.y, ti.dwID) ){
          pManip->ProcessDownWithTime(ti.dwID, static_cast<FLOAT>
(ptInput.x), static_cast<FLOAT>(ptInput.y), ti.dwTime);                  
          setCursorID(ti.dwID);                  
            
          fContinue = FALSE;
        }
      }
...
  }
  CloseTouchInputHandle((HTOUCHINPUT)lParam);

}

Após implementar essa alteração, quando um objeto tocado é contatado, dados toque pára Obtendo enviadas para outros objetos na matriz. Alterar o aplicativo para que o primeiro objeto sob mouse entrada recebe toque entrada, você pode quebrar da opção entrada processamento instrução para mouse pressionada entrada, short-circuits lógica para entrada do mouse. Figura 5 demonstra as alterações para a instrução switch no manipulador de entrada de mouse.

Figura 5 alterando a declaração de alternar no manipulador de entrada do mouse

case WM_LBUTTONDOWN:
        for (i=0; i<drawables; i++){
          if (draw[i]->IsContacted(LOWORD(lParam), HIWORD(lParam), MOUSE_CURSOR_ID)){
              draw[i]->setCursorID(MOUSE_CURSOR_ID);
              draw[i]->ProcessMouseData(hWnd, message, wParam, lParam);   
              break;
          }
        }
...

Em seguida, você deve alterar seu aplicativo para garantir que quando um usuário redimensiona objetos, os objetos não ficará tão pequenos que o usuário não pode selecionar ou redimensioná-los novamente. Para resolver isso, você pode usar configurações API manipulações restringir pequena como um objeto pode ser dimensionado. As seguintes alterações são feitas para o utilitário de processador de manipulação de objeto Drawable:

void Drawable::SetUpManipulator(void){
  pManip->put_MinimumScaleRotateRadius(4000.0f);  
}

Agora quando você dimensiona um objeto, escala valores menores que 4.000 centipixels são ignorados pelo aplicativo. Cada objeto Drawable pode ter restrições exclusivas definidas no método SetUpManipulator para garantir que o objeto pode ser manipulado de forma apropriada.

Natural User Interface

Em um aplicativo projetado para ter uma aparência natural, um usuário deve ser capaz de executar manipulações simultâneas em vários objetos. Objetos devem ter física simples quando estiver movidos pela tela, semelhante a como se comportam no mundo real, e o usuário deve ser capaz de manipular objetos fora da tela.

Por design, aplicativos que usam API manipulações devem dar suporte a manipulação simultânea de objetos. Porque este exemplo usa a API de manipulação, manipulações simultâneas são habilitadas automaticamente. Quando você usa o suporte API de gestos para Windows Touch, simultâneo manipulação de objetos não é possível e gestos compostos como panorâmica + zoom e zoom + girar não são tanto. Por esse motivo, você deve usar a API manipulações quando você está criando um aplicativo Windows Touch destinos PCs móveis.

API do Windows Touch inclui interface IInertiaProcessor para habilitar o suporte simples física (inércia). IInertiaProcessor usa alguns dos mesmos métodos como interface IManipulationProcessor para simplificar a adicionar suporte para inércia para aplicativos que já estão usando manipulações. Para habilitar o suporte inércia, você precisa estender o coletor de eventos existente para o processador de manipulação, adicione uma referência a uma instância de interface IInertiaProcessor no objeto Drawable, conectar dados de evento do coletor de eventos para o objeto IInertiaProcessor e use um timer para acionar a interface IInertiaProcessor para eventos de manipulação de disparador para inércia. Let’s examinar cada operação em mais detalhes.

Primeiro você precisa atualizar o coletor de eventos para ativar o suporte para o envio de dados para uma interface IInertiaProcessor. Os seguintes membros e as definições de construtor são adicionadas para o cabeçalho de implementação do coletor de evento:

class CManipulationEventSink : _IManipulationEvents
{
public:
    CManipulationEventSink(IInertiaProcessor *inert, Drawable* d);
    CManipulationEventSink(IManipulationProcessor *manip, IInertiaProcessor *inert, Drawable* d);

...
protected:
    IInertiaProcessor*      m_pInert;
    BOOL fExtrapolating;

Você também adicionar um membro e um método de acesso para o coletor de eventos para definir um HWND é usado para timers, como mostrado aqui:
pública:

void SetWindow(HWND hWnd) {m_hWnd = hWnd;}
...
private:
...
HWND m_hWnd;

Em seguida, alterar o construtor que leva uma interface IManipulationProcessor para aceitar uma interface IInertiaProcessor e adicionar um construtor que aceita somente uma interface IInertiaProcessor. O construtor que leva uma interface IManipulationProcessor usa a referência para a interface IInertiaProcessor para disparar inércia a partir do evento ManipulationCompleted. O construtor que leva apenas um IInertiaProcessor interface alças eventos que são inércia. Figura 6 mostra as implementações esses construtores.

Figura 6 do implementações de IManipulationProcessor e construtores de IInertiaProcesor

CManipulationEventSink::CManipulationEventSink(IManipulationProcessor *manip, IInertiaProcessor *inert, Drawable* d){
    drawable = d;
    // Yes, we are extrapolating inertia in this case
    fExtrapolating = false;

    //Set initial ref count to 1
    m_cRefCount = 1;

    m_pManip = NULL;
    m_pInert = inert;    

    m_cStartedEventCount = 0;
    m_cDeltaEventCount = 0;
    m_cCompletedEventCount = 0;

    HRESULT hr = S_OK;

    //Get the container with the connection points
    IConnectionPointContainer* spConnectionContainer;
    
    hr = manip->QueryInterface(
      IID_IConnectionPointContainer, 
      (LPVOID*) &spConnectionContainer
      );

    if (spConnectionContainer == NULL){
        // Something went wrong, try to gracefully quit        
    }

    //Get a connection point
    hr = spConnectionContainer->FindConnectionPoint
(__uuidof(_IManipulationEvents), &m_pConnPoint);

    if (m_pConnPoint == NULL){
        // Something went wrong, try to gracefully quit
    }

    DWORD dwCookie;

    //Advise
    hr = m_pConnPoint->Advise(this, &dwCookie);
}
CManipulationEventSink::CManipulationEventSink(IInertiaProcessor *inert, Drawable* d)
{
    drawable = d;
    // Yes, we are extrapolating inertia in this case
    fExtrapolating = true;

    //Set initial ref count to 1
    m_cRefCount = 1;

    m_pManip = NULL;
    m_pInert = inert;    

    m_cStartedEventCount = 0;
    m_cDeltaEventCount = 0;
    m_cCompletedEventCount = 0;

    HRESULT hr = S_OK;

    //Get the container with the connection points
    IConnectionPointContainer* spConnectionContainer;
    
    hr = inert->QueryInterface(
      IID_IConnectionPointContainer, 
      (LPVOID*) &spConnectionContainer
      );

    if (spConnectionContainer == NULL){
        // Something went wrong, try to gracefully quit        
    }

    //Get a connection point
    hr = spConnectionContainer->FindConnectionPoint
(__uuidof(_IManipulationEvents), &m_pConnPoint);
    if (m_pConnPoint == NULL){
        // Something went wrong, try to gracefully quit
    }

    DWORD dwCookie;

    //Advise
    hr = m_pConnPoint->Advise(this, &dwCookie);

Em seguida, atualizar a classe Drawable para habilitar o suporte inércia. A definição direta mostrada do Figura 7 deve ser adicionada, bem como uma variável de membro pInert.

Figura 7 Atualizando Class Drawable

interface IInertiaProcessor;
public:
...
    // Inertia Processor Initiation
    virtual void SetUpInertia(void);

...
protected:

    HWND m_hWnd;
    
    IManipulationProcessor* pManip;
    IInertiaProcessor*      pInert;
    CManipulationEventSink* pEventSink;

O código a seguir mostra a implementação mais simples para o método SetUpInertia. Esse método termina qualquer processamento, redefine o processador inércia e define todas as configurações:

void Drawable::SetUpInertia(void){
    // Complete any previous processing
    pInert->Complete();

    pInert->put_InitialOriginX(originX*100);
    pInert->put_InitialOriginY(originY*100);
       
    // Configure the inertia processor
    pInert->put_DesiredDeceleration(.1f);  
}

Após atualizar a classe Drawable, altere o construtor Drawable para incorporar os construtores de coletor de evento novo, como mostrado no do Figura 8.

Figura 8 Incorporando o novo evento Sink Constructors

Drawable::Drawable(HWND hWnd){
. . 
  
    // Initialize manipulators  
    HRESULT hr = CoCreateInstance(CLSID_ManipulationProcessor,
          NULL,
          CLSCTX_INPROC_SERVER,
          IID_IUnknown,
          (VOID**)(&pManip)
    );

    // Initialize inertia processor
    hr = CoCreateInstance(CLSID_InertiaProcessor,
          NULL,
          CLSCTX_INPROC_SERVER,
          IID_IUnknown,
          (VOID**)(&pInert)
    );

    //TODO: test HR 
    pEventSink = new CManipulationEventSink(pManip,pInert, this);
    pInertSink = new CManipulationEventSink(pInert, this);
    pEventSink->SetWindow(hWnd);
    pInertSink->SetWindow(hWnd);

    SetUpManipulator();
    SetUpInertia();
    m_hWnd = hWnd;
}

E agora, adicione o seguinte manipulador de mensagem do timer para o programa principal:

case WM_TIMER:
        // wParam indicates the timer ID
        for (int i=0; i<drawables; i++){
            if (wParam == draw[i]->GetIndex() ){
                BOOL b;       
                draw[i]->ProcessInertia(&b);        
            }
        }
    break;

Depois de ter seu manipulador de timer e seu timer é configurado, você precisará dispará-lo de mensagem concluída em evento onde não há nenhum inércia. Figura 9 mostra as alterações para o evento concluído que iniciar o timer quando o usuário é terminado manipular um objeto e parar o timer de uma vez concluída a inércia.

Figura 9 do alterações para o evento concluído

HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationCompleted( 
    /* [in] */ FLOAT x,
    /* [in] */ FLOAT y,
    /* [in] */ FLOAT cumulativeTranslationX,
    /* [in] */ FLOAT cumulativeTranslationY,
    /* [in] */ FLOAT cumulativeScale,
    /* [in] */ FLOAT cumulativeExpansion,
    /* [in] */ FLOAT cumulativeRotation)
{
    m_cCompletedEventCount ++;

    m_fX = x;
    m_fY = y;


    if (m_hWnd){
        if (fExtrapolating){
            //Inertia Complete, stop the timer used for processing
            KillTimer(m_hWnd,drawable->GetIndex());
        }else{ 
            // Setup velocities for inertia processor
            float vX, vY, vA = 0.0f;
            m_pManip->GetVelocityX(&vX);
            m_pManip->GetVelocityY(&vY);
            m_pManip->GetAngularVelocity(&vA);

            drawable->SetUpInertia();

            // Set up the touch coordinate data
            m_pInert->put_InitialVelocityX(vX / 100);
            m_pInert->put_InitialVelocityY(vY / 100);        
                          
            // Start a timer
            SetTimer(m_hWnd, drawable->GetIndex(), 50, 0);   
    
            // Reset sets the initial timestamp
            pInert->Reset();     
        }
    }
}

Observe que reduzir o intervalo de timer, o terceiro parâmetro SetTimer, resulta em mais suave animação mas disparadores mais atualiza eventos, potencialmente causando degradação de desempenho dependendo quais operações manipuladores de evento executar. Por exemplo, alterando este valor para 5 resulta na animação suave muito, mas a janela é atualizada com mais freqüência devido adicionais chamadas para CManipulationEventSink::ManipulationDelta.

Agora você pode criar e executar seu aplicativo, mas sem alterações adicionais, irão migrar objetos manipulated fora da tela. Para impedir que objetos manipulados fora da tela, configure a interface IInertiaProcessor para usar limites Elástico. Figura 10 mostra as alterações que devem ser feitas para o método SetUpInertia para o objeto Drawable inicializar os limites de tela.

Figura 10 Inicializando limites de tela

void Drawable::SetUpInertia(void){
(...)
            
    // Reset sets the  initial timestamp       
    pInert->put_DesiredDeceleration(.1f);

    RECT rect;
    GetClientRect(m_hWnd, &rect);        

    int width = rect.right - rect.left;
    int height = rect.bottom - rect.top;

    int wMargin = width  * .1;
    int hMargin = height * .1;

    pInert->put_BoundaryLeft(rect.left * 100);
    pInert->put_BoundaryTop(rect.top * 100);
    pInert->put_BoundaryRight(rect.right * 100);
    pInert->put_BoundaryBottom(rect.bottom * 100);

    pInert->put_ElasticMarginTop((rect.top - hMargin) * 100);
    pInert->put_ElasticMarginLeft((rect.left + wMargin) * 100);
    pInert->put_ElasticMarginRight((rect.right - wMargin) * 100);
    pInert->put_ElasticMarginBottom((rect.bottom + hMargin) * 100);

...
}

Olhando para o futuro

Usando a API de toque do Windows é uma maneira eficaz para adicionar valor a aplicativos existentes e é uma ótima maneira de tornar seus aplicativos destacar. Levando tempo extra para o contexto de endereço que seu aplicativo será usado em permite fazer a maioria da API de toque do Windows. Se você levar em consideração os requisitos de usabilidade do seu aplicativo e mobilidade, o aplicativo se torna mais intuitivo e os usuários precisam de menos tempo para descobrir sua funcionalidade. (Recursos adicionais, incluindo referência documentação completa para Windows Touch, podem ser encontrados no MSDN em de .aspx msdn.microsoft.com/library/dd562197 (VS.85) ).

Com o lançamento do WPF (Windows Presentation Framework) e .NET 4, Microsoft irá oferece suporte a desenvolvimento gerenciado usando controles que permitem que vários pontos de contatos. Se você for um desenvolvedor trabalhar com código gerenciado procurando melhorar seu aplicativo com suporte de entrada de vários, esse lançamento vale check-out. Atualmente, exemplos de invólucros gerenciados para translation from VPE for Csharp Windows Touch estão incluídos no SDK do Windows.

Gus “gclassy” Class é um escritor/divulgador programação Microsoft, onde ele trabalhou em Windows Touch, do TABLETPC e DRMsystems da Microsoft. Ele discute armadilhas de desenvolvedor e oferece exemplos de programação em seu blog em gclassy.comde .

Graças aos seguinte especialista técnico para revisar este artigo: Xiao Tu

Envie suas dúvidas e comentários para Gus de goplaces@microsoft.com.