Atur fokus pada TextBox di WPF dari model tampilan

129

Saya memiliki TextBoxdan Buttondalam pandangan saya.

Sekarang saya memeriksa suatu kondisi pada tombol klik dan jika kondisi ternyata salah, menampilkan pesan kepada pengguna, dan kemudian saya harus mengatur kursor ke TextBoxkontrol.

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

Kode di atas ada di dalam ViewModel.

The CompanyAssociationadalah nama tampilan.

Tetapi kursor tidak diatur dalam TextBox.

XAML adalah:

<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}"/>
priyanka.sarkar
sumber
Saat Anda menggunakan caliburn.micro, ini adalah solusi yang sangat bagus.
matze8426

Jawaban:

264

Biarkan saya menjawab pertanyaan Anda dalam tiga bagian.

  1. Saya bertanya-tanya apa itu "cs.txtCompanyID" dalam contoh Anda? Apakah ini kontrol TextBox? Jika ya, berarti Anda berada di jalan yang salah. Secara umum itu bukan ide yang baik untuk memiliki referensi ke UI di ViewModel Anda. Anda bisa bertanya, "Kenapa?" tapi ini pertanyaan lain untuk dikirim di Stackoverflow :).

  2. Cara terbaik untuk melacak masalah dengan Fokus adalah ... men-debug kode sumber .Net. Tidak bercanda. Ini menyelamatkan saya banyak waktu berkali-kali. Untuk mengaktifkan debugging kode sumber .net, lihat blog Shawn Bruke .

  3. Akhirnya, pendekatan umum yang saya gunakan untuk mengatur fokus dari ViewModel adalah Properti Terlampir. Saya menulis properti terlampir yang sangat sederhana, yang dapat diset pada UIElement apa pun. Dan itu dapat diikat ke properti ViewModel "IsFocused" misalnya. Ini dia:

    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.
            }
        }
    }
    

    Sekarang di View Anda (dalam XAML) Anda dapat mengikat properti ini ke ViewModel Anda:

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

Semoga ini membantu :). Jika tidak merujuk ke jawaban # 2.

Bersulang.

Anvaka
sumber
5
Ide keren Saya perlu mengatur IsUserNameFocused menjadi true, lalu false lagi agar ini berfungsi, apakah ini benar?
Sam
19
Anda juga harus menelepon Keyboard.Focus(uie);dari OnIsFocusedPropertyChangedacara Anda jika Anda ingin kontrol Anda menerima Fokus Keyboard serta Fokus Logis
Rachel
6
Bagaimana ini seharusnya digunakan? Jika saya menyetel properti saya menjadi true, kontrol difokuskan. Tapi itu akan selalu fokus lagi ketika saya kembali ke pandangan ini. Menyetel ulang dari OnIsFocusedPropertyChanged tidak mengubah ini. Menyetel ulang secara langsung setelah mengaturnya dari ViewModel tidak lagi memfokuskan apa pun. Itu tidak bekerja. Apa sebenarnya yang dilakukan oleh 70 orang upvoter itu?
ygoe
4
Saya juga mengubah panggilan balik ke ini: ...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 ... Kadang-kadang saya bahkan harus mengatur ulang 'IsFocused' menjadi false di ViewModel, jika saya ingin mengatur fokus beberapa kali. Tapi kemudian berhasil, di mana beberapa metode lain gagal.
Simon D.
3
setelah Anda mengatur fokus dan kontrol lain mendapatkan fokus, untuk mengatur fokus lagi tidak akan berfungsi karena IsFocused masih benar. Perlu memaksanya untuk salah dan kemudian benar. public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
walterhuang
75

Saya tahu pertanyaan ini telah dijawab ribuan kali sekarang, tetapi saya mengedit kontribusi Anvaka yang saya pikir akan membantu orang lain yang memiliki masalah serupa yang saya miliki.

Pertama, saya mengubah Properti Terlampir di atas seperti:

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

Alasan saya untuk menambahkan referensi visibilitas adalah tab. Tampaknya jika Anda menggunakan properti terlampir pada tab lain di luar tab yang awalnya terlihat, properti terlampir tidak berfungsi sampai Anda memfokuskan kontrol secara manual.

