ビューモデルからWPFのTextBoxにフォーカスを設定します


129

私にはa TextBoxとa があるとButton思います。

ボタンのクリック時に条件を確認し、条件がfalseであることが判明した場合は、ユーザーにメッセージを表示してから、カーソルをTextBoxコントロールに設定する必要があります。

if (companyref == null)
{
    var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation(); 

    MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);

    cs.txtCompanyID.Focusable = true;

    System.Windows.Input.Keyboard.Focus(cs.txtCompanyID);
}

上記のコードはViewModelにあります。

CompanyAssociationビュー名です。

しかし、カーソルはに設定されていませんTextBox

xamlは次のとおりです。

<igEditors:XamTextEditor Name="txtCompanyID" 
                         KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
                         ValueChanged="txtCompanyID_ValueChanged"
                         Text="{Binding Company.CompanyId,
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}"
                         Width="{Binding ActualWidth, ElementName=border}"
                         Grid.Column="1" Grid.Row="0"
                         VerticalAlignment="Top"
                         HorizontalAlignment="Stretch"
                         Margin="0,5,0,0"
                         IsEnabled="{Binding Path=IsEditable}"/>

<Button Template="{StaticResource buttonTemp1}"
        Command="{Binding ContactCommand}"
        CommandParameter="searchCompany"
        Content="Search"
        Width="80"
        Grid.Row="0" Grid.Column="2"
        VerticalAlignment="Top"
        Margin="0"
        HorizontalAlignment="Left"
        IsEnabled="{Binding Path=IsEditable}"/>

caliburn.microを使用している場合、これは優れたソリューションです。
matze8426 2018

回答:


264

3つの部分であなたの質問に答えさせてください。

  1. あなたの例では「cs.txtCompanyID」とは何ですか?TextBoxコントロールですか?はいの場合、あなたは間違った方向に進んでいます。一般的に言えば、ViewModelでUIへの参照を持つことはお勧めできません。「なぜ?」と尋ねることができます。しかし、これはStackoverflowに投稿するもう1つの質問です:)。

  2. Focusの問題を追跡する最良の方法は... .Netソースコードをデバッグすることです。冗談ではありません。多くの時間を節約できました。.netソースコードのデバッグを有効にするには、Shawn Brukeのブログを参照してください。

  3. 最後に、ViewModelからフォーカスを設定するために使用する一般的なアプローチは、添付プロパティです。任意のUIElementで設定できる非常に単純な添付プロパティを作成しました。また、たとえばViewModelのプロパティ「IsFocused」にバインドできます。ここにあります:

    public static class FocusExtension
    {
        public static bool GetIsFocused(DependencyObject obj)
        {
            return (bool) obj.GetValue(IsFocusedProperty);
        }
    
        public static void SetIsFocused(DependencyObject obj, bool value)
        {
            obj.SetValue(IsFocusedProperty, value);
        }
    
        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached(
                "IsFocused", typeof (bool), typeof (FocusExtension),
                new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
    
        private static void OnIsFocusedPropertyChanged(
            DependencyObject d, 
            DependencyPropertyChangedEventArgs e)
        {
            var uie = (UIElement) d;
            if ((bool) e.NewValue)
            {
                uie.Focus(); // Don't care about false values.
            }
        }
    }

    これで(XAMLの)ビューで、このプロパティをViewModelにバインドできます。

    <TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />

お役に立てれば :)。それが答えを参照していない場合#2。

乾杯。


5
クールなアイデア。これを機能させるには、IsUserNameFocusedをtrueに設定してから、もう一度falseに設定する必要があります。これは正しいですか?
サム

19
コントロールにキーボードフォーカスと論理フォーカスを受け取る場合もKeyboard.Focus(uie);OnIsFocusedPropertyChangedイベントから呼び出す必要があります
Rachel

