2012-06-18 17 views
8

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

क्या एक शानदार तरीके से अद्यतन को मजबूर करने का कोई तरीका है? मैं एमवीवीएम (लेकिन कोई भी एमवीवीएम फ्रेमवर्क नहीं) का उपयोग कर रहा हूं, इसलिए मैं कमांड कोड से यूआई विशिष्ट चीजों को रखना चाहता हूं। इसके अलावा मैं वास्तव में हर बदलाव पर अपडेट करने के लिए बाइंडिंग को बदलना नहीं चाहता हूं, यह ठीक है कि फोकस खो जाने पर ही इसे अपडेट करना ठीक है।

उत्तर

2

मैं स्पष्ट रूप मूल्यों के लिए पूछ रहा से पहले कुछ अन्य तत्व को फोकस सेट करके ऐसा समाधान कर लिया है अब। यह स्पष्ट रूप से उस तत्व को बनाता है जिस पर वर्तमान में फोकस इसे खो देता है और बाध्यकारी अद्यतन करता है।

फोकस सेट करने के लिए, मैंने एक संलग्न संपत्ति लिखी है, जो अन्य प्रश्नों के उत्तर से प्रेरित है। इसके अलावा, my other question के साथ मैंने इसे कुछ हद तक स्वचालित बना दिया।

तो उपयोग करने के लिए यह, मैं मूल रूप से मेरी संपत्ति एक तत्व के लिए एक टैब नियंत्रण देते हैं, इस मामले में:

<TabControl c:Util.ShouldFocus="{Binding ShouldClearFocus}"> 

मेरे विचार मॉडल में, मैं एक साधारण बूलियन संपत्ति ShouldClearFocus है कि एक मानक संपत्ति को ऊपर उठाने है एक PropertyChangedEvent, इसलिए डेटा बाध्यकारी काम करता है। जब मैं फोकस रीसेट करना चाहता हूं तो मैं बस ShouldClearFocus से true पर सेट करता हूं। संलग्न संपत्ति स्वचालित रूप से फोकस सेट करती है और संपत्ति मान को फिर से रीसेट करती है। इस तरह मैं को false पर सेट किए बिना सेट कर सकता हूं।

जुड़ी संपत्ति अपने परिवर्तन हैंडलर के रूप में इस के साथ एक मानक कार्यान्वयन है:

public static void ShouldFocusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    if (!(bool)e.NewValue || !(obj is FrameworkElement)) 
     return; 

    FrameworkElement element = (FrameworkElement)obj; 
    if (element.Focusable) 
     element.Focus(); 

    // reset value 
    BindingExpression bindingExpression = BindingOperations.GetBindingExpression(obj, ShouldFocusProperty); 
    if (bindingExpression != null) 
    { 
     PropertyInfo property = bindingExpression.DataItem.GetType().GetProperty(bindingExpression.ParentBinding.Path.Path); 
     if (property != null) 
      property.SetValue(bindingExpression.DataItem, false, null); 
    } 
    else 
     SetShouldFocus(obj, false); 
} 
+0

अब तक, इस मंच पर प्रस्तावित सबसे लचीला/सुरुचिपूर्ण समाधान। बहुत अच्छा काम किया - धन्यवाद – BCA

2

यहाँ वर्ग मैं एक ऐसी ही स्थिति के लिए इस्तेमाल किया है:

public class TextBoxUpdatesTextBindingOnPropertyChanged : Behavior<TextBox> 
{ 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 

     AssociatedObject.TextChanged += TextBox_TextChanged; 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 

     AssociatedObject.TextChanged -= TextBox_TextChanged; 
    } 

    void TextBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     var bindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty); 
     bindingExpression.UpdateSource(); 
    } 
} 

XAML:

<TextBox Text="{Binding UserName,Mode=TwoWay,UpdateSourceTrigger=Explicit}"> 
    <i:Interaction.Behaviors> 
     <h:TextBoxUpdatesTextBindingOnPropertyChanged /> 
    </i:Interaction.Behaviors> 
</TextBox> 

कॉलिंग OnPropertyChanged("YourPropertyName") सीमित मान अद्यतन करने के लिए दृश्य सूचित करेंगे।

अन्यथा यह उत्तर देखें: WPF TextBox DataBind on EnterKey press

+0

समस्या डेटा → दृश्य से बाध्यकारी नहीं है, यह दूसरी तरफ है। मैं डेटा पक्ष पर एक अद्यतन मजबूर करना चाहता हूँ। – poke

+0

ठीक है, मैंने जो लिंक पोस्ट किया है, वह दिखाता है कि एक व्यवहार कैसे बनाया जाए जो बाध्यकारी (डेटा पक्ष पर) को अद्यतन करेगा जब नियंत्रण पर एक निश्चित घटना फेंक दी जाएगी। यदि आप इसे KeyPressed या KeyUp ईवेंट तक तार करते हैं, तो आपको जिस प्रभाव की आवश्यकता है उसे प्राप्त करना चाहिए। –

+0

उस समाधान में 'UpdateSourceTrigger' को 'PropertyChanged'' पर सेट करना शामिल है जो पहले से ही पर्याप्त होना चाहिए, जैसा कि सवाल में कहा गया है, जो मैं चाहता हूं। मैं ट्रिगर को बदलने के बिना ऐसा करने का एक तरीका ढूंढ रहा हूं। – poke