Kendala lain adalah menciptakan cara yang lebih elegan untuk mengatur ulang properti yang mendasarinya menjadi false ketika kehilangan fokus. Di situlah peristiwa fokus yang hilang masuk.

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

Jika ada cara yang lebih baik untuk menangani masalah visibilitas, beri tahu saya.

Catatan: Terima kasih kepada Apfelkuacha untuk saran menempatkan BindsTwoWayByDefault di DependencyProperty. Saya sudah melakukannya sejak lama di kode saya sendiri, tetapi tidak pernah memperbarui posting ini. Mode = TwoWay tidak lagi diperlukan dalam kode WPF karena perubahan ini.

Zamotik
sumber
9
Ini berfungsi baik untuk saya kecuali saya perlu menambahkan tanda "if (e.Source == e.OriginalSource)" di GotFocus / LostFocus atau jika tidak stackoverflows (secara harfiah) ketika digunakan pada UserControl saya, yang mengarahkan ulang fokus ke inner komponen. Saya menghapus cek Terlihat, menerima kenyataan bahwa itu berfungsi seperti metode .Focus (). Jika .Focus () tidak berfungsi, pengikatan tidak akan berfungsi - dan itu ok untuk skenario saya.
HelloSam
1
Saya menggunakan ini di WF 4.5. Pada IsFocusedChanged saya punya skenario (Aktivitas akan dimuat ulang) di mana e.NewValue adalah nol dan melempar pengecualian, jadi periksa dulu. Semuanya berfungsi dengan baik dengan perubahan kecil ini.
Olaru Mircea
1
Terima kasih ini wprks Hebat :) Saya baru saja menambahkan '{BindsTwoWayByDefault = true}' di 'FrameworkPropertyMetadata' untuk mengatur mode default ke TwoWayBinding sehingga tidak diperlukan pada setiap Binding
R00st3r
1
Saya menyadari ini adalah jawaban lama, tapi saya mengalami situasi di mana properti IsEnabled dari kontrol yang ingin saya alihkan fokusnya terikat dengan konverter multi-nilai. Rupanya, event handler GotFocus dipanggil sebelum konverter multi-nilai tidak ... yang berarti kontrol, pada saat itu, dinonaktifkan, sehingga begitu GotFocus selesai, LostFocus dipanggil (saya kira karena kontrolnya masih dinonaktifkan) . Adakah pemikiran tentang cara mengatasinya?
Mark Olbert
1
@MarkOlbert menggunakan fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);itu diperbarui setelah dimuat. Info lebih lanjut di sini: telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha
32

Saya pikir cara terbaik adalah menjaga prinsip MVVM bersih, jadi pada dasarnya Anda harus menggunakan Kelas Messenger yang disediakan dengan MVVM Light dan di sini adalah bagaimana menggunakannya:

di viewmodel Anda (exampleViewModel.cs): tulis berikut ini

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

sekarang di View.cs Anda (bukan XAML, view.xaml.cs) tulis yang berikut di konstruktor

 public MyView()
        {
            InitializeComponent();

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

Metode itu berjalan dengan baik dan dengan kode yang lebih sedikit dan mempertahankan standar MVVM

Adam
sumber
9
Nah, jika Anda ingin menjaga prinsip MVVM bersih, Anda tidak akan menulis kode dalam kode Anda di tempat pertama. Saya percaya pendekatan properti terlampir jauh lebih bersih. Itu tidak memperkenalkan banyak string ajaib dalam model tampilan Anda juga.
Ε Г И І И О
32
El Nino: Di mana tepatnya Anda mendapatkan ide itu seharusnya tidak ada apa-apa dalam pandangan Anda di belakang kode? Apa pun yang terkait dengan UI harus ada dalam kode di belakang tampilan. Pengaturan fokus elemen UI harus jelas dalam kode di belakang tampilan. Biarkan model tampilan mengetahui kapan harus mengirim pesan; biarkan tampilan mencari tahu apa yang harus dilakukan dengan pesan tersebut. Itulah yang dilakukan MV-VM: memisahkan masalah model data, logika bisnis, dan UI.
Kyle Hale
Berdasarkan saran ini, saya telah mengimplementasikan ViewCommandManager saya sendiri yang menangani perintah pemanggilan dalam tampilan yang terhubung. Ini pada dasarnya adalah arah lain dari Perintah biasa, untuk kasus-kasus ini ketika ViewModel perlu melakukan beberapa tindakan dalam Tampilannya. Ini menggunakan refleksi seperti perintah terikat data dan Referensi Lemah untuk menghindari kebocoran memori. dev.unclassified.de/source/viewcommand (juga di CodeProject)
ygoe
Saya menggunakan metode ini untuk mencetak WPF FlowDocuments. Bekerja dengan baik. Terima kasih
Gordon Slysz
Saya ingin satu di Silverlight? Bisakah kita menggunakannya?
Bigeyes
18

Tak satu pun dari ini bekerja untuk saya persis, tetapi untuk kepentingan orang lain, inilah yang akhirnya saya tulis berdasarkan beberapa kode yang sudah disediakan di sini.

Penggunaannya adalah sebagai berikut:

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

Dan implementasinya adalah sebagai berikut:

/// <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
}
Leo Vildosola
sumber
11