6
これはどのように使用されることになっていますか?プロパティをtrueに設定すると、コントロールがフォーカスされます。しかし、私がこの見方に戻ったとき、それは常に再び焦点を合わせます。OnIsFocusedPropertyChangedからリセットしても、これは変わりません。ViewModelから設定した直後にリセットすると、何もフォーカスされなくなります。動かない。70人の賛成者は正確に何をしましたか?
ygoe 2013

4
コールバックもこれに変更しました...if ((bool)e.NewValue && uie.Dispatcher != null) { uie.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => uie.Focus())); // invoke behaves nicer, if e.g. you have some additional handler attached to 'GotFocus' of UIE. uie.SetValue(IsFocusedProperty, false); // reset bound value if possible, to allow setting again ... 。フォーカスを複数回設定する場合は、ViewModelで「IsFocused」をfalseにリセットする必要がある場合もあります。しかし、それは機能し、他のいくつかの方法が失敗しました。
Simon D.

3
フォーカスを設定して別のコントロールがフォーカスを取得した後は、IsFocusedがまだtrueであるため、再度フォーカスを設定することはできません。強制的にfalseにしてからtrueにする必要があります。public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
ウォルターファン

75

この質問は今までに1000回以上回答されていますが、私と同様の問題を抱えていた他の人を助けるためにアンバカの貢献をいくつか編集しました。

まず、上記の添付プロパティを次のように変更しました。

public static class FocusExtension
{
    public static readonly DependencyProperty IsFocusedProperty = 
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true});

    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        return (bool?)element.GetValue(IsFocusedProperty);
    }

    public static void SetIsFocused(DependencyObject element, bool? value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        element.SetValue(IsFocusedProperty, value);
    }

    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)d;

        if (e.OldValue == null)
        {
            fe.GotFocus += FrameworkElement_GotFocus;
            fe.LostFocus += FrameworkElement_LostFocus;
        }

        if (!fe.IsVisible)
        {
            fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
        }

        if ((bool)e.NewValue)
        {
            fe.Focus();
        }
    }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)sender;
        if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
        {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
        }
    }

    private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, true);
    }

    private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, false);
    }
}

可視性参照を追加した理由はタブでした。どうやら、最初に表示されていたタブ以外のタブで添付プロパティを使用した場合、手動でコントロールにフォーカスするまで、添付プロパティは機能しませんでした。

もう1つの障害は、基になるプロパティがフォーカスを失ったときにfalseにリセットするよりエレガントな方法を作成することでした。フォーカスが失われたイベントが発生したのはここです。

<TextBox            
    Text="{Binding Description}"
    FocusExtension.IsFocused="{Binding IsFocused}"/>

可視性の問題を処理するより良い方法がある場合は、お知らせください。

注:BindsTwoWayByDefaultをDependencyPropertyに配置することを提案してくれたApfelkuachaに感謝します。私はずっと前に自分のコードでそれを行っていましたが、この投稿を更新したことはありません。この変更により、WPFコードではMode = TwoWayは不要になりました。


9
これは、GotFocus / LostFocusに「if(e.Source == e.OriginalSource)」チェックを追加する必要があることを除いて、うまく機能します。成分。.Focus()メソッドと同じように機能するという事実を受け入れて、Visibleチェックを削除しました。.Focus()が機能しない場合、バインディングは機能しないはずです。これは私のシナリオでは問題ありません。
HelloSam 2013年

1
これをWF 4.5で使用しています。IsFocusedChangedで、e.NewValueがnullで例外をスローするシナリオ(アクティビティがリロードされる)があるので、最初に確認してください。この小さな変更ですべてがうまくいきます。
Olaru Mircea

1
このwprksに感謝:)「FrameworkPropertyMetadata」に「{BindsTwoWayByDefault = true}」を追加して、デフォルトモードをTwoWayBindingに設定したため、すべてのバインディングで必要ではありません
R00st3r

1
これは古い答えですが、フォーカスを移動したいコントロールのIsEnabledプロパティが多値コンバーターに関連付けられている状況に遭遇しています。どうやら、GotFocusイベントハンドラーは複数値コンバーターが呼び出される前に呼び出されます...つまり、その時点でコントロールは無効になっているため、GotFocusが完了するとすぐにLostFocusが呼び出されます(コントロールがまだ無効であるためと思います)。 。それをどのように処理するかについての考えはありますか?
Mark Olbert

