silverlight events textbox windows-phone-7

silverlight - Evento TextBox.TextChanged que se activa dos veces en el emulador de Windows Phone 7



events windows-phone-7 (10)

¡Bonito! Encontré esta pregunta buscando un problema relacionado y también encontré esta cosa molesta en mi código. El doble evento consume más recursos de la CPU en mi caso. Entonces, arreglé mi cuadro de texto de filtro en tiempo real con esta solución:

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

Tengo una aplicación de prueba muy simple para jugar con Windows Phone 7. Acabo de agregar un TextBox y un TextBlock a la plantilla de UI estándar. El único código personalizado es el siguiente:

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"; } }

El evento TextBox.TextChanged está conectado a TextBoxChanged en XAML:

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

Sin embargo, cada vez que presiono una tecla al ejecutar en el emulador (ya sea el teclado en pantalla o el físico, después de haber presionado Pausa para habilitar este último) incrementa el contador dos veces, mostrando dos líneas en el TextBlock . Todo lo que he probado muestra que el evento se está disparando realmente dos veces, y no tengo idea de por qué. He verificado que solo se suscribió una vez: si MainPage la suscripción en el constructor de MainPage , no sucede nada (al bloque de texto) cuando el texto cambia.

Probé el código equivalente en una aplicación regular de Silverlight, y no ocurrió allí. No tengo un teléfono físico para reproducir esto en este momento. No he encontrado ningún registro de que este sea un problema conocido en Windows Phone 7.

¿Alguien puede explicar lo que estoy haciendo mal, o debería informar esto como un error?

EDITAR: Para reducir la posibilidad de que esto se deba a tener dos controles de texto, intenté eliminar TextBlock completo y cambiar el método TextBoxChanged para incrementar el counter . Luego corrí en el emulador, escribí 10 letras y luego puse un punto de interrupción en el counter++; línea (solo para deshacerse de cualquier posibilidad de que irrumpir en el depurador esté causando problemas) - y muestra el counter como 20.

EDITAR: ahora he preguntado en el foro de Windows Phone 7 ... veremos qué sucede.


Claro que me parece un error, si intentas plantear un evento cada vez que cambia el texto, podrías intentar utilizar un enlace bidireccional, pero desafortunadamente esto no generará eventos de cambio de prensa por tecla (solo cuando el campo esté en blanco). pierde el foco). Aquí hay una solución si la necesita:

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


Creo que esto siempre ha sido un error en el Marco Compacto. Debe haber sido transferido a WP7.


Descargo de responsabilidad: no estoy familiarizado con los matices xaml y sé que esto suena ilógico ... pero de todos modos, mi primer pensamiento es tratar de pasar como simplemente eventargs en lugar de textchangedeventargs. No tiene sentido, pero ¿podría ser de ayuda? Parece que cuando he visto disparos dobles como este antes, es debido a un error o debido a que de alguna manera hay 2 llamadas de administrador de eventos que suceden detrás de escena ... ¿No estoy seguro de qué?

Si necesitas algo rápido y sucio, una vez más, yo no tengo experiencia con xaml- mi siguiente paso sería simplemente omitir xaml para ese cuadro de texto como una solución rápida ... hacer ese cuadro de texto totalmente en c # por ahora hasta que puedas identificar el error o código engañoso ... es decir, si necesita una solución temporal.


Es un tema viejo, pero en lugar de cambiar la plantilla (eso no funciona para mí, no veo el otro cuadro de texto con Mezcla) puede agregar booleano para verificar si el evento ya hizo la función o no.

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

Soy consciente de que NO es la manera perfecta, pero creo que es la manera más simple de hacerlo. Y funciona.


Eso me suena a un error. Como solución alternativa, siempre puede usar DistinctUntilChanged de Rx. Hay una sobrecarga que le permite especificar la clave distinta.

Este método de extensión devuelve el evento observable TextChanged pero omite duplicados consecutivos:

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); }

Una vez que se solucione el error, simplemente puede eliminar la línea DistinctUntilChanged .


La razón por la cual el evento TextChanged se dispara dos veces en WP7 es un efecto secundario de cómo se ha TextBox para el aspecto de Metro.

Si edita la plantilla TextBox en Blend, verá que contiene un TextBox secundario para el estado deshabilitado / solo lectura. Esto causa, como efecto secundario, el evento de disparar dos veces.

Puede cambiar la plantilla para eliminar el TextBox adicional (y los estados asociados) si no necesita estos estados, o modificar la plantilla para lograr un aspecto diferente en el estado deshabilitado / solo lectura, sin usar un TextBox secundario.

Con eso, el evento se disparará solo una vez.


No creo que sea un error. Cuando asigna el valor a una propiedad de texto dentro del evento text-changed, se cambia el valor de la caja de texto que volverá a llamar al evento text changed.

intente esto en la aplicación Windows Forms, es posible que obtenga un error

"Se produjo una excepción no controlada del tipo ''System.Exception'' en System.Windows.Forms.dll"


StefanWick tiene razón, considere usar esta plantilla

<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>


iría por el error, principalmente porque si KeyUp eventos KeyDown y KeyUp allí, muestra que solo se disparan una vez (cada uno de ellos), pero el evento TextBoxChanged se dispara dos veces