2009-02-18 20 views
92

TextBox पर डिफ़ॉल्ट डेटाबेसिंग TwoWay है और यह केवल TextBox पर अपना ध्यान खोने पर ही संपत्ति को टेक्स्ट करता है।एंटर-कुंजी प्रेस पर बाइंड टेक्स्टबॉक्स

क्या TextBox पर कुंजी दर्ज करते समय डेटाबेसिंग करने के लिए कोई आसान XAML तरीका है? मुझे पता है कि कोड के पीछे करना बहुत आसान है, लेकिन कल्पना करें कि यह TextBox कुछ जटिल DataTemplate के अंदर है।

उत्तर

121

आप attached behaviour बनाकर स्वयं को एक शुद्ध एक्सएएमएल दृष्टिकोण बना सकते हैं।

कुछ इस तरह:

public static class InputBindingsManager 
{ 

    public static readonly DependencyProperty UpdatePropertySourceWhenEnterPressedProperty = DependencyProperty.RegisterAttached(
      "UpdatePropertySourceWhenEnterPressed", typeof(DependencyProperty), typeof(InputBindingsManager), new PropertyMetadata(null, OnUpdatePropertySourceWhenEnterPressedPropertyChanged)); 

    static InputBindingsManager() 
    { 

    } 

    public static void SetUpdatePropertySourceWhenEnterPressed(DependencyObject dp, DependencyProperty value) 
    { 
     dp.SetValue(UpdatePropertySourceWhenEnterPressedProperty, value); 
    } 

    public static DependencyProperty GetUpdatePropertySourceWhenEnterPressed(DependencyObject dp) 
    { 
     return (DependencyProperty)dp.GetValue(UpdatePropertySourceWhenEnterPressedProperty); 
    } 

    private static void OnUpdatePropertySourceWhenEnterPressedPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) 
    { 
     UIElement element = dp as UIElement; 

     if (element == null) 
     { 
      return; 
     } 

     if (e.OldValue != null) 
     { 
      element.PreviewKeyDown -= HandlePreviewKeyDown; 
     } 

     if (e.NewValue != null) 
     { 
      element.PreviewKeyDown += new KeyEventHandler(HandlePreviewKeyDown); 
     } 
    } 

    static void HandlePreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.Key == Key.Enter) 
     { 
      DoUpdateSource(e.Source); 
     } 
    } 

    static void DoUpdateSource(object source) 
    { 
     DependencyProperty property = 
      GetUpdatePropertySourceWhenEnterPressed(source as DependencyObject); 

     if (property == null) 
     { 
      return; 
     } 

     UIElement elt = source as UIElement; 

     if (elt == null) 
     { 
      return; 
     } 

     BindingExpression binding = BindingOperations.GetBindingExpression(elt, property); 

     if (binding != null) 
     { 
      binding.UpdateSource(); 
     } 
    } 
} 

फिर अपने XAML में आप InputBindingsManager.UpdatePropertySourceWhenEnterPressedProperty संपत्ति एक आप को अपडेट करते समय दर्ज कुंजी दबाने चाहते करने के लिए सेट। इस

<TextBox Name="itemNameTextBox" 
     Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" 
     b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"/> 

की तरह (तुम बस कभी नाम स्थान आप में InputBindingsManager डाल अपने XAML फाइल जो की ओर इशारा करते के मूल तत्व में "बी" के लिए एक xmlns clr-नाम स्थान संदर्भ शामिल करने के लिए सुनिश्चित करने की आवश्यकता)।

+0

मैंने कोशिश की <टेक्स्टबॉक्स x: नाम = "itemNameTextBox" टेक्स्ट = "{बाइंडिंग स्रोत, ElementName = webBrowser कस्टम, मोड = दोवे, अपडेटसोर्स ट्रिगर = प्रॉपर्टी चेंजड}" बी: इनपुट बाइंडिंग्स मैनेजर.अपडेटप्रॉपर्टीसोर्सवेन एंटर दबाया गया = "टेक्स्टबॉक्स। टेक्स्ट" /> लेकिन ऐसा लगता है कि वेबब्रोसर अपने स्रोत को अद्यतन नहीं करता है। कुछ भी मुझे याद आया? मैंने किसी भी घटना को संभाल नहीं किया। मैं 2 तरीके बाध्यकारी, अपने ऑटो हैंडल घटना द्वारा मानते हैं। क्या मै गलत हु? धन्यवाद। –

+7