1
@MarkOlbert fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);は、ロード後に更新されることを使用します。詳細はこちら:telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha

32

私はMVVMの原則をクリーンに保つのが最善の方法だと思うので、基本的にはMVVMライトで提供されるメッセンジャークラスを使用する必要があり、その使用方法を次に示します。

あなたのviewmodel(exampleViewModel.cs)で:次のように書いてください

 Messenger.Default.Send<string>("focus", "DoFocus");

View.cs(XAMLではなくview.xaml.cs)で、コンストラクタに次のように記述します

 public MyView()
        {
            InitializeComponent();

            Messenger.Default.Register<string>(this, "DoFocus", doFocus);
        }
        public void doFocus(string msg)
        {
            if (msg == "focus")
                this.txtcode.Focus();
        }

その方法は問題なく機能し、少ないコードでMVVM標準を維持します


9
まあ、MVVMの原則を明確に保ちたいのであれば、そもそもコードの後ろにコードを書くことはないでしょう。添付プロパティのアプローチははるかにきれいだと思います。ビューモデルにも多くの魔法の文字列は導入されていません。
ΕГИІИО

32
エルニーニョ:ビューのコードビハインドには何もあるべきではないという考えを正確にどこで得ましたか?UIに関連するものはすべて、ビューの分離コードに含める必要があります。UI要素のフォーカスを設定することは、間違いなくビューのコードビハインドにある必要があります。メッセージを送信するタイミングをviewmodelが把握できるようにします。ビューでメッセージの処理方法を把握します。それがMV-VMの機能です。データモデル、ビジネスロジック、UIの懸念を分離します。
カイル・ヘイル、

この提案に基づいて、接続されたビューでのコマンドの呼び出しを処理する独自のViewCommandManagerを実装しました。これは基本的に、通常のコマンドのもう1つの方向です。これらの場合、ViewModelがそのビューでアクションを実行する必要がある場合です。データバインドコマンドやWeakReferencesなどのリフレクションを使用して、メモリリークを回避します。dev.unclassified.de/source/viewcommand(これもCodeProjectにあります)
ygoe

このメソッドを使用して、WPF FlowDocumentsを出力しました。うまくいきました。ありがとう
Gordon Slysz 2014年

Silverlightで必要ですか?使えますか?
Bigeyes 2017年

18

これらはどれも正確には機能しませんでしたが、他の人の利益のために、ここにすでに提供されているコードの一部に基づいてこれを記述しました。

使用法は次のようになります。

<TextBox ... h:FocusBehavior.IsFocused="True"/>

そして実装は次のようになります:

/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
    #region Dependency Properties
    /// <summary>
    /// <c>IsFocused</c> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
            typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
    /// <summary>
    /// Gets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        return (bool?)element.GetValue(IsFocusedProperty);
    }
    /// <summary>
    /// Sets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <param name="value">The value.</param>
    public static void SetIsFocused(DependencyObject element, bool? value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(IsFocusedProperty, value);
    }
    #endregion Dependency Properties

    #region Event Handlers
    /// <summary>
    /// Determines whether the value of the dependency property <c>IsFocused</c> has change.
    /// </summary>
    /// <param name="d">The dependency object.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = d as FrameworkElement;
        if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue)
        {
            // Attach to the Loaded event to set the focus there. If we do it here it will
            // be overridden by the view rendering the framework element.
            fe.Loaded += FrameworkElementLoaded;
        }
    }
    /// <summary>
    /// Sets the focus when the framework element is loaded and ready to receive input.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
    private static void FrameworkElementLoaded(object sender, RoutedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = sender as FrameworkElement;
        if (fe != null)
        {
            // Remove the event handler registration.
            fe.Loaded -= FrameworkElementLoaded;
            // Set the focus to the given framework element.
            fe.Focus();
            // Determine if it is a text box like element.
            var tb = fe as TextBoxBase;
            if (tb != null)
            {
                // Select all text to be ready for replacement.
                tb.SelectAll();
            }
        }
    }
    #endregion Event Handlers
}

