दृश्य मॉडल से WPF में टेक्स्टबॉक्स पर ध्यान केंद्रित करें


129

मेरे विचार में मेरे पास एक TextBoxऔर एक Buttonहै।

अब मैं बटन क्लिक पर एक स्थिति की जांच कर रहा हूं और यदि स्थिति झूठी हो जाती है, तो उपयोगकर्ता को संदेश प्रदर्शित करता है, और फिर मुझे कर्सर को 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}"/>

जब आप कैलिबर्न.माइक्रो का उपयोग कर रहे हैं तो यह एक उत्कृष्ट उपाय है।
matze8426

जवाबों:


264

मुझे आपके प्रश्न का उत्तर तीन भागों में देना चाहिए।

  1. मैं सोच रहा हूँ कि आपके उदाहरण में "cs.txtCompanyID" क्या है? क्या यह एक टेक्स्टबॉक्स नियंत्रण है? यदि हाँ, तो आप गलत रास्ते पर हैं। आम तौर पर यह कहना कि आपके ViewModel में UI का कोई संदर्भ होना अच्छा नहीं है। आप पूछ सकते हैं "क्यों?" लेकिन यह Stackoverflow पर पोस्ट करने के लिए एक और सवाल है :)।

  2. फोकस के साथ मुद्दों को ट्रैक करने का सबसे अच्छा तरीका है ... डीबगिंग .Net स्रोत कोड। मजाक नहीं। इसने मुझे कई बार बचाया। .Net स्रोत कोड डीबगिंग को सक्षम करने के लिए शॉन ब्रुके के ब्लॉग को देखें ।

  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 को सही पर सेट करने की आवश्यकता है, फिर इस काम को पाने के लिए फिर से झूठ, क्या यह सही है?
सैम

19
यदि आप कीबोर्ड कंट्रोल के साथ-साथ लॉजिकल फोकस प्राप्त करना चाहते हैं, तो आपको Keyboard.Focus(uie);अपने OnIsFocusedPropertyChangedईवेंट से भी कॉल करना चाहिए
राहेल

6
इसका उपयोग कैसे किया जाना चाहिए? यदि मैंने अपनी संपत्ति को सही पर सेट किया है, तो नियंत्रण केंद्रित है। लेकिन जब मैं इस दृष्टिकोण पर वापस आऊंगा तो यह हमेशा केंद्रित रहेगा। इसे OnIsFocusedPropertyChanged से रीसेट करने से यह परिवर्तित नहीं होता है। ViewModel से इसे सेट करने के बाद इसे सीधे रीसेट करने से कुछ भी फ़ोकस नहीं होता है। यह काम नहीं करता है। उन 70 उत्थानकर्ताओं ने वास्तव में क्या किया है?
23

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' को रीसेट करना पड़ता है, अगर मैं कई बार फोकस सेट करना चाहता हूं। लेकिन फिर यह काम करता है, जहां कुछ अन्य तरीके विफल हो गए।
साइमन डी।

3
आपके द्वारा फ़ोकस सेट करने के बाद और फ़ोकस नियंत्रित करने पर फ़ोकस सेट हो जाता है, फ़ोकस फिर से काम नहीं करेगा क्योंकि IsFocused अभी भी सही है। इसे असत्य और फिर सत्य के लिए मजबूर करने की आवश्यकता है। public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
वाल्टरहुआंग

75

मुझे पता है कि इस सवाल का अब तक एक हजार बार जवाब दिया जा चुका है, लेकिन मैंने अनवाका के योगदान के लिए कुछ संपादन किए हैं जो मुझे लगता है कि दूसरों की मदद करेंगे जिनके समान मुद्दे थे।

सबसे पहले, मैंने उपरोक्त अटैच की गई संपत्ति को इस तरह बदल दिया:

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

दृश्यता संदर्भों को जोड़ने का मेरा कारण टैब थे। यदि आप प्रारंभ में दिखाई देने वाले टैब के बाहर किसी अन्य टैब पर संलग्न संपत्ति का उपयोग करते हैं, तो संलग्न संपत्ति तब तक काम नहीं करती जब तक कि आप मैन्युअल रूप से नियंत्रण पर ध्यान केंद्रित नहीं करते।

