2013-06-04 4 views
8

निम्नलिखित सरल WPF आवेदन में पर क्लिक LostFocus को बढ़ाया नहीं गया एक TextBox जब फोकस तोपाठ बॉक्स जब कुछ अन्य नियंत्रण

<DockPanel> 
    <ToolBar DockPanel.Dock="Top"> 
     <Button>Test</Button> 
    </ToolBar> 
    <TextBox Text="{Binding MyString}" /> 
</DockPanel> 

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = this; 
} 

public string MyString 
{ 
    get { return _myString; } 
    set { _myString = value; } 
} 

हालांकि जब मैं चलाने की तरह है, कि नियंत्रण से खो दिया है एक संपत्ति अद्यतन करने के लिए सेट कर दिया जाता इस आवेदन, पाठ बॉक्स में कुछ पाठ दर्ज करें और फिर MyString संपत्ति पर मेरी ब्रेकप्वाइंट नहीं उठाया, भी FocusLost घटना के लिए किसी भी इवेंट हैंडलर या तो बढ़ाया नहीं गया है "टेस्ट" बटन पर क्लिक करें। इन घटनाओं केवल उठाया जाता है जब फ़ोकस को किसी और तरीके के माध्यम से नियंत्रण से खो दिया है (उदाहरण के लिए विंडो बंद हो)।

यह वास्तव में के रूप में हमारे लिए समस्याएं खड़ी कर रहा है "टेस्ट" बटन तर्क जो MyString संपत्ति अपडेट की जा रही पर निर्भर करता है शामिल हैं।

मैं कैसे सुनिश्चित कर सकता हूं कि FocusLost ईवेंट सही ढंग से उठाया गया है और बाध्यकारी अद्यतन किया गया है क्योंकि मैं "टेस्ट" बटन पर क्लिक करता हूं? ऐसा लगता है कि समस्या किसी भी तरह एक मानक बटन के साथ ToolBar की जगह इस व्यवहार में परिणाम नहीं करता है के रूप में, ToolBar के उपयोग के कारण होता है।

उत्तर

2

इस मामले में टेक्स्ट बॉक्स वास्तव में नहीं ढीला तार्किक ध्यान और इसलिए घटना उठाया कभी नहीं करता है - अनिवार्य रूप से मैं वास्तव में LostKeyboardFocus घटना है, और न अपडेट लागू करने के LostFocus घटना चाहते हैं।

यह समस्या WPF: Data bound TabControl doesn't commit changes when new tab is selected के समान है और इसके लिए कई संभावित समाधानों के साथ here के लिए एक माइक्रोसॉफ्ट कनेक्ट आइटम है, हालांकि मैंने इसे एक संलग्न संपत्ति का उपयोग करके तय किया है।

public static readonly DependencyProperty BindOnLostKeyboardFocusProperty = 
    DependencyProperty.RegisterAttached("BindOnLostKeyboardFocus", typeof(bool), typeof(MainWindow), new PropertyMetadata(default(bool), BindOnLostKeyboardFocusChanged)); 

private static void BindOnLostKeyboardFocusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
{ 
    var control = o as UIElement; 
    if (control != null) 
    { 
     if ((bool) e.NewValue) 
     { 
      control.AddHandler(LostKeyboardFocusEvent, new RoutedEventHandler(ControlLostKeyboardFocus)); 
     } 
     else 
     { 
      control.RemoveHandler(LostKeyboardFocusEvent, new RoutedEventHandler(ControlLostKeyboardFocus)); 
     } 
    } 
} 

private static void ControlLostKeyboardFocus(object sender, RoutedEventArgs e) 
{ 
    var control = (UIElement)sender; 
    control.RaiseEvent(new RoutedEventArgs(LostFocusEvent)); 
} 

यह सिर्फ मतलब है कि जब भी LostKeyboardFocus कि नियंत्रण के लिए उठाया है, यह आगे चला जाता है और अद्यतन करने के लिए बाध्यकारी के कारण एक अतिरिक्त LostFocus घटना उठाती है। इसकी तरह तो

<TextBox Text="{Binding Test}" LostKeyboardFocus="UIElement_OnLostKeyboardFocus" local:MainWindow.BindOnLostKeyboardFocus="True" /> 
2

आपकी अनुलग्न संपत्ति मान्यताओं की एक जोड़ी बनाता है इस्तेमाल किया:

  • कि कुछ भी नहीं LostKeyboardFocus और LostFocus घटनाओं के बीच के अंतर के आधार पर किया जाता है
  • उस तत्व पर बाइंडिंग यह संलग्न है वास्तव में LostFocus ईवेंट का जवाब देगा (वे UpdateSourceTrigger.Explicit हो सकते हैं)

इसके बजाय, आप तत्व पर बाइंडिंग की गणना कर सकते हैं और सीधे UpdateSource फोन:

private void CommitBindings(DependencyObject element) { 
    var localValueEnumerator = element.GetLocalValueEnumerator(); 
    while (localValueEnumerator.MoveNext()) { 
     var entry = localValueEnumerator.Current; 
     if (BindingOperations.IsDataBound(element, entry.Property)) { 
      var bindingExpression = (BindingExpressionBase)entry.Value; 
      bindingExpression.UpdateSource(); 
     } 
    } 
} 

इसके अलावा, बजाय प्रत्येक TextBox से निपटने को व्यक्तिगत रूप से, आप कंटेनर को संभाल सकता है और OldFocus का उपयोग वास्तविक तत्व यह है कि कीबोर्ड फ़ोकस खो दिया पाने के लिए।

0

निम्नलिखित व्यवहार ठीक कर देंगे:

public class TextBoxUpdateOnLostKeyboardFocusBehavior : Behavior<TextBox> 
{ 
    protected override void OnAttached() 
    { 
     if (AssociatedObject != null) 
     { 
      base.OnAttached(); 
      AssociatedObject.LostKeyboardFocus += OnKeyboardLostFocus; 
     } 
    } 

    protected override void OnDetaching() 
    { 
     if (AssociatedObject != null) 
     { 
      AssociatedObject.LostKeyboardFocus -= OnKeyboardLostFocus; 
      base.OnDetaching(); 
     } 
    } 

    private void OnKeyboardLostFocus(object sender, KeyboardFocusChangedEventArgs e) 
    { 
     var textBox = sender as TextBox; 

     if (textBox != null && e.NewFocus == null) 
     { 
      // Focus on the closest focusable ancestor 
      FrameworkElement parent = (FrameworkElement) textBox.Parent; 
      while (parent is IInputElement && !((IInputElement) parent).Focusable) 
      { 
       parent = (FrameworkElement) parent.Parent; 
      } 

      DependencyObject scope = FocusManager.GetFocusScope(textBox); 
      FocusManager.SetFocusedElement(scope, parent); 
     } 
    } 
} 

इस प्रकार आप अपने पाठ बॉक्स में अटैच कर सकते हैं:

 <TextBox> 
      <i:Interaction.Behaviors> 
       <behaviors1:TextBoxUpdateOnLostKeyboardFocusBehavior /> 
      </i:Interaction.Behaviors>    
     </TextBox> 
संबंधित मुद्दे