11

これは古いスレッドですが、Anavankaの承認された回答の問題に対処するコードでの回答はないようです。viewmodelのプロパティをfalseに設定した場合、またはプロパティをに設定した場合は機能しませんtrue、ユーザーが手動で別の場所をクリックした後、もう一度trueに設定します。これらの場合でも、Zamoticのソリューションを確実に機能させることができませんでした。

上記の議論のいくつかをまとめると、私が思うこれらの問題に対処する以下のコードが得られます:

public static class FocusExtension
{
    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }

    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new UIPropertyMetadata(false, null, OnCoerceValue));

    private static object OnCoerceValue(DependencyObject d, object baseValue)
    {
        if ((bool)baseValue)
            ((UIElement)d).Focus();
        else if (((UIElement) d).IsFocused)
            Keyboard.ClearFocus();
        return ((bool)baseValue);
    }
}

とは言っても、コードビハインドの1行で実行できることについては、これはまだ複雑であり、CoerceValueは実際にはこのように使用することを意図していないため、おそらくコードビハインドが進むべき道です。


1
これは一貫して機能しますが、受け入れられた回答は機能しません。ありがとう!
NathanAldenSr 2016年

4

私の場合、メソッドOnIsFocusedPropertyChangedを変更するまで、FocusExtensionは機能しませんでした。ブレークポイントがプロセスを停止したとき、元のバージョンはデバッグでのみ機能していました。実行時には、プロセスが速すぎて何も起こりませんでした。この小さな変更と友人のタスクの助けにより、これは両方のシナリオで正常に機能しています。

private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var uie = (UIElement)d;
  if ((bool)e.NewValue)
  {
    var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus())));
    Task.Factory.StartNew(action);
  }
}

3

問題は、IsUserNameFocusedがtrueに設定されると、決してfalseにならないことです。これは、FrameworkElementのGotFocusとLostFocusを処理することで解決します。

ソースコードのフォーマットに問題があったので、ここにリンクがあります


1
「object fe =(FrameworkElement)d;」を変更しました 「FrameworkElement fe =(FrameworkElement)d;」へ したがって、インテリセンスは機能します

それでも問題は解決しません。要素は、戻ってくるたびに集中し続けます。
ygoe 2013

3

Anvakasの素晴らしいコードは、Windowsデスクトップアプリケーション用です。あなたが私のようなもので、Windowsストアアプリに同じソリューションが必要な場合、このコードは便利です。

public static class FocusExtension
{
    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }


    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }


    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new PropertyMetadata(false, OnIsFocusedPropertyChanged));


    private static void OnIsFocusedPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue)
        {
            var uie = d as Windows.UI.Xaml.Controls.Control;

            if( uie != null )
            {
                uie.Focus(FocusState.Programmatic);
            }
        }
    }
}

1

上記のAnvakaのソリューションを使用しようとした場合、lostfocusがプロパティをfalseに更新しないため、バインディングが最初にしか機能しないという問題がありました。プロパティを手動でfalseに設定してから、毎回trueに設定できますが、より良い解決策は、プロパティで次のようなことを行うことです。

bool _isFocused = false;
    public bool IsFocused 
    {
        get { return _isFocused ; }
        set
        {
            _isFocused = false;
            _isFocused = value;
            base.OnPropertyChanged("IsFocused ");
        }
    }

この方法では、これをtrueに設定するだけでよく、フォーカスされます。


なぜif文があるのですか?_isFocusedがfalseに設定されると、次の行の値に変更されるだけです。
Damien McGivern、2011年

1
@Tyrsiusこの問題は、依存関係プロパティをCoerceに取得することで丸めることができます。here
social.msdn.microsoft.com/Forums/

1