0

मैं अपनी परियोजनाओं में निम्नलिखित का उपयोग करता हूं। समस्या यह है कि बटन फोकस प्राप्त नहीं किया था।

मेरी app.xaml.cs में

EventManager.RegisterClassHandler(typeof(Button), ButtonBase.ClickEvent, new RoutedEventHandler(ButtonClick)); 

    private void ButtonClick(object sender, RoutedEventArgs e) 
    { 
     if (sender != null && sender is Button) 
     { 
      (sender as Button).Focus(); 
     } 
    } 
+0

वह समाधान स्वीकार्य होगा लेकिन मेरे पास क्लिक करने वाला बटन नहीं है। कमांड को 'कीबाइंडिंग' द्वारा बुलाया जाता है। – poke

9

बल्कि फोकस आप भी सिर्फ बाध्यकारी स्रोत अद्यतन सकता है अगर वर्तमान तत्व एक TextBox है बदल रहा है। आप अन्य नियंत्रणों के लिए कुछ भी कर सकते हैं लेकिन मेरे अनुभव में मुझे केवल TextBox के साथ यह समस्या हुई है।

// if the current focused element is textbox then updates the source. 
var focusedElement = Keyboard.FocusedElement as FrameworkElement; 

if (focusedElement is TextBox) 
{ 
    var expression = focusedElement.GetBindingExpression(TextBox.TextProperty); 
    if (expression != null) expression.UpdateSource(); 
} 
+0

अच्छा विचार, आप इसे एमवीवीएम सेटअप में कहां रखेंगे? - यह भी नहीं पता था कि बाध्यकारी अभिव्यक्ति पर वास्तव में 'अपडेटसोर्स' विधि है, इसके लिए धन्यवाद! – poke

+0

मुझे लगता है कि आपको इसे अपनी संलग्न संपत्ति में रखना होगा - बस यह अनुमान लगाया गया है कि यह आगे बढ़ने पर एक सुधार है। आप इस कार्यक्षमता को संभालने के लिए एंटरप्राइज़ लाइब्रेरी से कंपोजिट कमांड जैसे कुछ भी उपयोग कर सकते हैं, लेकिन यह वास्तव में इस पर निर्भर करता है कि आपका एप्लिकेशन किस प्रकार संरचित है। –

0

मुझे लगता है कि यह करने के लिए सबसे अच्छा तरीका है स्थापित करने के लिए है बंधन के UpdateSourceTrigger=PropertyChanged, और फिर Reactive Extensions का उपयोग कर घटना धारा रुके।इस प्रकार संपत्ति केवल तभी अपडेट होगी जब उपयोगकर्ता ने कुछ निश्चित समय के लिए टाइप करना बंद कर दिया हो (1/2 सेकेंड एक अच्छी राशि है)।

यह बहुत अच्छा है क्योंकि संपत्ति हर समय अपडेट नहीं होगी, लेकिन यह बदलने के लिए ध्यान देने की आवश्यकता के बिना भी अपडेट हो जाएगी। वास्तव में आप क्या चाहते हैं।

Here is some really useful information on Rx

bindable IObservables here है कि एक MVVM एक्सटेंशन पुस्तकालय नहीं है। उनके यहां जो उदाहरण है, वह वही कर रहा है जो मैंने सुझाया था।

आपने लालित्य के लिए कहा: यहां यह है। और यह इतना काम नहीं है।

3

अपने TextBox पर, आपको अपने टेक्स्ट बाध्यकारी पर UpdateSourceTrigger सेट करने की आवश्यकता है जो परिभाषित करता है कि स्रोत टेक्स्टबॉक्स मान के साथ कब अपडेट किया जाएगा। डिफ़ॉल्ट रूप से यह LostFocusText संपत्ति के लिए है, जो वास्तव में हो रहा है - यह केवल स्रोत को अपडेट करता है जब यह फोकस खो देता है। आपको UpdateSourceTrigger से PropertyChanged का मान निर्धारित करना चाहिए और जब भी टेक्स्टबॉक्स मान बदलता है तो यह अपडेट हो जाएगा।

उदा।

<TextBox ... Text="{Binding Foo, UpdateSourceTrigger=PropertyChanged}"/> 

पथ सामान्य प्रॉपर्टी जब बाइंडिंग आदेश का उपयोग, इसलिए ऊपर Path=Foo

+0

प्रश्न से: * "मैं भी वास्तव में हर बदलाव पर अद्यतन करने के लिए बाध्यकारी नहीं बदलना चाहता" *। – poke

0

के बराबर वहाँ लचीला/सुरुचिपूर्ण चीज़ें यहाँ का एक बहुत है है। मैं इस मुद्दे को हल करने के लिए नियंत्रण नाम और कमांड पैरामीटर गुणों का उपयोग कर रहा हूं।

मैं WPF के लिए नया हूँ, इसलिए मुझे पता है कि अगर मैं चीजों को सही तरीके से नहीं कर रहा हूँ करते हैं;)

XAML:

<dxc:SimpleButton Name="okButton" Content="OK" Command="{Binding OKCommand}" CommandParameter="{Binding ElementName=okButton}" IsDefault="True" Width="100"/> 

सी #:

private void OnOKCommand(object obj) 
    { 
     ((System.Windows.FrameworkElement)obj).Focus(); 

     // other code here 
    } 
संबंधित मुद्दे