Ini adalah utas lama, tetapi sepertinya tidak ada jawaban dengan kode yang mengatasi masalah dengan jawaban yang diterima Anavanka: tidak berfungsi jika Anda menyetel properti di viewmodel menjadi false, atau jika Anda menyetel properti Anda ke benar, pengguna secara manual mengklik sesuatu yang lain, dan kemudian Anda mengaturnya menjadi benar lagi. Saya juga tidak bisa mendapatkan solusi Zamotic untuk bekerja dengan andal dalam kasus-kasus ini.

Menyatukan beberapa diskusi di atas memberi saya kode di bawah ini yang menangani masalah ini, saya pikir:

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

Karena itu, ini masih kompleks untuk sesuatu yang dapat dilakukan dalam satu baris dalam codebehind, dan CoerceValue tidak benar-benar dimaksudkan untuk digunakan dengan cara ini, jadi mungkin codebehind adalah cara untuk pergi.

Rich N
sumber
1
Ini bekerja secara konsisten, sedangkan jawaban yang diterima tidak. Terima kasih!
NathanAldenSr
4

Dalam kasus saya, FocusExtension tidak berfungsi sampai saya mengubah metode OnIsFocusedPropertyChanged. Yang asli hanya berfungsi di debug ketika break point menghentikan proses. Saat runtime, prosesnya terlalu cepat dan tidak ada yang terjadi. Dengan sedikit modifikasi ini dan bantuan Tugas teman kita, ini berfungsi dengan baik di kedua skenario.

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);
  }
}
Vincent Rithner
sumber
3

Masalahnya adalah begitu IsUserNameFocused disetel ke true, itu tidak akan pernah salah. Ini menyelesaikannya dengan menangani GotFocus dan LostFocus untuk FrameworkElement.

Saya mengalami masalah dengan pemformatan kode sumber jadi di sini ada tautan

Shawn
sumber
1
Saya mengubah "objek fe = (FrameworkElement) d;" untuk "FrameworkElement fe = (FrameworkElement) d;" jadi intellisense berfungsi
Masih tidak menyelesaikan masalah. Elemen tetap fokus setiap kali saya kembali ke sana.
ygoe
3

Kode brilian Anvakas adalah untuk aplikasi Windows Desktop. Jika Anda seperti saya dan membutuhkan solusi yang sama untuk aplikasi Windows Store, kode ini mungkin berguna:

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);
            }
        }
    }
}
PEK
sumber
1

Bagi mereka yang mencoba menggunakan solusi Anvaka di atas, saya mengalami masalah dengan pengikatan hanya berfungsi pertama kali, karena kehilanganfokus tidak akan memperbarui properti ke false. Anda dapat secara manual mengatur properti menjadi false dan kemudian benar setiap kali, tetapi solusi yang lebih baik bisa dengan melakukan sesuatu seperti ini di properti Anda:

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

Dengan cara ini Anda hanya perlu mengaturnya menjadi benar, dan itu akan mendapatkan fokus.

