Görünüm modelinden WPF'deki TextBox'a odaklanma


129

Benim görüşümde bir TextBoxve bir var Button.

Şimdi düğme tıklandığında bir koşulu kontrol ediyorum ve eğer koşul yanlış çıkarsa, mesajı kullanıcıya gösteriyorum ve ardından imleci TextBoxkontrole ayarlamam gerekiyor .

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

Yukarıdaki kod ViewModel içindedir.

CompanyAssociationGörünüm adıdır.

Ancak imleç 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 kullandığınızda bu mükemmel bir çözümdür.
matze8426

Yanıtlar:


265

Sorunuza üç kısımda cevap vereyim.

  1. Örneğinizdeki "cs.txtCompanyID" nedir merak ediyorum? Bir TextBox denetimi mi? Cevabınız evet ise, yanlış yoldasınız demektir. Genel olarak konuşursak, ViewModel'inizde kullanıcı arayüzüne herhangi bir referans olması iyi bir fikir değildir. "Neden" diye sorabilirsiniz. ancak bu Stackoverflow'a gönderilecek başka bir sorudur :).

  2. Focus ile ilgili sorunları bulmanın en iyi yolu ... Net kaynak kodunda hata ayıklamaktır. Şaka yapmıyorum. Bana birçok kez zaman kazandırdı. .Net kaynak kodu hata ayıklamasını etkinleştirmek için Shawn Bruke'un bloguna bakın.

  3. Son olarak, ViewModel'den odağı ayarlamak için kullandığım genel yaklaşım Attached Properties. Herhangi bir UIElement üzerinde ayarlanabilen çok basit ekli özellik yazdım. Ve örneğin ViewModel'in "IsFocused" özelliğine bağlanabilir. İşte burada:

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

    Şimdi Görünümünüzde (XAML'de) bu özelliği ViewModel'inize bağlayabilirsiniz:

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

Bu yardımcı olur umarım :). Cevaba 2 atıfta bulunmuyorsa.

Şerefe.


5
İyi fikir. Bunu çalıştırmak için IsUserNameFocused öğesini true, ardından da false olarak ayarlamam gerekiyor, bu doğru mu?
Sam

19
Ayrıca çağırmalıdır Keyboard.Focus(uie);senin dan OnIsFocusedPropertyChangedsize Klavye Odak almayı kontrolünü hem de mantıksal Odak isterseniz olay
Rachel

6
Bunun nasıl kullanılması gerekiyor? Mülkümü true olarak ayarlarsam, kontrol odaklanır. Ancak bu görüşe geri döndüğümde her zaman yeniden odaklanılacaktır. OnIsFocusedPropertyChanged'den sıfırlamak bunu değiştirmez. ViewModel'den ayarladıktan sonra doğrudan sıfırlamak artık hiçbir şeye odaklanmıyor. Çalışmıyor. Bu 70 artırıcı tam olarak ne yaptı?
ygoe

4
Ayrıca geri aramayı buna değiştirdim: ...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 ... Odağı birden çok kez ayarlamak istersem, bazen ViewModel'de 'IsFocused' öğesini false olarak sıfırlamam gerekiyor. Ama sonra, diğer bazı yöntemlerin başarısız olduğu yerde çalışır.
Simon D.

3
Odağı ayarladıktan ve odağı başka bir kontrol aldıktan sonra, odağı yeniden ayarlamak işe yaramaz çünkü IsFocused hala doğrudur. Onu yanlışa ve sonra doğruya zorlamanız gerekir. public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
walterhuang

75

Şimdiye kadar bu sorunun binlerce kez yanıtlandığını biliyorum, ancak Anvaka'nın katkısında, sahip olduğum benzer sorunları olanlara yardımcı olacağını düşündüğüm bazı düzenlemeler yaptım.

İlk olarak, yukarıdaki Ekli Mülkü şu şekilde değiştirdim:

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

