2012-10-17 25 views
19

निम्न स्थिति है। मुझे पांच कीबाइंडिंग के साथ UserControl मिला है। जब टेक्स्टबॉक्स ने फोकस किया है तो UserControl रोकथाम बंद करने की कीबाइंडिंग ..UserControl में कीबाइंडिंग काम नहीं करती है जब टेक्स्टबॉक्स पर फोकस

क्या इस समस्या को ठीक करने का कोई तरीका है?

<UserControl.InputBindings> 
    <KeyBinding Key="PageDown" Modifiers="Control" Command="{Binding NextCommand}"></KeyBinding> 
    <KeyBinding Key="PageUp" Modifiers="Control" Command="{Binding PreviousCommand}"></KeyBinding> 
    <KeyBinding Key="End" Modifiers="Control" Command="{Binding LastCommand}"></KeyBinding> 
    <KeyBinding Key="Home" Modifiers="Control" Command="{Binding FirstCommand}"></KeyBinding> 
    <KeyBinding Key="F" Modifiers="Control" Command="{Binding SetFocusCommand}"></KeyBinding> 
</UserControl.InputBindings> 
<TextBox Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"> 
    <TextBox.InputBindings> 
     <KeyBinding Gesture="Enter" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl }}, Path=DataContext.FilterCommand}"></KeyBinding> 
    </TextBox.InputBindings> 
</TextBox> 

ऐसा लगता है फ़ंक्शन कुंजियों (एफ 1 आदि) और एएलटी + [कुंजी] काम करते हैं। मुझे लगता है कि CTRL और SHIFT संशोधक किसी भी तरह से UserControl तक बुलबुले से ईवेंट को अवरुद्ध कर रहे हैं।

+0

टेक्स्टबॉक्स उपयोगकर्ता नियंत्रण के अंदर है? –

+0

@ डीजे बिल्कुल। UserControl कंटेनर है और (इस उदाहरण में) टेक्स्टबॉक्स इसके अंदर है। यह कॉम्बोबॉक्स, डाटाग्रिड इत्यादि के लिए भी काम करता है –

उत्तर

38

कुछ इनपुट बाइंडिंग काम करने का कारण है और कुछ ऐसा नहीं है कि टेक्स्टबॉक्स नियंत्रण कुछ महत्वपूर्ण बाइंडिंग को पकड़ता है और संभालता है। उदाहरण के लिए, यह दूसरी ओर आदि पाठ की शुरुआत, अन्य कुंजी संयोजन ऐसे CTRL + रूप F3 के लिए जा रहा के लिए CTRL + वी पेस्ट के लिए, CTRL + होम हैंडल नहीं कर रहे टेक्स्टबॉक्स द्वारा संभाला नहीं जाता है, और इसलिए वे बबल हो जाएंगे।

यदि आप टेक्स्टबॉक्स के इनपुट बाध्यकारी को अक्षम करना चाहते हैं, तो यह आसान होगा - आप ApplicationCommands.NotACommand कमांड का उपयोग कर सकते हैं, जो डिफ़ॉल्ट व्यवहार को अक्षम कर देगा। उदाहरण के लिए, निम्नलिखित मामले में, साथ CTRL + वी अक्षम कर दिया जाएगा चिपकाने:

<TextBox> 
    <TextBox.InputBindings> 
     <KeyBinding Key="V" Modifiers="Control" Command="ApplicationCommands.NotACommand" /> 
    </TextBox.InputBindings> 
</TextBox> 

हालांकि, उपयोगकर्ता नियंत्रण करने के लिए यह बुलबुला बनाने थोड़ा जटिल काम है। मेरा सुझाव है कि एक संलग्न व्यवहार बनाना है जिसे UserControl पर लागू किया जाएगा, PreviewKeyDown ईवेंट पर पंजीकरण करें, और टेक्स्टबॉक्स तक पहुंचने से पहले आवश्यकतानुसार इनपुट इनपुट बाइंडिंग निष्पादित करें। इनपुट बाइंडिंग निष्पादित होने पर यह UserControl को प्राथमिकता देगा।

मैं एक बुनियादी व्यवहार है कि इस कार्यक्षमता को प्राप्त होता है आरंभ करने के लिए लिखा है:

public class InputBindingsBehavior 
{ 
    public static readonly DependencyProperty TakesInputBindingPrecedenceProperty = 
     DependencyProperty.RegisterAttached("TakesInputBindingPrecedence", typeof(bool), typeof(InputBindingsBehavior), new UIPropertyMetadata(false, OnTakesInputBindingPrecedenceChanged)); 

    public static bool GetTakesInputBindingPrecedence(UIElement obj) 
    { 
     return (bool)obj.GetValue(TakesInputBindingPrecedenceProperty); 
    } 

    public static void SetTakesInputBindingPrecedence(UIElement obj, bool value) 
    { 
     obj.SetValue(TakesInputBindingPrecedenceProperty, value); 
    } 

    private static void OnTakesInputBindingPrecedenceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((UIElement)d).PreviewKeyDown += new KeyEventHandler(InputBindingsBehavior_PreviewKeyDown); 
    } 

    private static void InputBindingsBehavior_PreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     var uielement = (UIElement)sender; 

     var foundBinding = uielement.InputBindings 
      .OfType<KeyBinding>() 
      .FirstOrDefault(kb => kb.Key == e.Key && kb.Modifiers == e.KeyboardDevice.Modifiers); 

     if (foundBinding != null) 
     { 
      e.Handled = true; 
      if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) 
      { 
       foundBinding.Command.Execute(foundBinding.CommandParameter); 
      } 
     } 
    } 
} 

उपयोग:

<UserControl local:InputBindingsBehavior.TakesInputBindingPrecedence="True"> 
    <UserControl.InputBindings> 
     <KeyBinding Key="Home" Modifiers="Control" Command="{Binding MyCommand}" /> 
    </UserControl.InputBindings> 
    <TextBox ... /> 
</UserControl> 

आशा इस मदद करता है।

+0

मुझे यह पसंद है! कुछ प्रयोग करने जा रहे हैं, धन्यवाद –

+0

@AdiLester मैंने आपके समाधान की कोशिश की है। मैंने बस अपनी लैम्ब्डा अभिव्यक्ति को 'kb => kb.Key == key.Enter' के साथ बदल दिया है। मैंने 'Key' से' Enter' में 'Key' से' Enter' में 'Key' को भी बदल दिया। और 'Modifiers' हटा दिया। मेरा टेक्स्टबॉक्स DataGridColumnHeader के अंदर रहता है। इसलिए, मैंने संलग्न संपत्ति को डेटाग्रिड पर लागू किया। अब, जब मैं एंटर के अलावा किसी भी कुंजी को दबाता हूं, उदाहरण के लिए नीचे तीर कुंजी, आदेश आग। जब मैं एंटर कुंजी दबाता हूं तो मैं बस अपने कमांड को आग लगाना चाहता हूं। क्या आप उपर्युक्त कोड में कुछ बदलाव प्रदान कर सकते हैं ???? – Vishal

+0

@Adi लेस्टर पूर्वावलोकनकेडाउन + = नया कीवेन्टहैंडलर जहां आप घटना से अनियंत्रित करते हैं? – Gilad

4

आदि लेस्टर का समाधान अच्छी तरह से काम करता है। व्यवहार का उपयोग कर एक समान समाधान यहाँ है। सी # कोड:

public class AcceptKeyBinding : Behavior<UIElement> 
{ 


    private TextBox _textBox; 



    /// <summary> 
    /// Subscribes to the PreviewKeyDown event of the <see cref="TextBox"/>. 
    /// </summary> 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 

     _textBox = AssociatedObject as TextBox; 

     if (_textBox == null) 
     { 
      return; 
     } 

     _textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown; 
    } 

    private void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs keyEventArgs) 
    { 
     var uielement = (UIElement)sender; 

     var foundBinding = uielement.InputBindings 
      .OfType<KeyBinding>() 
      .FirstOrDefault(kb => kb.Key == keyEventArgs.Key && kb.Modifiers ==   keyEventArgs.KeyboardDevice.Modifiers); 

     if (foundBinding != null) 
     { 
      keyEventArgs.Handled = true; 
      if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) 
      { 
       foundBinding.Command.Execute(foundBinding.CommandParameter); 
      } 
     } 
    } 

    /// <summary> 
    ///  Unsubscribes to the PreviewKeyDown event of the <see cref="TextBox"/>. 
    /// </summary> 
    protected override void OnDetaching() 
    { 
     if (_textBox == null) 
     { 
      return; 
     } 

     _textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown; 

     base.OnDetaching(); 
    } 

} 

और XAML:

<TextBox> 
    <TextBox.InputBindings> 
     <KeyBinding Key="Enter" Modifiers="Shift" Command="{Binding CommandManager[ExecuteCommand]}" 
      CommandParameter="{Binding ExecuteText}" /> 
    </TextBox.InputBindings> 
     <i:Interaction.Behaviors> 
     <behaviours:AcceptKeyBinding /> 
     </i:Interaction.Behaviors> 
</TextBox> 
0
<UserControl.Style> 
    <Style TargetType="UserControl"> 
     <Style.Triggers> 
      <Trigger Property="IsKeyboardFocusWithin" Value="True"> 
       <Setter Property="FocusManager.FocusedElement" Value=" {Binding ElementName=keyPressPlaceHoler}" /> 
       </Trigger> 
     </Style.Triggers> 
    </Style> 
</UserControl.Style> 

keyPressPlaceHoleruielement

usercontrol में Focusable="True" स्थापित करने के लिए याद अपने लक्ष्य के कंटेनर का नाम है

0

इसके अतिरिक्त एडी लेस्टर को उनके (बहुत उपयोगी) उत्तर में मैं कुछ सुधार/एक्सटेंशन सुझाऊंगा जो मुझे मेरे कार्यान्वयन में मदद करते हैं।

Gesture.Matches

foundBinding भी Gesture.Matches फोन करके किया जा सकता है। निम्न के foundBinding LINQ क्वेरी बदलें:

KeyBinding foundBinding = ((UIElement)this).InputBindings 
      .OfType<KeyBinding>() 
      .FirstOrDefault(inputBinding => inputBinding.Gesture.Matches(sender, eventArgs)); 

MouseBinding इसके अलावा आप भी MouseBindings परिभाषित कर सकते हैं।

<MouseBinding Command="{Binding DataContext.AddInputValueCommand, ElementName=root}" CommandParameter="{Binding}" Gesture="Shift+MiddleClick" /> 

फिर आप भी जैसे PreviewMouseEvents की सदस्यता के लिए की जरूरत है पूर्वावलोकनमाउसअप और पूर्वावलोकनमाउस डबलक्लिक करें। कार्यान्वयन लगभग KeyBindings के लिए लगभग समान है।

private void OnTextBoxPreviewMouseUp(object sender, MouseButtonEventArgs eventArgs) 
{ 
    MouseBinding foundBinding = ((UIElement)this).InputBindings 
     .OfType<MouseBinding>() 
     .FirstOrDefault(inputBinding => inputBinding.Gesture.Matches(sender, eventArgs)); 

    if (foundBinding != null) 
    { 
     eventArgs.Handled = true; 
     if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) 
     { 
      foundBinding.Command.Execute(foundBinding.CommandParameter); 
     } 
    } 
}