Kyeotik
sumber
Mengapa Anda memiliki pernyataan if? _isFocused setelah disetel ke false hanya akan diubah menjadi nilai pada baris berikutnya.
Damien McGivern
1
@Tyrsius Anda dapat melengkapi masalah ini dengan mendapatkan properti ketergantungan untuk memaksa, lihat di sini- social.msdn.microsoft.com/Forums/en-US/wpf/thread/...
RichardOD
1

Saya telah menemukan solusi dengan mengedit kode sebagai berikut. Tidak perlu mengatur properti Binding terlebih dahulu False lalu 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);
        }
    }
}
Bharat Mendapara
sumber
0

Untuk 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>

ATAU

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

Untuk mengatur fokus, lakukan saja dalam kode:

EmailFocus = true;

Ingat bahwa plugin ini adalah bagian dari halaman html, jadi kontrol lain di halaman tersebut mungkin memiliki fokus

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

Anda bisa menggunakan pola desain ViewCommand . Ini menjelaskan metode untuk pola desain MVVM untuk mengontrol tampilan dari ViewModel dengan perintah.

Saya sudah mengimplementasikannya berdasarkan saran Raja A.Majid untuk menggunakan kelas MVVM Light Messenger. Kelas ViewCommandManager menangani perintah pemanggilan dalam tampilan yang terhubung. Ini pada dasarnya adalah arah lain dari Perintah reguler, untuk kasus-kasus ini ketika ViewModel perlu melakukan beberapa tindakan dalam Tampilannya. Ini menggunakan refleksi seperti perintah terikat data dan Referensi Lemah untuk menghindari kebocoran memori.

http://dev.unclassified.de/source/viewcommand (juga dipublikasikan di CodeProject)

ygoe
sumber
0

Sepertinya tidak ada yang memasukkan langkah terakhir untuk memudahkan memperbarui atribut melalui variabel terikat. Inilah yang saya pikirkan. Beri tahu saya jika ada cara yang lebih baik untuk melakukan ini.

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

    }
Hugh
sumber
0

Pertama-tama saya ingin mengucapkan terima kasih kepada Avanka karena telah membantu saya memecahkan masalah fokus saya. Namun ada bug dalam kode yang dia posting, yaitu di baris: if (e.OldValue == null)

Masalah yang saya miliki adalah bahwa jika Anda pertama kali mengklik pada tampilan Anda dan memfokuskan kontrol, e.oldValue tidak lagi nol. Kemudian ketika Anda mengatur variabel untuk memfokuskan kontrol untuk pertama kalinya, ini menghasilkan fokus yang hilang dan penangan fokus yang tidak ditetapkan. Solusi saya untuk ini adalah sebagai berikut:

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);
            }
        }
    }
pengguna2127475
sumber
0

Lakukan saja ini:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...
Zoltan
sumber
Saya suka ini. Ini berfungsi baik jika Anda ingin mengatur fokus awal.
user2430797
0

Setelah menerapkan jawaban yang diterima, saya menemukan masalah yang saat menavigasi tampilan dengan Prism TextBox masih tidak akan mendapatkan fokus. Perubahan kecil ke penangan PropertyChanged menyelesaikannya

    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();
            }));
        }
    }
Joe H.
sumber
0

Pendekatan alternatif berdasarkan jawaban @Sheridan di sini

 <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>

Dalam model tampilan Anda, atur ikatan Anda dengan cara biasa dan kemudian atur SomeTextIsFocused menjadi true untuk mengatur fokus pada kotak teks Anda

Stuicidle
sumber
-1

Saya menemukan solusi Krusial untuk masalah IsVisible sangat berguna. Itu tidak sepenuhnya menyelesaikan masalah saya, tetapi beberapa kode tambahan mengikuti pola yang sama untuk pola IsEnabled.

Ke metode IsFocusedChanged saya menambahkan:

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

Dan ini dia:

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();
    }
}
Wayne Maurer
sumber
-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }
Jayasri
sumber
-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);
KitWest
sumber
1
OP menggunakan WPF. Kode fokus untuk WinForms tidak akan membantu.
Josh G