भावी पाठकों को कुछ मिनटों को झुकाव बचाने के प्रयास में, मैंने अभी इसे अपने प्रोजेक्ट में इस्तेमाल किया है, और उपर्युक्त नमूना एक्सएएमएल सही काम नहीं करता है। स्रोत प्रत्येक चरित्र परिवर्तन पर अद्यतन किया गया था। "UpdateSourceTrigger = PropertyChanged" को "UpdateSourceTrigger = Explicit" में बदलकर समस्या को हल किया गया। अब यह सब वांछित के रूप में काम करता है। – ihake

+0

@ihake: मुझे लगता है कि आपका अनुशंसित परिवर्तन – VoteCoffee

45

मुझे विश्वास नहीं है कि आप जो भी वर्णन कर रहे हैं उसे करने के लिए कोई "शुद्ध XAML" तरीका है।

<TextBox Name="itemNameTextBox" 
    Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}" /> 

आप UpdateSourceTrigger करने के लिए "स्पष्ट" सेट करते हैं: जब कोई पाठ बॉक्स परिवर्तन में पाठ इस तरह UpdateSourceTrigger संपत्ति की स्थापना, द्वारा (बल्कि जब पाठ बॉक्स ध्यान केंद्रित खो देता है की तुलना में) इतना है कि यह अद्यतन करता है एक बाध्यकारी सेट कर सकते हैं और फिर टेक्स्टबॉक्स के पूर्वावलोकन केडडाउन ईवेंट (एंटर कुंजी की तलाश में) को संभाला, फिर आप जो चाहते हैं उसे प्राप्त कर सकते हैं, लेकिन इसके लिए कोड-बैक की आवश्यकता होगी। शायद कुछ प्रकार की संलग्न संपत्ति (मेरे EnterKeyTraversal संपत्ति के समान) woudld आपके लिए काम करती है।

+2

यह उत्तर उत्तर के रूप में चिह्नित एक से अधिक सरल हो सकता है, लेकिन इसमें कुछ सीमाएं हैं। छवि आप बाध्य संपत्ति के सेट-फ़ंक्शन में किसी प्रकार की जांच करना चाहते हैं (यह जांचना कि इनपुट मान्य है या नहीं)। उपयोगकर्ता द्वारा दबाए गए प्रत्येक कुंजी के बाद आप उस चेक फ़ंक्शन को कॉल नहीं करना चाहते हैं, क्या आप (विशेष रूप से जब फ़ंक्शन में कुछ समय लगता है)। –

25

आप आसानी से टेक्स्टबॉक्स से विरासत में अपना नियंत्रण बना सकते हैं और इसे अपने पूरे प्रोजेक्ट में पुन: उपयोग कर सकते हैं।

कुछ इस के लिए इसी तरह काम करना चाहिए:

public class SubmitTextBox : TextBox 
{ 
    public SubmitTextBox() 
     : base() 
    { 
     PreviewKeyDown += new KeyEventHandler(SubmitTextBox_PreviewKeyDown); 
    } 

    void SubmitTextBox_PreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.Key == Key.Enter) 
     { 
      BindingExpression be = GetBindingExpression(TextBox.TextProperty); 
      if (be != null) 
      { 
       be.UpdateSource(); 
      } 
     } 
    } 
} 

वहाँ एक तरह से इस कदम के आसपास पाने के लिए हो सकता है, लेकिन अन्यथा आप इस तरह बाँध (स्पष्ट का प्रयोग करके) करना चाहिए:

<custom:SubmitTextBox 
    Text="{Binding Path=BoundProperty, UpdateSourceTrigger=Explicit}" /> 
+9

डब्ल्यूपीएफ/सिल्वरलाइट में आपको कभी भी विरासत का उपयोग नहीं करना चाहिए - यह शैलियों को गड़बड़ करता है और संलग्न व्यवहार के रूप में लचीला नहीं है। उदाहरण के लिए संलग्न व्यवहार के साथ आप एक ही टेक्स्टबॉक्स पर वॉटरमार्क और अपडेटऑन एंटर दोनों प्राप्त कर सकते हैं। – Mikhail

2

मामले में आप अपने टेक्स्टबॉक्स के साथ मल्टीबाइंडिंग का उपयोग कर रहे हैं, आपको के बजाय BindingOperations.GetMultiBindingExpression विधि का उपयोग करने की आवश्यकता है।

// Get the correct binding expression based on type of binding 
//(simple binding or multi binding. 
BindingExpressionBase binding = 
    BindingOperations.GetBindingExpression(element, prop); 
if (binding == null) 
{ 
    binding = BindingOperations.GetMultiBindingExpression(element, prop); 
} 

if (binding != null) 
{ 
    object value = element.GetValue(prop); 
    if (string.IsNullOrEmpty(value.ToString()) == true) 
    { 
     binding.UpdateTarget(); 
    } 
    else 
    { 
      binding.UpdateSource(); 
    } 
} 
33

