TextBox.TextChanged घटना विंडोज फोन 7 एमुलेटर पर दो बार फायरिंग


91

मेरे पास विंडोज फोन 7 के साथ खेलने के लिए एक बहुत ही सरल परीक्षण ऐप है। मैंने मानक यूआई टेम्पलेट में सिर्फ एक TextBoxऔर एक जोड़ा है TextBlock। केवल कस्टम कोड निम्नलिखित है:

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private int counter = 0;

    private void TextBoxChanged(object sender, TextChangedEventArgs e)
    {
        textBlock1.Text += "Text changed " + (counter++) + "\r\n";
    }
}

TextBox.TextChangedघटना अप करने के लिए वायर्ड है TextBoxChangedXAML में:

<TextBox Height="72" HorizontalAlignment="Left" Margin="6,37,0,0"
         Name="textBox1" Text="" VerticalAlignment="Top"
         Width="460" TextChanged="TextBoxChanged" />

हालाँकि, हर बार जब मैं एमुलेटर (ऑन-स्क्रीन कीबोर्ड या फिजिकल वन) में रनिंग करता हूं, तो बाद वाले को सक्षम करने के लिए पॉज़ दबाया जाता है। यह दो बार काउंटर को बढ़ाता है, जिसमें दो लाइनें प्रदर्शित होती हैं TextBlock। मैंने जो कुछ भी आजमाया है, उससे पता चलता है कि घटना वास्तव में दो बार फायरिंग है, और मुझे पता नहीं क्यों। मैंने सत्यापित किया है कि यह केवल एक बार सब्सक्राइब किया जा रहा है - अगर मैं MainPageकंस्ट्रक्टर में अनसब्सक्राइब करता हूं , तो टेक्स्ट में बदलाव होने पर (टेक्स्ट ब्लॉक में) कुछ भी नहीं होता है।

मैंने एक नियमित सिल्वरलाइट ऐप में बराबर कोड की कोशिश की है, और यह वहां नहीं हुआ। मेरे पास इस समय इसे पुन: पेश करने के लिए एक भौतिक फोन नहीं है। मुझे विंडोज फोन 7 में इस समस्या का कोई रिकॉर्ड नहीं मिला है।

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

संपादित करें: यह दो पाठ नियंत्रण होने की संभावना को कम करने के लिए, मैंने TextBlockपूरी तरह से हटाने की कोशिश की है , और केवल वृद्धि के लिए TextBoxChanged विधि को बदलना counter। मैं फिर एमुलेटर में चला गया, 10 अक्षर टाइप किए और फिरcounter++; लाइन पर एक ब्रेकपॉइंट लगाया (बस किसी भी संभावना से छुटकारा पाने के लिए कि डिबगर में टूटने से समस्या पैदा हो रही है) - और यह counter20 के रूप में दिखाता है ।

संपादित करें: मैंने अब विंडोज फोन 7 फोरम में पूछा है ... हम देखेंगे कि क्या होता है।


बस रुचि के बाहर - यदि आप घटना के अंदर की जाँच करते हैं, तो क्या टेक्स्टबॉक्स की सामग्री दोनों ही बार घटना होती है? मैं वास्तव में नहीं जानता कि ऐसा क्यों होगा, क्योंकि मैं आमतौर पर इन चीजों के लिए ईवेंट हैंडलिंग के बजाय MVVM और डेटा बाइंडिंग का उपयोग करता हूं (सिल्वरलाइट और WPF, WP7 के साथ बहुत अनुभव नहीं)।
रूण जैकबसेन

@ जून: हां, मैं दो बार "बाद" पाठ देखता हूं। इसलिए अगर मैं "h" textBox1.Textदबाता हूं और टेक्स्टब्लॉक 1 के हिस्से के रूप में प्रदर्शित करता हूं, तो यह दोनों लाइनों में "एच" दिखाएगा।
जॉन स्कीट

