1

次の WP7 アプリ (Vb.NET で記述) で MVVM の機能を改善しようとしています。フォーカスが与えられ、WP7 キーボードが表示されているテキスト ボックスがあります。コマンド バインディングと xyzzer のバインド可能なアプリケーション バー (これは優れています) を使用しています。

http://bindableapplicationb.codeplex.com/

フォームにフォーカスを設定することで、ViewModel から TextBox のフォーカスをキャンセルできるようにしたいと考えています。通常(非MVVM)、フォーム内から次のように呼び出してこれを行います。

  Me.Focus()

しかし、ViewModel からこれを行うことはできません (すべきではありません)。現時点では、ViewModel からイベントを発生させ、フォームでキャッチしていますが、厄介です。MVVMフレンドリーな方法はありますか? vb.net の例が限られているため、ツールキットを使用したことはありません。

コマンドバインディングを使用しています。

4

3 に答える 3

2

推測してみましょう: 問題は、ApplicationBarIconButton をクリックしたときに、TextBox が ViewModel のバインドされたプロパティをまだ更新していないことですよね?

Cimbalino Windows Phone Toolkitの ApplicationBarBehavior を使用して( NuGetからも取得できます)、これを内部で処理します。そのため、ApplicationBarIconButton クリック イベントが完了する前に、TextBox.Text バインド プロパティが既に更新されています。

GitHub のサンプル コードを確認してください。使用する準備はすべて整っています。

編集:

ページにフォーカスを設定することだけが必要な場合 (したがって、TextBox がフォーカスを失った後にキーボードを閉じる場合)、外部クラスを使用してジョブを実行し、それを ViewModel で使用します。次のようになります。

//This is the service interface
public interface IPageService
{
    void Focus();
}
//This implements the real service for runtime 
public class PageService : IPageServiceusage
{
    public void Focus()
    {
        var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;

        if (rootFrame == null)
            return;

        var page = rootFrame.Content as PhoneApplicationPage;

        if (page == null)
            return;

        page.Focus();
    }
}

//This implements the mockup service for testing purpose
public class PageServiceMockup : IPageService
{
    public void Focus()
    {
        System.Diagnostics.Debug.WriteLine("Called IPageService.Focus()");
    }
}

次に、ViewModel で、次のようなサービスのインスタンスを作成します。

public class MyViewModel
{
    private IPageService _pageService;

    public MyViewModel()
    {
#if USE_MOCKUP
        _pageService = new PageServiceMockup();
#else
        _pageService = new PageService();
#endif
    }
}

ページにフォーカスを設定したい場合は、 を呼び出すだけ_pageService.Focus()です。

これは、問題を解決するための完全に MVVM 化された方法です!

于 2012-04-15T21:26:25.123 に答える
2

ビヘイビアを使用して試すことができます:

public class FocusBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            AssociatedObject.GotFocus += (sender, args) => IsFocused = true;
            AssociatedObject.LostFocus += (sender, a) => IsFocused = false;
            AssociatedObject.Loaded += (o, a) => { if (HasInitialFocus || IsFocused) AssociatedObject.Focus(); };

            base.OnAttached();
        }

        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.Register(
                "IsFocused",
                typeof (bool),
                typeof (FocusBehavior),
                new PropertyMetadata(false, (d, e) => { if ((bool) e.NewValue) ((FocusBehavior) d).AssociatedObject.Focus(); }));

        public bool IsFocused
        {
            get { return (bool) GetValue(IsFocusedProperty); }
            set { SetValue(IsFocusedProperty, value); }
        }

        public static readonly DependencyProperty HasInitialFocusProperty =
            DependencyProperty.Register(
                "HasInitialFocus",
                typeof (bool),
                typeof (FocusBehavior),
                new PropertyMetadata(false, null));

        public bool HasInitialFocus
        {
            get { return (bool) GetValue(HasInitialFocusProperty); }
            set { SetValue(HasInitialFocusProperty, value); }
        }
    }

次にxamlで:

 <TextBox>
            <i:Interaction.Behaviors>
                <behaviors:FocusBehavior HasInitialFocus="True"
                                         IsFocused="{Binding IsFocused}" />
            </i:Interaction.Behaviors>
        </TextBox>
于 2012-04-15T22:44:31.863 に答える
0

Pedros の例と、以前アプリに実装した他のサービスを使用して、vb.net で次のソリューションをまとめました。

IFocus インターフェイスを作成します。このインターフェイスは、フォーカス サービスまたはモックによって実装できます。

Public Interface IFocusInterface
    Sub Focus()
End Interface

IFocusable インターフェイスを作成します。これは ViewModel によって実装され、IFocusInterface を実装するオブジェクトを受け入れます。

Public Interface IFocusable
    Property FocusService As IFocusInterface
End Interface

シングルトン パターンを使用してフォーカス インターフェイスを実装する

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

ViewModel で IFocusable を実装し、ViewModel が構築された後にフォーカス サービス シングルトンを ViewModel に渡すようにしてください。

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
于 2012-04-26T21:54:32.340 に答える