Görünürlük referanslarını ekleme nedenim sekmelerdi. Görünüşe göre, ekli özelliği başlangıçta görünür sekmenin dışındaki herhangi bir sekmede kullandıysanız, ekli özellik siz denetimi manuel olarak odaklayana kadar çalışmadı.

Diğer engel, odak noktasını kaybettiğinde temeldeki özelliği yanlışa sıfırlamanın daha zarif bir yolunu yaratmaktı. Kayıp odak olayları burada devreye giriyor.

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

Görünürlük sorununu halletmenin daha iyi bir yolu varsa lütfen bize bildirin.

Not: BindsTwoWayByDefault'u DependencyProperty'ye koyma önerisi için Apfelkuacha'ya teşekkürler. Bunu uzun zaman önce kendi kodumla yapmıştım, ancak bu yazıyı hiç güncellemedim. Mod = TwoWay, bu değişiklik nedeniyle WPF kodunda artık gerekli değildir.


9
Bu benim için iyi çalışıyor, ancak GotFocus / LostFocus'a bir "if (e.Source == e.OriginalSource)" işareti eklemem gerekmediği sürece, UserControl'ümde kullanıldığında (kelimenin tam anlamıyla), odağı iç kısma yönlendiren bileşen. .Focus () yöntemi gibi çalıştığını kabul ederek Görünür kontrolleri kaldırdım. .Focus () çalışmazsa, bağlama çalışmamalı - ve bu benim senaryom için sorun değil.
HelloSam

1
Bunu WF 4.5'te kullanıyorum. IsFocusedChanged'de e.NewValue'nun boş olduğu ve bir istisna attığı bir senaryom var (bir Activity yeniden yüklenir), bu yüzden önce bunu kontrol edin. Bu küçük değişiklikle her şey yolunda gidiyor.
Olaru Mircea

1
Teşekkürler bu wprks Harika :) Varsayılan modu TwoWayBinding olarak ayarlamak için 'FrameworkPropertyMetadata'da' {BindsTwoWayByDefault = true} 'ekledim, böylece her Binding'de buna gerek
kalmadı

1
Bunun eski bir cevap olduğunu fark ettim, ancak odağı kaydırmak istediğim denetimin IsEnabled özelliğinin çok değerli bir dönüştürücüye bağlı olduğu bir durumla karşılaşıyorum. Görünüşe göre, GotFocus olay işleyicisi, çok değerli dönüştürücü yapmadan önce çağrılıyor ... bu, o noktada kontrolün devre dışı bırakıldığı anlamına gelir, bu nedenle GotFocus tamamlanır tamamlanmaz LostFocus çağrılır (sanırım kontrol hala devre dışı olduğu için) . Bununla nasıl başa çıkılacağına dair bir fikrin var mı?
Mark Olbert

1
@MarkOlbert fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);yüklendikten sonra güncellenmesini kullanır . Daha fazla bilgi burada: telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha

32

Bence en iyi yol, MVVM prensibini temiz tutmaktır, bu yüzden temelde MVVM Light ile sağlanan Messenger Sınıfını kullanmanız gerekir ve işte onu nasıl kullanacağınız:

görünüm modelinizde (exampleViewModel.cs): aşağıdakileri yazın

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