1
आप 2 कीबोर्ड का उल्लेख करते हैं, क्या यह एक कारक हो सकता है? क्या आप एक को निष्क्रिय कर सकते हैं? और शायद आप जांच सकते हैं कि क्या TextChangedEventArgs के सभी सदस्य दोनों कॉल में समान हैं?
हेंक होल्टरमैन

@ हेनक: ज्यादातर समय मैंने फिजिकल कीबोर्ड को इनेबल करने की जहमत नहीं उठाई ... केवल यह देखने के लिए कि क्या इसका असर होगा। TextChangedEventArgsवास्तव में बहुत कुछ उपलब्ध नहीं है - बस OriginalSource, जो हमेशा शून्य है।
जॉन स्कीट

3
यह बग की तरह दिखता है, यह कीबोर्ड से संबंधित नहीं है क्योंकि आप टेक्स्ट प्रॉपर्टी को एक नया मान देकर समान परिणाम प्राप्त कर सकते हैं, टेक्स्टचैनड अभी भी दो बार फायर करता है।
एंथनीवजोन

जवाबों:


75

TextChangedWP7 में दो बार घटना आग लगने का कारण है TextBoxकि मेट्रो लुक के लिए कैसे टेम्प्लेट किया गया है।

यदि आप TextBoxब्लेंड में टेम्प्लेट को संपादित करते हैं, तो आप देखेंगे कि इसमें TextBoxविकलांग / रीड-ओनली स्टेट के लिए एक सेकेंडरी है । यह एक दुष्प्रभाव के रूप में, दो बार आग लगने की घटना का कारण बनता है।

TextBoxयदि आपको इन राज्यों की आवश्यकता नहीं है, तो आप अतिरिक्त (और संबद्ध राज्यों) को हटाने के लिए टेम्पलेट बदल सकते हैं , या माध्यमिक का उपयोग किए बिना, अक्षम / पढ़ने-योग्य राज्य में एक अलग रूप प्राप्त करने के लिए टेम्पलेट को संशोधित कर सकते हैं TextBox

इसके साथ, घटना केवल एक बार आग लग जाएगी।


18

मैं बग के लिए जाऊंगा, मुख्य रूप से क्योंकि अगर आप घटनाओं KeyDownऔर KeyUpघटनाओं को वहां रखते हैं, तो यह दर्शाता है कि उन्हें केवल एक बार निकाल दिया गया है (उनमें से प्रत्येक) लेकिन TextBoxChangedघटना दो बार निकाल दी जाती है


@undertakeror: उस बिट की जाँच करने के लिए धन्यवाद। मैं WP7- विशिष्ट मंच पर एक ही सवाल पूछूंगा और देखें कि क्या प्रतिक्रिया है ...
जॉन स्कीट

TextInput क्या करता है? WP7 की इकाई परीक्षणों के माध्यम से फिसलने के लिए ये काफी बड़ा बग जैसा लगता है, लेकिन फिर यह SL है
क्रिस S

@ क्रिस एस: आपका क्या मतलब है "क्या करता TextInputहै?" मैं परिचित नहीं हूँ TextInput...
जॉन स्कीट

@Jon `OnTextInput (TextCompositionEventArgs e)` KeyDown के बजाय टेक्स्ट इनपुट को संभालने का SL तरीका है, क्योंकि जाहिर है कि डिवाइस में कीबोर्ड नहीं हो सकता है: "तब होता है जब UI तत्व को डिवाइस-स्वतंत्र तरीके से टेक्स्ट मिलता है" msdn.microsoft। com / en-us / पुस्तकालय /…
क्रिस एस

मैं बस उत्सुक था कि अगर दो बार गोलीबारी की
क्रिस एस

8

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

यह विस्तार विधि अवलोकनीय TextChanged घटना देता है, लेकिन लगातार डुप्लिकेट को छोड़ देता है:

public static IObservable<IEvent<TextChangedEventArgs>> GetTextChanged(
    this TextBox tb)
{
    return Observable.FromEvent<TextChangedEventArgs>(
               h => textBox1.TextChanged += h, 
               h => textBox1.TextChanged -= h
           )
           .DistinctUntilChanged(t => t.Text);
}