私はWPF / Caliburn Microを使用していますが、「dfaivre」が一般的で実用的なソリューションをここで作成していることがわかりました:http ://caliburnmicro.codeplex.com/discussions/222892


1

以下のようにコードを編集することで解決策を見つけました。Bindingプロパティを最初にFalse、次にTrueに設定する必要はありません。

public static class FocusExtension
{

    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }


    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }


    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));


    private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d != null && d is Control)
        {
            var _Control = d as Control;
            if ((bool)e.NewValue)
            {
                // To set false value to get focus on control. if we don't set value to False then we have to set all binding
                //property to first False then True to set focus on control.
                OnLostFocus(_Control, null);
                _Control.Focus(); // Don't care about false values.
            }
        }
    }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
    {
        if (sender != null && sender is Control)
        {
            (sender as Control).SetValue(IsFocusedProperty, false);
        }
    }
}

0

Silverlightの場合:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace MyProject.Behaviors
{
    public class FocusBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.Loaded += AssociatedObject_Loaded;
            base.OnAttached();
        }

        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
            if (this.HasInitialFocus || this.IsFocused)
            {
                this.GotFocus();
            }
        }

        private void GotFocus()
        {
            this.AssociatedObject.Focus();
            if (this.IsSelectAll)
            {
                if (this.AssociatedObject is TextBox)
                {
                    (this.AssociatedObject as TextBox).SelectAll();
                }
                else if (this.AssociatedObject is PasswordBox)
                {
                    (this.AssociatedObject as PasswordBox).SelectAll();
                }
                else if (this.AssociatedObject is RichTextBox)
                {
                    (this.AssociatedObject as RichTextBox).SelectAll();
                }
            }
        }

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

        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); }
        }

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

        public bool IsSelectAll
        {
            get { return (bool)GetValue(IsSelectAllProperty); }
            set { SetValue(IsSelectAllProperty, value); }
        }

    }
}

LoginViewModel.cs:

    public class LoginModel : ViewModelBase
    {
        ....

        private bool _EmailFocus = false;
        public bool EmailFocus
        {
            get
            {
                return _EmailFocus;
            }
            set
            {
                if (value)
                {
                    _EmailFocus = false;
                    RaisePropertyChanged("EmailFocus");
                }
                _EmailFocus = value;
                RaisePropertyChanged("EmailFocus");
            }
        }
       ...
   }

Login.xaml:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:beh="clr-namespace:MyProject.Behaviors"

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior IsFocused="{Binding EmailFocus}" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

または

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior HasInitialFocus="True" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

フォーカスを設定するには、コードでそれを行うだけです。

EmailFocus = true;

このプラグインはHTMLページの一部であるため、ページ内の他のコントロールにフォーカスがある可能性があることに注意してください

if (!Application.Current.IsRunningOutOfBrowser)
{
    System.Windows.Browser.HtmlPage.Plugin.Focus();
}

0

ViewCommandデザインパターンを使用できます。MVVM設計パターンがコマンドを使用してViewModelからビューを制御する方法について説明します。

MVVM Light Messengerクラスを使用するというA.Majid王の提案に基づいて実装しました。ViewCommandManagerクラスは、接続されたビューでのコマンドの呼び出しを処理します。これは、基本的には通常のコマンドのもう1つの方向です。ViewModelがそのビューで何らかのアクションを実行する必要がある場合に備えています。データバインドコマンドやWeakReferencesなどのリフレクションを使用して、メモリリークを回避します。

http://dev.unclassified.de/source/viewcommand(CodeProjectでも公開)


0

バインドされた変数を介して属性を簡単に更新するための最後のステップを含めた人はいないようです。これが私が思いついたものです。これを行うより良い方法があるかどうか教えてください。

XAML

    <TextBox x:Name="txtLabel"
      Text="{Binding Label}"
      local:FocusExtension.IsFocused="{Binding txtLabel_IsFocused, Mode=TwoWay}" 
     />

    <Button x:Name="butEdit" Content="Edit"
        Height="40"  
        IsEnabled="{Binding butEdit_IsEnabled}"                        
        Command="{Binding cmdCapsuleEdit.Command}"                            
     />   