şimdi View.cs dosyanızda (XAML the view.xaml.cs değil) yapıcıya aşağıdakileri yazın

 public MyView()
        {
            InitializeComponent();

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

bu yöntem gayet iyi ve daha az kodla ve MVVM standartlarını koruyor


9
MVVM prensibini temiz tutmak istiyorsanız, en başta kodunuzun arkasına kod yazmazsınız. Ekteki mülkiyet yaklaşımının çok daha temiz olduğuna inanıyorum. Görünüm modelinizde de pek çok sihirli dizge bulunmaz.
Ε Г И І И О

32
El Nino: Arka plan kodunuzda hiçbir şeyin olmaması gerektiği fikrini tam olarak nereden edindiniz? UI ile ilgili her şey, görünümün arka plan kodunda olmalıdır. UI öğelerinin odak noktasını belirleme Kesinlikle görünümün arka plan kodunda olmalıdır . Görüş modelinin mesajı ne zaman göndereceğini bulmasına izin verin; bırakın görünüm mesajla ne yapacağını bulsun. Yani MV-VM yaptığı şudur: veri modelinin, iş mantığı ve UI kaygılarını ayırır.
Kyle Hale

Bu öneriye dayanarak, bağlantılı görünümlerde komut çağırmayı işleyen kendi ViewCommandManager'ımı uyguladım. Bu, temelde normal Komutların diğer yönüdür, bu durumlar için ViewModel'in Görünümlerinde bazı eylemler yapması gerekir. Bellek sızıntılarını önlemek için veriye bağlı komutlar ve WeakReferences gibi yansıma kullanır. dev.unclassified.de/source/viewcommand (ayrıca CodeProject'te)
ygoe

Bu yöntemi WPF FlowDocuments yazdırmak için kullandım. İyi çalıştı. Teşekkürler
Gordon Slysz

Silverlight'ta bir tane ister miyim? Kullanabilir miyiz?
Bigeyes

18

Bunların hiçbiri benim için tam olarak işe yaramadı, ancak başkalarının yararına, burada zaten sağlanan kodun bir kısmına dayanarak yazdım.

Kullanım aşağıdaki gibi olacaktır:

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

Ve uygulama şu şekilde olacaktır:

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

Bu eski bir iş parçacığı, ancak Anavanka'nın kabul ettiği yanıtla ilgili sorunları gideren kodda bir yanıt yok gibi görünüyor: görünüm modelinde mülkü yanlış olarak ayarlarsanız veya mülkünüzü true, kullanıcı manuel olarak başka bir şeyi tıklar ve siz bunu tekrar true olarak ayarlarsınız. Zamotic'in çözümünün bu durumlarda da güvenilir bir şekilde çalışmasını sağlayamadım.

Yukarıdaki tartışmalardan bazılarını bir araya getirdiğimde, bana, düşündüğüm bu sorunları ele alan aşağıdaki kodu veriyor:

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

Bunu söyledikten sonra, bu kod arka planda bir satırda yapılabilecek bir şey için hala karmaşıktır ve CoerceValue gerçekten bu şekilde kullanılmak üzere tasarlanmamıştır, bu yüzden belki kod arkası gitmek için yoldur.


1
Bu tutarlı bir şekilde çalışır, oysa kabul edilen cevap çalışmaz. Teşekkürler!
NathanAldenSr

4

Benim durumumda FocusExtension, OnIsFocusedPropertyChanged yöntemini değiştirene kadar çalışmadı. Orijinal olan, yalnızca bir kırılma noktası işlemi durdurduğunda hata ayıklamada çalışıyordu. Çalışma zamanında süreç çok hızlı ve hiçbir şey olmuyor. Bu küçük değişiklik ve arkadaşımız Task'ın yardımıyla, bu her iki senaryoda da iyi çalışıyor.

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

Sorun şu ki, IsUserNameFocused true olarak ayarlandığında asla yanlış olmayacak. Bu, FrameworkElement için GotFocus ve LostFocus'u işleyerek çözer.

Kaynak kodu biçimlendirmesiyle ilgili sorun yaşıyordum, işte bir bağlantı


1
"Fe = (FrameworkElement) d;" nesnesini değiştirdim "FrameworkElement fe = (FrameworkElement) d;" böylece intellisense çalışır

Hala sorunu çözmüyor. Öğe, ona her döndüğümde odaklanmış durumda kalıyor.
ygoe

3

Anvakas parlak kodu Windows Masaüstü uygulamaları içindir. Benim gibiyseniz ve Windows Mağazası uygulamaları için aynı çözüme ihtiyacınız varsa, bu kod kullanışlı olabilir:

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'nın yukarıdaki çözümünü kullanmaya çalışanlar için, lostfocus özelliği yanlış olarak güncellemeyeceği için yalnızca ilk seferde bağlanma ile ilgili sorunlar yaşıyordum. Özelliği manuel olarak false ve ardından her seferinde doğru olarak ayarlayabilirsiniz, ancak mülkünüzde buna benzer bir şey yapmak daha iyi bir çözüm olabilir:

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

Bu şekilde, yalnızca onu doğru olarak ayarlamanız gerekir ve odak noktası olacaktır.


Neden bir if ifadeniz var? _isFocused bir kez false olarak ayarlandığında bir sonraki satırda bir değere değiştirilecektir.
Damien McGivern

1
@Tyrsius Bağımlılık özelliğini Coerce'ye alarak bu sorunu çözebilirsiniz, buraya bakın- social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
RichardOD


1

Aşağıdaki gibi kodu düzenleyerek çözüm buldum. Önce Binding özelliğini False sonra True ayarlamaya gerek yoktur.

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 için:

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>

VEYA

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

Odağı ayarlamak için bunu kodda yapmanız yeterlidir:

EmailFocus = true;

Bu eklentinin bir html sayfasının parçası olduğunu, bu nedenle sayfadaki diğer kontrollerin odak noktası olabileceğini unutmayın.

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

0

ViewCommand'i kullanabilirsiniz tasarım desenini . Komutlarla bir ViewModel'den bir Görünümü kontrol etmek için MVVM tasarım modeline yönelik bir yöntemi açıklar.

Bunu King A.Majid'in MVVM Light Messenger sınıfını kullanma önerisine dayanarak uyguladım. ViewCommandManager sınıfı, bağlı görünümlerde çağrılan komutları işler. Bu, temelde, bir ViewModel'in kendi Görünümünde bazı eylemler yapması gerektiği durumlar için normal Komutların diğer yönüdür. Bellek sızıntılarını önlemek için veriye bağlı komutlar ve WeakReferences gibi yansıma kullanır.

http://dev.unclassified.de/source/viewcommand (CodeProject'te de yayınlanmıştır)


0

Bağlanmış değişkenler aracılığıyla özniteliklerin güncellenmesini kolaylaştırmak için son adımı kimse eklememiş görünüyor. İşte bulduğum şey. Bunu yapmanın daha iyi bir yolu olup olmadığını bana bildirin.

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

Öncelikle, odaklanma sorunumu çözmeme yardımcı olduğu için Avanka'ya teşekkür etmek istiyorum. Bununla birlikte, gönderdiği kodda, yani şu satırda bir hata var: if (e.OldValue == null)

Karşılaştığım sorun, ilk önce görünümünüze tıklayıp kontrole odaklanırsanız, e.oldValue'nun artık boş olmamasıydı. Daha sonra, değişkeni kontrole ilk kez odaklanacak şekilde ayarladığınızda, bu, odak kaybına ve odak işleyicilerinin ayarlanmamasına neden olur. Buna çözümüm şuydu:

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

Sadece şunu yap:

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

Bunu severim. İlk odağı ayarlamak istiyorsanız bu iyi çalışır.
user2430797

0

Kabul edilen cevabı uyguladıktan sonra, Prism ile görünümlerde gezinirken TextBox'ın hala odaklanamayacağı bir sorunla karşılaştım. PropertyChanged işleyicisindeki küçük bir değişiklik sorunu çözdü

    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

@Sheridan cevabına dayalı alternatif bir yaklaşım burada

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

Görünüm modelinizde bağlamanızı normal şekilde ayarlayın ve ardından odağı metin kutunuza ayarlamak için SomeTextIsFocused öğesini true olarak ayarlayın.


-1

Çok önemli buldum IsVisible sorununa bireyin çözüm çok kullanışlı. Sorunumu tamamen çözmedi, ancak IsEnabled kalıbı için aynı kalıbı izleyen bazı ekstra kodlar çözdü.

Eklediğim IsFocusedChanged yöntemine:

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

Ve işte işleyici:

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 kullanıyor. WinForms için odak kodu yardımcı olmayacak.
Josh G
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.