अन्य बाधा ध्यान केंद्रित खो जाने पर अंतर्निहित संपत्ति को झूठी करने के लिए रीसेट करने का एक और अधिक सुरुचिपूर्ण तरीका बना रही थी। यहीं से खोई हुई फोकस घटनाएं सामने आईं।

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

यदि दृश्यता मुद्दे को संभालने का एक बेहतर तरीका है, तो कृपया मुझे बताएं।

नोट: डिपेंडेंसीप्रोपरेटी में BindsTwoWayByDefault लगाने के सुझाव के लिए Apfelkuacha का धन्यवाद। मैंने बहुत पहले अपने कोड में किया था, लेकिन इस पोस्ट को कभी अपडेट नहीं किया। मोड = TwoWay इस परिवर्तन के कारण WPF कोड में आवश्यक नहीं रह गया है।


9
यह मेरे लिए अच्छी तरह से काम करता है, इसके अलावा मुझे GotFocus / LostFocus में "if (e.Source == e.OriginalSource)" को जोड़ने की आवश्यकता है, अन्यथा यह मेरे यूज़रकंट्रोल पर उपयोग किए जाने पर स्टैकओवरफ्लो (शाब्दिक रूप से) करता है, जो आंतरिक पर ध्यान केंद्रित करता है। घटक। मैंने विज़िबल चेक को हटा दिया, इस तथ्य को स्वीकार करते हुए कि यह वर्कफ़्लो की तरह काम करता है। यदि .Focus () काम नहीं करता है, तो बंधन को काम नहीं करना चाहिए - और यह मेरे परिदृश्य के लिए ठीक है।
हेल्ससम

1
मैं इसका उपयोग WF 4.5 में कर रहा हूं। IsFocusedChanged पर मेरे पास एक परिदृश्य है (एक गतिविधि फिर से लोड हो जाती है) जहां e.NewValue शून्य है और एक अपवाद को फेंकता है, इसलिए पहले जांचें। इस मामूली बदलाव से सब कुछ ठीक हो जाता है।
ओलारू मिर्सिया

1
धन्यवाद इस wprks महान :) मैंने सिर्फ '' 'BindsTwoWayByDefault = true}' को 'फ्रेमवर्कप्रोपरेटीमेटाटा' में TwoWayBinding के लिए डिफ़ॉल्ट मोड सेट करने के लिए जोड़ा है, इसलिए इसे हर बाध्यकारी पर जरूरी नहीं है
R00st3r