ViewModel

    public class LoginModel : ViewModelBase
    {

    public string txtLabel_IsFocused { get; set; }                 
    public string butEdit_IsEnabled { get; set; }                


    public void SetProperty(string PropertyName, string value)
    {
        System.Reflection.PropertyInfo propertyInfo = this.GetType().GetProperty(PropertyName);
        propertyInfo.SetValue(this, Convert.ChangeType(value, propertyInfo.PropertyType), null);
        OnPropertyChanged(PropertyName);
    }                


    private void Example_function(){

        SetProperty("butEdit_IsEnabled", "False");
        SetProperty("txtLabel_IsFocused", "True");        
    }

    }

0

最初に、私は私の焦点の問題を解決するのを手伝ってくれたAvankaに感謝します。しかし、彼が投稿したコード、つまり次の行にはバグがあります:if(e.OldValue == null)

私が抱えていた問題は、最初にビューをクリックしてコントロールにフォーカスすると、e.oldValueがnullでなくなるということでした。次に、変数を設定してコントロールに初めてフォーカスを設定すると、lostfocusハンドラとgotfocusハンドラが設定されなくなります。これに対する私の解決策は次のとおりです:

public static class ExtensionFocus
    {
    static ExtensionFocus()
        {
        BoundElements = new List<string>();
        }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
        typeof(ExtensionFocus), new FrameworkPropertyMetadata(false, IsFocusedChanged));

    private static List<string> BoundElements;

    public static bool? GetIsFocused(DependencyObject element)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus GetIsFocused called with null element");
            }
        return (bool?)element.GetValue(IsFocusedProperty);
        }

    public static void SetIsFocused(DependencyObject element, bool? value)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus SetIsFocused called with null element");
            }
        element.SetValue(IsFocusedProperty, value);
        }

    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)d;

        // OLD LINE:
        // if (e.OldValue == null)
        // TWO NEW LINES:
        if (BoundElements.Contains(fe.Name) == false)
            {
            BoundElements.Add(fe.Name);
            fe.LostFocus += OnLostFocus;
            fe.GotFocus += OnGotFocus;
            }           


        if (!fe.IsVisible)
            {
            fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
            }

        if ((bool)e.NewValue)
            {
            fe.Focus();             
            }
        }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)sender;

        if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
            {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
            }
        }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, false);
            }
        }

    private static void OnGotFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, true);
            }
        }
    }

0

これを行うだけです:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...

私はこれが好き。これは、初期フォーカスを設定したい場合にうまく機能します。
user2430797

0

受け入れられた回答を実装した後、PrismでビューをナビゲートするとTextBoxがまだフォーカスされないという問題に遭遇しました。PropertyChangedハンドラーに小さな変更を加えて解決しました

    private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var uie = (UIElement)d;
        if ((bool)e.NewValue)
        {
            uie.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                uie.Focus();
            }));
        }
    }

0

@シェリダンの回答に基づく別のアプローチはこちら

 <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TextBox.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SomeTextIsFocused, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
                        <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

ビューモデルで通常の方法でバインディングを設定し、SomeTextIsFocusedをtrueに設定して、テキストボックスにフォーカスを設定します。


-1

IsVisible問題に対するCrucialの解決策が非常に役立つことがわかりました。それは私の問題を完全に解決しませんでしたが、IsEnabledパターンと同じパターンに従ういくつかの追加のコードはしました。

追加したIsFocusedChangedメソッドに:

    if (!fe.IsEnabled)
    {
        fe.IsEnabledChanged += fe_IsEnabledChanged;
    }

そしてここにハンドラがあります:

private static void fe_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var fe = (FrameworkElement)sender;
    if (fe.IsEnabled && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
    {
        fe.IsEnabledChanged -= fe_IsEnabledChanged;
        fe.Focus();
    }
}

-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }

-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);

1
OPはWPFを使用しています。WinFormsのフォーカスコードは役に立ちません。
Josh G
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.