Search code examples
vb.netwindows-phone-7mvvmvb.net-2010windows-phone-7.1.1

WP7 MVVM how do I call me.setfocus() from the ViewModel?


I'm attempting to improve my MVVM abilities in my next WP7 App (which is written in Vb.NET). I have a textbox that has been given focus and has a WP7 keyboard displayed. I am using command binding and a xyzzer's bindable Application bar (which is excellent).

http://bindableapplicationb.codeplex.com/

I want to be able to cancel the focus of the TextBox from the ViewModel, by setting focus on the form. Normally (Non MVVM) I would do this from within the form by calling:

  Me.Focus()

But I can't do this from the ViewModel (and I shouldn't). At the moment I am raising an event out of the ViewModel and catching it on the form but its nasty. Is there a MVVM Friendly way of doing it? I haven't been using a Toolkit so far as there are limited examples in vb.net.

I have been using command binding.


Solution

  • Using Pedros example, and the other services I have previously implemented in my App I put together the following solution in vb.net:

    Create an IFocus Interface, This Interface can be implemented by the focus service or a Mock

    Public Interface IFocusInterface
        Sub Focus()
    End Interface
    

    Create a IFocusable Interface. This will be implemented by the ViewModel and accepts an object that implements IFocusInterface.

    Public Interface IFocusable
        Property FocusService As IFocusInterface
    End Interface
    

    Implement the Focus Interface with a singleton pattern

    Imports Microsoft.Phone.Controls
    
    Public NotInheritable Class FocusService
        Implements IFocusInterface
    
        Private Sub New()
        End Sub
    
        Private Shared ReadOnly m_instance As New FocusService
        Public Shared ReadOnly Property Instance() As FocusService
            Get
                Return m_instance
            End Get
        End Property
    
        Public Sub Focus() Implements IFocusInterface.Focus
            Dim rootFrame = TryCast(Application.Current.RootVisual, PhoneApplicationFrame)
            If Not rootFrame Is Nothing Then
    
                Dim page = TryCast(rootFrame.Content, PhoneApplicationPage)
    
                If Not page Is Nothing Then
                    page.Focus()
                Else
                    Throw New Exception("Unable to Cast the Root Frame Content into an Application Page")
                End If
    
            Else
                Throw New Exception("Unable to Cast the RootVisual into a PhoneApplicationFrame")
            End If
    
        End Sub
    
    End Class
    

    In your ViewModel Implement IFocusable, and make sure you pass in the Focus Service Singleton into the ViewModel after the ViewModel is Constructed.

    Public Class MyViewModel
        Implements INotifyPropertyChanged
        Implements IFocusable
    
        ' Property for the Focus Service
        <Xml.Serialization.XmlIgnore()> Public Property FocusService As IFocusInterface Implements IFocusable.FocusService
    
        Public Sub Focus()
            If Not FocusService Is Nothing Then
                FocusService.Focus()
            Else
                Throw New Exception("ViewModel hasn't been passed a Focus Service")
            End If
        End Sub
    
    End Class
    
    Dim tMyViewModel as New MyViewModel
    tMyViewModel.FocusService = Vacation_Calc_Model.FocusService.Instance