इस प्रकार मैंने इस समस्या को हल किया। मैं एक विशेष ईवेंट हैंडलर कि पीछे कोड में चला गया बनाया:

<TextBox Text="{Binding TextValue1}" KeyUp="TextBox_KeyEnterUpdate" /> 
<TextBox Text="{Binding TextValue2}" KeyUp="TextBox_KeyEnterUpdate" /> 

ईवेंट हैंडलर अपनी sender संदर्भ का उपयोग करता है पैदा करने के लिए:

private void TextBox_KeyEnterUpdate(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.Enter) 
    { 
     TextBox tBox = (TextBox)sender; 
     DependencyProperty prop = TextBox.TextProperty; 

     BindingExpression binding = BindingOperations.GetBindingExpression(tBox, prop); 
     if (binding != null) { binding.UpdateSource(); } 
    } 
} 

तब मैं सिर्फ XAML में एक KeyUp ईवेंट हैंडलर के रूप में इस जोड़ा अपडेट होने के लिए यह स्वयं बाध्यकारी है। चूंकि इवेंट हैंडलर स्वयं निहित है, इसलिए इसे जटिल डेटा टेम्पलेट में काम करना चाहिए। यह एक ईवेंट हैंडलर अब उन सभी टेक्स्टबॉक्स में जोड़ा जा सकता है जिन्हें इस सुविधा की आवश्यकता है।

+4

कुछ मुझे बताता है कि यह एक अंडररेड पोस्ट है। बहुत से जवाब लोकप्रिय हैं क्योंकि वे "एक्सएएमएल-वाई" हैं। लेकिन यह ज्यादातर अवसरों में अंतरिक्ष को बचाने के लिए प्रतीत होता है। –

+1

+1 यह आपको अकेले अपडेटसोर्स ट्रिगर छोड़ने की इजाजत देता है यदि आप पहले से ही अपने टेक्स्टबॉक्स बाइंडिंग को पहले से ही जिस तरह से चाहते हैं (शैलियों, सत्यापन, twoway, आदि के साथ व्यवहार करने के लिए दर्दनाक रूप से प्राप्त कर चुके हैं), लेकिन वर्तमान में दबाने के बाद इनपुट प्राप्त नहीं होगा दर्ज। – Jamin

+0

यह सबसे साफ दृष्टिकोण है जो मैंने पाया है, और मेरी राय में उत्तर के रूप में चिह्नित किया जाना चाहिए। स्रोत प्रॉपर्टी को अपडेट करने के बाद टेक्स्टबॉक्स से फोकस हटाने के लिए प्रेषक पर एक अतिरिक्त शून्य जांच, कुंजी पर वापसी। मेरे कुंजीपटल रिटर्न कुंजी। रीटर्न पर कुंजी दर्ज करें, और कीबोर्ड। क्लीयरफोकस()। मैंने उत्तर में संपादन किया है जो सहकर्मी समीक्षा का इंतजार कर रहा है। – Oystein

4

यहां एक दृष्टिकोण है जो मेरे लिए एक सरल तरीका है, और आसान है कि एक संलग्न Behaviour (जो एक वैध समाधान भी है) जोड़ना आसान है। हम डिफॉल्ट अपडेटसोर्स ट्रिगर (टेक्स्टबॉक्स के लिए लॉस्टफोकस) का उपयोग करते हैं, और फिर एक कमांड के लिए बाध्य एंटर कुंजी में इनपुट बाइंडिंग जोड़ें।

XAML के रूप में इस प्रकार है

 <TextBox Grid.Row="0" Text="{Binding Txt1}" Height="30" Width="150"> 
     <TextBox.InputBindings> 
      <KeyBinding Gesture="Enter" 
         Command="{Binding UpdateText1Command}" 
         CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}},Path=Text}" /> 
     </TextBox.InputBindings> 
    </TextBox> 

फिर कमान तरीकों

Private Function CanExecuteUpdateText1(ByVal param As Object) As Boolean 
    Return True 
End Function 
Private Sub ExecuteUpdateText1(ByVal param As Object) 

    If TypeOf param Is String Then 
     Txt1 = CType(param, String) 
    End If 
End Sub 

हैं और पाठबॉक्स संपत्ति के लिए बाध्य है है

अभी तक यह अच्छी तरह से काम करने लगता है और टेक्स्टबॉक्स में एंटर कुंजी ईवेंट पकड़ता है।

3

अधिक सरल, कोड 0hPropertyChanged पर TextBox के बाध्यकारी में कोडबेहिंड में कुछ भी जोड़ने के बिना बस सेट करें। बस इस तरह:

<TextBox Text="{Binding Path=BoundProperty, UpdateSourceTrigger=PropertyChanged}"/> 

यह मेरे लिए काम करता है।

+0

यह काम करता है, लेकिन यह प्रत्येक चरित्र परिवर्तन – VoteCoffee

11

तुम दोनों बेन और ausadmin के समाधान गठबंधन हैं, तो आप एक बहुत MVVM अनुकूल समाधान के साथ अंत:

<TextBox Text="{Binding Txt1, Mode=TwoWay, UpdateSourceTrigger=Explicit}"> 
    <TextBox.InputBindings> 
     <KeyBinding Gesture="Enter" 
        Command="{Binding UpdateTextBoxBindingOnEnterCommand}" 
        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}" /> 
    </TextBox.InputBindings> 
</TextBox> 

... जिसका मतलब है कि आप Command को पैरामीटर के रूप में TextBox गुजर रहे हैं ही।

public bool CanExecuteUpdateTextBoxBindingOnEnterCommand(object parameter) 
    { 
     return true; 
    } 

    public void ExecuteUpdateTextBoxBindingOnEnterCommand(object parameter) 
    { 
     TextBox tBox = parameter as TextBox; 
     if (tBox != null) 
     { 
      DependencyProperty prop = TextBox.TextProperty; 
      BindingExpression binding = BindingOperations.GetBindingExpression(tBox, prop); 
      if (binding != null) 
       binding.UpdateSource(); 
     } 
    } 

यह Command कार्यान्वयन सब कोई कोड का सबसे अच्छा किसी भी TextBox के लिए इस्तेमाल किया जा सकता है:

यह आपके Command इस तरह लग रही (यदि आप अपने वी एम में एक DelegateCommand शैली कार्यान्वयन का उपयोग कर रहे हैं) की ओर जाता है कोड-बैक में हालांकि आप इसे अपनी कक्षा में रखना चाहते हैं, इसलिए आपके वीएम में System.Windows.Controls पर कोई निर्भरता नहीं है। यह इस बात पर निर्भर करता है कि आपके कोड दिशानिर्देश कितने सख्त हैं।

+0

नाइस पर अपडेट होगा। बहुत साफ। यदि एक मल्टीबाइंडिंग शामिल है, तो आपको बाइंडिंगऑपरेशंस का उपयोग करने की आवश्यकता हो सकती है। GETBindingExpressionBase (tBox, prop); और फिर बाध्यकारी। अद्यतनडेटा(); – VoteCoffee

0

यह मेरे लिए काम करता है:

 <TextBox     
      Text="{Binding Path=UserInput, UpdateSourceTrigger=PropertyChanged}"> 
      <TextBox.InputBindings> 
       <KeyBinding Key="Return" 
          Command="{Binding Ok}"/> 
      </TextBox.InputBindings> 
     </TextBox> 
1

यहाँ उत्तर दिया काफी सुंदर ढंग से संलग्न व्यवहार, लगभग कुछ के लिए मेरे पसंदीदा तरीका इस्तेमाल करते हैं।

WPF how to make textbox lose focus after hitting enter

0

इस मूल प्रश्न का उत्तर है, बल्कि @Samuel जैक द्वारा accepted answer का एक विस्तार नहीं है। मैंने अपने आवेदन में निम्नलिखित किया, और सैमुअल के समाधान के लालित्य के भय से डर गया। यह बहुत साफ है, और बहुत पुन: प्रयोज्य है, क्योंकि इसका उपयोग किसी भी नियंत्रण पर किया जा सकता है, न केवल TextBox। मैंने सोचा कि इसे समुदाय के साथ साझा किया जाना चाहिए।

आप एक हजार TextBoxes कि सभी दर्ज करें पर बाइंडिंग स्रोत अद्यतन करने के लिए आवश्यकता होती है के साथ एक खिड़की है, तो आप XAML अपने WindowResources में नीचे सहित बजाय प्रत्येक पाठ बॉक्स को अटैच कर उन सभी को इस व्यवहार संलग्न कर सकते हैं। सबसे पहले आपको संलग्न व्यवहार को Samuel's post के अनुसार लागू करना होगा।

<Window.Resources> 
    <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}"> 
     <Style.Setters> 
      <Setter Property="b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed" Value="TextBox.Text"/> 
     </Style.Setters> 
    </Style> 
</Window.Resources> 

तुम हमेशा यदि खिड़की के बच्चे तत्वों में से एक के संसाधन में शैली रख कर, की जरूरत है, दायरा सीमित कर सकते हैं (उदाहरण के लिए Grid) कि लक्ष्य बक्सें में शामिल है।

संबंधित मुद्दे