एक बार बग ठीक हो जाने के बाद आप बस DistinctUntilChangedलाइन को हटा सकते हैं ।


2

अच्छा! मैंने इस प्रश्न को संबंधित समस्या के लिए खोजा और मेरे कोड में इस कष्टप्रद बात को भी पाया। दोहरी घटना मेरे मामले में अधिक सीपीयू संसाधनों को खाती है। इसलिए, मैंने इस समाधान के साथ अपना वास्तविक समय फ़िल्टर टेक्स्टबॉक्स तय किया:

private string filterText = String.Empty;

private void SearchBoxUpdated( object sender, TextChangedEventArgs e )
{
    if ( filterText != filterTextBox.Text )
    {
        // one call per change
        filterText = filterTextBox.Text;
        ...
    }

}

1

मेरा मानना ​​है कि यह हमेशा कॉम्पैक्ट फ्रेमवर्क में एक बग रहा है। इसे WP7 में ले जाना चाहिए था।


मैंने सोचा कि यह सीएफ के एक और हालिया संस्करण में तय किया गया था ... और सिल्वरलाइट की ओर बढ़ने के बावजूद इसे प्राप्त करना अजीब होगा। दूसरी ओर, यह वैसे भी देखने के लिए एक बहुत ही अजीब बग है ...
जॉन स्केट

मैं मानता हूं कि यह अजीब है। मैं एक CF 2.0 आवेदन में कल में फिर से।
जेरोड हेटेलिंग 15

0

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

        this.textBox1.TextChanged -= this.TextBoxChanged;
        textBlock1.Text += "Text changed " + (counter++) + "\r\n";
        this.textBox1.TextChanged += this.TextBoxChanged;

मुझे यकीन नहीं है कि यह चारों ओर काम करेगा - समस्या यह नहीं है कि इवेंट हैंडलर फायरिंग को textBlock1.Textबदलने के कारण - मैं इसे एक कोशिश करूँगा। ( मैं जो प्रयास करने जा रहा था, वह मेरे इवेंटहैंडलर को स्टेटफुल बनाने के लिए था, पिछले पाठ को याद करते हुए। अगर यह वास्तव में नहीं बदला है, तो इसे नजरअंदाज कर दें :)
जॉन स्कीट

0

डिस्क्लेमर- मैं xaml की बारीकियों से परिचित नहीं हूं और मुझे पता है कि यह अतार्किक लगता है ... लेकिन वैसे भी- मेरा पहला विचार है कि टेक्स्टचेंजेडवेंट्स के बजाय सिर्फ प्लेन इवेंटगर्ल्स के रूप में पास होने की कोशिश करें। समझ में नहीं आता है, लेकिन यह मदद कर सकता है? ऐसा लगता है जब मैंने इस तरह से डबल फायरिंग देखी है इससे पहले कि यह या तो बग के कारण है या किसी तरह 2 ऐड इवेंट हैंडलर कॉल को पर्दे के पीछे हो रहा है ... मुझे यकीन नहीं है कि हालांकि?

यदि आपको त्वरित और गंदे की आवश्यकता है, तो फिर से, मुझे xaml के साथ अनुभव नहीं किया जा रहा है- मेरा अगला कदम सिर्फ उस टेक्स्टबॉक्स के लिए त्वरित वर्कअराउंड के रूप में xaml को छोड़ना होगा ... उस टेक्स्टबॉक्स को पूरी तरह से c # के लिए करें जब तक कि आप बग को इंगित नहीं कर सकते या मुश्किल कोड ... यही है, अगर आपको एक अस्थायी समाधान की आवश्यकता है।


मैं किसी भी घटना को पारित करने वाला नहीं हूं - मैं एक इवेंट हैंडलर को लागू कर रहा हूं। लेकिन मैंने सत्यापित किया है कि C # में इवेंट हैंडलर को शुद्ध रूप से जोड़ने से कोई फर्क नहीं पड़ता ... यह अभी भी दो बार निकाल दिया जाता है।
जॉन स्कीट