1
मुझे लगता है कि यह एक पुराना उत्तर है, लेकिन मैं ऐसी स्थिति में भाग रहा हूं, जहां नियंत्रण की अक्षम संपत्ति मैं उस फोकस को शिफ्ट करना चाहता हूं जो एक बहु-मूल्य कनवर्टर से बंधा है। जाहिरा तौर पर, गॉटफोकस इवेंट हैंडलर को मल्टी-वैल्यू कनवर्टर से पहले कॉल किया जाता है ... जिसका मतलब है कि नियंत्रण, उस बिंदु पर, अक्षम है, इसलिए जैसे ही गॉटफोकस पूरा होता है, लॉस्टफोकस को कॉल किया जाता है (मुझे लगता है क्योंकि नियंत्रण अभी भी अक्षम है। । कैसे संभालना है पर कोई विचार?
मार्क ऑलबर्ट

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 सिद्धांत को साफ रखना चाहते हैं, तो आप अपने कोड में पहले स्थान पर कोड नहीं लिखेंगे। मेरा मानना ​​है कि संलग्न संपत्ति दृष्टिकोण बहुत क्लीनर है। यह आपके दृश्य मॉडल में बहुत सारे जादू के तार भी पेश नहीं करता है।
12 Г И О И О

32
अल नीनो: वास्तव में आपको यह विचार कहां से मिला कि आपके व्यू कोड के पीछे कुछ भी नहीं होना चाहिए? UI से संबंधित कुछ भी दृश्य के कोड-पीछे होना चाहिए। UI तत्वों का फ़ोकस सेट करना निश्चित रूप से दृश्य के कोड-पीछे होना चाहिए । संदेश भेजने के लिए व्यूमोडेल का पता लगाने दें; संदेश के साथ क्या करना है, यह देखने दें। वह है जो एमवी-वीएम करता है: डेटा मॉडल, व्यावसायिक तर्क और UI की चिंताओं को अलग करता है।
काइल हेल

इस सुझाव के आधार पर, मैंने अपना स्वयं का ViewCommandManager कार्यान्वित किया है जो कनेक्टेड दृश्यों में कमांड को लागू करने का काम करता है। यह मूल रूप से नियमित कमांड्स की दूसरी दिशा है, इन मामलों के लिए जब एक ViewModel को अपने दृश्य (ओं) में कुछ कार्रवाई करने की आवश्यकता होती है। यह मेमोरी लीक से बचने के लिए डेटा-बाउंड कमांड्स और वीकरेफेरेंस जैसे प्रतिबिंब का उपयोग करता है। dev.unclassified.de/source/viewcommand ( कोडप्रोजेक्ट पर भी)
ygoe

मैंने WPF FlowDocuments को प्रिंट करने के लिए इस विधि का उपयोग किया। अच्छी तरह से काम किया। धन्यवाद
गॉर्डन Slysz

मुझे सिल्वरलाइट में एक चाहिए? क्या हम इसका उपयोग कर सकते हैं?
बिगयेस

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 के स्वीकृत उत्तर के साथ मुद्दों को संबोधित करता है: यह काम नहीं करता है यदि आप व्यूमोडेल में संपत्ति को गलत पर सेट करते हैं, या यदि आप अपनी संपत्ति सेट करते हैं तो सच है, उपयोगकर्ता मैन्युअल रूप से कुछ और पर क्लिक करता है, और फिर आप इसे फिर से सच करने के लिए सेट करते हैं। मैं इन मामलों में मज़बूती से काम करने के लिए ज़मोटिक का समाधान नहीं प्राप्त कर सका।

उपरोक्त कुछ चर्चाओं को एक साथ खींचने से मुझे नीचे दिया गया कोड मिलता है जो इन मुद्दों को संबोधित करता है जो मुझे लगता है:

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

यह कहते हुए कि, यह अभी भी उस चीज के लिए जटिल है, जो कोडबेहिंड में एक पंक्ति में की जा सकती है, और CoerceValue का वास्तव में इस तरह से उपयोग करने का मतलब नहीं है, इसलिए हो सकता है कि कोडबिहंड जाने का रास्ता हो।


1
यह लगातार काम करता है, जबकि स्वीकृत उत्तर नहीं देता है। धन्यवाद!
नाथनअल्डनसेर

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 को सही पर सेट करने के बाद, यह कभी भी गलत नहीं होगा। यह फ्रेमवर्क के लिए GotFocus और LostFocus को संभालने के द्वारा इसे हल करता है।

मुझे सोर्स कोड फॉर्मेटिंग में दिक्कत हो रही थी इसलिए यहाँ एक लिंक दिया गया है


1
मैंने "ऑब्जेक्ट फ़े = (फ्रेमवर्क क्लेमेंट) घ;" "फ्रेमवर्क फ़्लाइट = (फ्रेमवर्क क्लेमेंट) डी;" तो

फिर भी समस्या हल नहीं होती है। तत्व हर उस समय केंद्रित रहता है जब मैं उसमें वापस आता हूं।
ygoe

3

Anvakas शानदार कोड विंडोज डेस्कटॉप अनुप्रयोगों के लिए है। यदि आप मेरे जैसे हैं और विंडोज स्टोर ऐप्स के लिए समान समाधान की आवश्यकता है तो यह कोड काम कर सकता है:

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 के समाधान का उपयोग करने की कोशिश करने वालों के लिए, मैं केवल पहली बार काम करने वाले बाइंडिंग के साथ समस्या कर रहा था, क्योंकि खोई हुई संपत्ति संपत्ति को गलत के लिए अपडेट नहीं करेगी। आप हर बार संपत्ति को गलत और फिर सच में सेट कर सकते हैं, लेकिन एक बेहतर उपाय यह हो सकता है कि आप अपनी संपत्ति में कुछ ऐसा करें:

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

इस तरह से आपको केवल इसे सच करने के लिए सेट करना होगा, और इसे फोकस मिलेगा।


यदि आप एक बयान क्यों है? _isFocused एक बार झूठे सेट करने के बाद अगली पंक्ति में मान में बदल दिया जाएगा।
डेमियन मैकगिवर्न

1
@Tyrsius आप मजबूर करने के लिए निर्भरता संपत्ति हो रही द्वारा इस मुद्दे दौर कर सकते हैं, यहाँ देख social.msdn.microsoft.com/Forums/en-US/wpf/thread/...
RichardOD

1

मैं WPF / कैलीबर्न माइक्रो का उपयोग करता हूँ एक पाया है कि "dfaivre" ने यहां एक सामान्य और व्यावहारिक समाधान बनाया है: http://caliburnmicro.codeplex.com/discussions/222892


1

मुझे निम्नलिखित के अनुसार कोड को संपादित करके समाधान मिल गया है। बाइंडिंग प्रॉपर्टी को पहले फाल्स सेट करने की जरूरत नहीं है फिर ट्रू।

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

सिल्वरलाइट के लिए:

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 का उपयोग कर सकते हैं डिजाइन पैटर्न का । यह एमवीवीएम डिज़ाइन पैटर्न के लिए एक विधि को कमांड से व्यू व्यूमेल से नियंत्रित करने के लिए वर्णन करता है।

मैंने एमवीवीएम लाइट मैसेंजर क्लास का उपयोग करने के लिए राजा ए.मजीद के सुझाव के आधार पर इसे लागू किया है। ViewCommandManager वर्ग जुड़े विचारों में आदेशों को लागू करने का काम करता है। यह मूल रूप से नियमित कमांड की दूसरी दिशा है, इन मामलों के लिए जब एक ViewModel को अपने दृश्य में कुछ कार्रवाई करने की आवश्यकता होती है। यह मेमोरी-लीक से बचने के लिए डेटा-बाउंड कमांड और कमजोरियों जैसे प्रतिबिंब का उपयोग करता है।

http://dev.unclassified.de/source/viewcommand (कोडप्रोजेक्ट पर भी प्रकाशित)


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

सबसे पहले मैं अपने फोकस की समस्या को हल करने में मदद करने के लिए अवंका को धन्यवाद देना चाहूंगा। हालाँकि, उसने पोस्ट किए गए कोड में एक बग रखा है, अर्थात् लाइन में: if (e.OldValue == null)

मेरे पास समस्या यह थी कि यदि आप पहली बार अपने विचार में क्लिक करते हैं और नियंत्रण पर ध्यान केंद्रित करते हैं, तो e.oldValue अब शून्य नहीं है। फिर जब आप पहली बार कंट्रोल को फोकस करने के लिए वेरिएबल सेट करते हैं, तो इसके परिणामस्वरूप लॉफोकस और गेटफोक हैंडलर सेट नहीं हो पाते हैं। मेरा समाधान इस प्रकार था:

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

स्वीकृत उत्तर को लागू करने के बाद, मैंने एक मुद्दे पर चलाया कि जब प्रिस्क्रिप्शन के साथ विचारों को नेविगेट करना तब भी ध्यान केंद्रित नहीं करेगा। प्रॉपर्टीचैन्ड हैंडलर में मामूली बदलाव ने इसे हल कर दिया

    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 उत्तर के आधार पर एक वैकल्पिक दृष्टिकोण

 <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 को अपने टेक्स्ट बॉक्स पर फ़ोकस सेट करने के लिए सही पर सेट करें।


-1

मुझे Crucial मिला बहुत ही उपयोगी IsV अदृश्य समस्या के लिए समाधान मिल गया। यह पूरी तरह से मेरी समस्या को हल नहीं करता था, लेकिन कुछ अतिरिक्त कोड के लिए इसी पैटर्न का अनुसरण किया।

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
ओपी WPF का उपयोग कर रहा है। WinForms के लिए फ़ोकस कोड मदद करने वाला नहीं है।
जोश जी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.