Windows Phone 7 에뮬레이터에서 TextBox.TextChanged 이벤트가 두 번 발생합니다.
Windows Phone 7을 사용하기위한 매우 간단한 테스트 앱이 있습니다 . 표준 UI 템플릿 에 a TextBox
및 a 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
이벤트까지 연결되어 TextBoxChanged
XAML에서 :
<TextBox Height="72" HorizontalAlignment="Left" Margin="6,37,0,0"
Name="textBox1" Text="" VerticalAlignment="Top"
Width="460" TextChanged="TextBoxChanged" />
그러나 에뮬레이터에서 실행할 때 키를 누를 때마다 (화면 키보드 또는 물리적 키보드, Pause를 눌러 후자를 활성화) 카운터가 두 번 증가하여 TextBlock
. 내가 시도한 모든 것은 이벤트가 실제로 두 번 실행되고 있음을 보여 주며 이유를 모르겠습니다. 한 번만 구독된다는 것을 확인했습니다. MainPage
생성자 에서 구독을 취소 하면 텍스트가 변경 될 때 아무 일도 일어나지 않습니다 (텍스트 블록에).
일반 Silverlight 앱에서 동등한 코드를 시도했지만 거기에서 발생하지 않았습니다. 나는 현재 이것을 재현 할 실제 전화기가 없습니다. Windows Phone 7에서 이것이 알려진 문제라는 기록을 찾지 못했습니다.
누구든지 내가 뭘 잘못하고 있는지 설명 할 수 있습니까? 아니면 버그로보고해야합니까?
편집 : 이것이 두 개의 텍스트 컨트롤을 가질 가능성을 줄이기 위해 TextBlock
완전히 제거 하고 TextBoxChanged 메서드를 단순히 증가 하도록 변경했습니다 counter
. 그런 다음 에뮬레이터에서 실행하고 10 개의 문자를 입력 한 다음counter++;
줄에 중단 점 을 추가했습니다 (디버거에 침입하여 문제를 일으킬 가능성을 제거하기 위해) counter
-20으로 표시 됩니다.
편집 : 이제 Windows Phone 7 포럼에서 질문했습니다 . 어떤 일이 발생하는지 살펴 보겠습니다.
TextChanged
WP7에서 이벤트가 두 번 발생 하는 이유는 TextBox
Metro 모양에 대해 템플릿이 지정 되는 방식의 부작용 때문입니다 .
TextBox
Blend 에서 템플릿 을 편집하면 TextBox
비활성화 / 읽기 전용 상태에 대한 보조가 포함 된 것을 볼 수 있습니다 . 이로 인해 부작용으로 이벤트가 두 번 발생합니다.
TextBox
이러한 상태가 필요하지 않은 경우 추가 (및 관련 상태) 를 제거하도록 템플릿을 변경 하거나, 보조를 사용하지 않고 비활성화 / 읽기 전용 상태에서 다른 모양을 얻도록 템플릿을 수정할 수 TextBox
있습니다.
이를 통해 이벤트는 한 번만 실행됩니다.
나는 버그에 대해 갈 것입니다. 주로 거기에 KeyDown
및 KeyUp
이벤트 를 넣으면 한 번만 발생한다는 것을 보여 주지만 TextBoxChanged
이벤트는 두 번 발생합니다.
그것은 나에게 버그처럼 들립니다. 해결 방법으로 항상 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
줄을 제거 할 수 있습니다 .
좋은! 나는 관련 문제를 검색 하여이 질문을 발견했으며 내 코드 에서이 성가신 것을 발견했습니다. 이중 이벤트는 내 경우 더 많은 CPU 리소스를 먹습니다. 그래서이 솔루션으로 실시간 필터 텍스트 상자를 수정했습니다.
private string filterText = String.Empty;
private void SearchBoxUpdated( object sender, TextChangedEventArgs e )
{
if ( filterText != filterTextBox.Text )
{
// one call per change
filterText = filterTextBox.Text;
...
}
}
I believe this has always been a bug in the Compact Framework. It must have been carried over into WP7.
Sure looks like a bug to me, if you're trying to raise an event every time the text changes you could try using a two-way binding instead, unfortunately this won't raise per-key press change events (only when the field loses focus). Here's a workaround if you need one:
this.textBox1.TextChanged -= this.TextBoxChanged;
textBlock1.Text += "Text changed " + (counter++) + "\r\n";
this.textBox1.TextChanged += this.TextBoxChanged;
Disclaimer- I'm not familiar with xaml nuances and I know this sounds illogical... but anyway- my first thought is to try passing as just plain eventargs rather than textchangedeventargs. Doesn't make sense, but may be it could help? It seems like when I've seen double firings like this before that it is either due to a bug or due to somehow 2 add event handler calls happening behind the scenes... I'm not sure which though?
If you need quick and dirty, again, me not being experienced with xaml- my next step would be to just skip xaml for that textbox as a quick workaround... do that textbox totally in c# for now until you can pinpoint the bug or tricky code... that is, if you need a temporary solution.
I dont think it is a bug .. When you assign the value to a text property inside the textchanged event , the textbox value is changed which will again call the text changed event ..
try this in Windows Forms Application , you might get an error
"An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll"
StefanWick is right, consider using this template
<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>
It's an old topic, but instead of change template (that does not work for me, I dont't see the other textbox with Blend) you can add boolean to check if the event already did the function or not.
boolean already = false;
private void Tweet_SizeChanged(object sender, EventArgs e)
{
if (!already)
{
already = true;
...
}
else
{
already = false;
}
}
I'm aware that is NOT the perfect way, but I think it's the simple way to do that. And it works.
'program tip' 카테고리의 다른 글
중괄호로 묶인 이니셜 라이저는 언제 사용합니까? (0) | 2020.09.06 |
---|---|
클로저는 언제 Fn, FnMut 및 FnOnce를 구현합니까? (0) | 2020.09.06 |
Python UTC datetime 객체의 ISO 형식에는 Z (Zulu 또는 Zero 오프셋)가 포함되지 않습니다. (0) | 2020.09.06 |
iOS8의 Safari는 고정 요소가 포커스를받을 때 화면을 스크롤합니다. (0) | 2020.09.06 |
버퍼를 나란히 분할하도록 Emacs 설정 (0) | 2020.09.06 |