ठीक है, हम्म। हाँ, अगर यह शुद्ध है # तो यह एक बग की तरह लगता है। पहले सुझाव के बारे में- मुझे खेद है कि मेरी क्रिया भयानक थी, मुझे यह कैसे बताना चाहिए था- मैं कोशिश करूँगा [आपके कार्यान्वयन में / TextBoxChanged हैंडलर विधि] आर्ग्स पैरामीटर प्रकार को सिर्फ सादे घटना-क्रम में बदल दें। शायद काम नहीं करेगा ... लेकिन हे ... यह सिर्फ मेरा पहला विचार था।
दलाल रस McJones 15

दूसरे शब्दों में, यह शायद काम नहीं करेगा लेकिन मैं विधि हस्ताक्षर करने की कोशिश करूँगा = निजी शून्य टेक्स्टबॉक्सचेंज (ऑब्जेक्ट प्रेषक, EventArgs ई) सिर्फ यह कहने के लिए कि मैंने इसे आज़माया =)
दलाल रस मैकजोन

सही। मुझे नहीं लगता कि इससे कोई प्रभावी होगा, मुझे डर है।
जॉन स्कीट

0

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

Windows प्रपत्र अनुप्रयोग में यह प्रयास करें, आपको एक त्रुटि मिल सकती है

"System.Wtindows.Forms.dll" में 'System.StackOverflowException' प्रकार का एक बिना अपवाद वाला अपवाद है


इस सवाल से: "मैंने अभी एक टेक्स्टबॉक्स और एक टेक्स्टब्लॉक को मानक UI टेम्पलेट में जोड़ा है" - वे एक ही बात नहीं हैं। मुझे एक टेक्स्टबॉक्स मिला है जिसे उपयोगकर्ता टाइप कर सकता है, और एक टेक्स्टब्लॉक जो गिनती प्रदर्शित करता है।
जॉन स्कीट

0

StefanWick सही है, इस टेम्पलेट का उपयोग करने पर विचार करें

<Application.Resources>
        <ControlTemplate x:Key="PhoneDisabledTextBoxTemplate" TargetType="TextBox">
            <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
        </ControlTemplate>
        <Style x:Key="TextBoxStyle1" TargetType="TextBox">
            <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
            <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
            <Setter Property="Background" Value="{StaticResource PhoneTextBoxBrush}"/>
            <Setter Property="Foreground" Value="{StaticResource PhoneTextBoxForegroundBrush}"/>
            <Setter Property="BorderBrush" Value="{StaticResource PhoneTextBoxBrush}"/>
            <Setter Property="SelectionBackground" Value="{StaticResource PhoneAccentBrush}"/>
            <Setter Property="SelectionForeground" Value="{StaticResource PhoneTextBoxSelectionForegroundBrush}"/>
            <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
            <Setter Property="Padding" Value="2"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TextBox">
                        <Grid Background="Transparent">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates" ec:ExtendedVisualStateManager.UseFluidLayout="True">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver"/>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Collapsed</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="ReadOnly">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Collapsed</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBorder">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="EnabledBorder">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBorderBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <VisualStateManager.CustomVisualStateManager>
                                <ec:ExtendedVisualStateManager/>
                            </VisualStateManager.CustomVisualStateManager>
                            <Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
                                <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>

0

यह एक पुराना विषय है, लेकिन बदले हुए टेम्पलेट के लिए (जो मेरे लिए काम नहीं करता है, मैं अन्य टेक्स्टबॉक्स को ब्लेंड के साथ नहीं देखता हूं) आप यह जांचने के लिए बूलियन जोड़ सकते हैं कि क्या घटना पहले से ही फ़ंक्शन की थी या नहीं।

boolean already = false;
private void Tweet_SizeChanged(object sender, EventArgs e)
{
    if (!already)
    {
        already = true;
        ...
    }
    else
    {
    already = false;
    }
}

मुझे पता है कि यह सही तरीका नहीं है, लेकिन मुझे लगता है कि यह ऐसा करने का सरल तरीका है। और यह काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.