Saya memiliki aplikasi pengujian yang sangat sederhana hanya untuk bermain-main dengan Windows Phone 7. Saya baru saja menambahkan a TextBox
dan a TextBlock
ke template UI standar. Satu-satunya kode kustom adalah sebagai berikut:
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";
}
}
The TextBox.TextChanged
event adalah kabel sampai TextBoxChanged
di XAML:
<TextBox Height="72" HorizontalAlignment="Left" Margin="6,37,0,0"
Name="textBox1" Text="" VerticalAlignment="Top"
Width="460" TextChanged="TextBoxChanged" />
Namun, setiap kali saya menekan tombol saat menjalankan emulator (baik keyboard di layar atau keyboard fisik, setelah menekan Jeda untuk mengaktifkan yang terakhir), penghitung akan bertambah dua kali, menampilkan dua baris di TextBlock
. Semua yang saya coba menunjukkan bahwa acara tersebut benar-benar terjadi dua kali, dan saya tidak tahu mengapa. Saya telah memverifikasi bahwa itu hanya berlangganan sekali - jika saya berhenti berlangganan di MainPage
konstruktor, tidak ada yang terjadi sama sekali (ke blok teks) ketika teks berubah.
Saya sudah mencoba kode yang setara di aplikasi Silverlight biasa, dan itu tidak terjadi di sana. Saat ini saya tidak memiliki ponsel fisik untuk mereproduksi ini. Saya belum menemukan catatan apa pun tentang ini sebagai masalah yang diketahui di Windows Phone 7.
Adakah yang bisa menjelaskan kesalahan saya, atau haruskah saya melaporkan ini sebagai bug?
EDIT: Untuk mengurangi kemungkinan ini menjadi memiliki dua kontrol teks, saya telah mencoba menghapus TextBlock
sepenuhnya, dan mengubah metode TextBoxChanged menjadi hanya kenaikan counter
. Saya kemudian menjalankan emulator, mengetik 10 huruf dan kemudian meletakkan breakpoint pada counter++;
baris (hanya untuk menghilangkan kemungkinan bahwa membobol debugger menyebabkan masalah) - dan itu ditampilkan counter
sebagai 20.
EDIT: Saya sekarang sudah bertanya di forum Windows Phone 7 ... kita akan lihat apa yang terjadi.
sumber
textBox1.Text
sebagai bagian dari penambahan textBlock1, itu akan menunjukkan "h" di kedua baris.TextChangedEventArgs
tidak banyak yang tersedia - hanyaOriginalSource
, yang selalu nol.Jawaban:
Alasan
TextChanged
peristiwa tersebut terjadi dua kali di WP7 adalah efek samping dari bagaimanaTextBox
template telah dibuat untuk tampilan Metro.Jika Anda mengedit
TextBox
template di Blend, Anda akan melihat bahwa template tersebut berisi template sekunderTextBox
untuk status nonaktif / read-only. Hal ini menyebabkan, sebagai efek samping, peristiwa tersebut diaktifkan dua kali.Anda dapat mengubah template untuk menghapus status tambahan
TextBox
(dan status terkait) jika Anda tidak memerlukan status ini, atau memodifikasi template untuk mendapatkan tampilan yang berbeda dalam status nonaktif / hanya baca, tanpa menggunakan status sekunderTextBox
.Dengan begitu, acara hanya akan aktif sekali.
sumber
saya akan mencari bug, terutama karena jika Anda meletakkan
KeyDown
danKeyUp
kejadian di sana, itu menunjukkan bahwa mereka hanya dipecat sekali (masing-masing) tetapiTextBoxChanged
acara dipecat dua kalisumber
TextInput
dilakukan?" Saya tidak akrab denganTextInput
...Itu terdengar seperti bug bagi saya. Sebagai solusinya, Anda selalu bisa menggunakan Rx's
DistinctUntilChanged
. Ada kelebihan beban yang memungkinkan Anda menentukan kunci yang berbeda.Metode ekstensi ini mengembalikan peristiwa TextChanged yang dapat diamati tetapi melewatkan duplikat yang berurutan:
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); }
Setelah bug diperbaiki, Anda cukup menghapus
DistinctUntilChanged
baris tersebut.sumber
Bagus! Saya menemukan pertanyaan ini dengan mencari masalah terkait dan juga menemukan hal yang mengganggu ini di kode saya. Acara ganda memakan lebih banyak sumber daya CPU dalam kasus saya. Jadi, saya memperbaiki kotak teks filter waktu nyata saya dengan solusi ini:
private string filterText = String.Empty; private void SearchBoxUpdated( object sender, TextChangedEventArgs e ) { if ( filterText != filterTextBox.Text ) { // one call per change filterText = filterTextBox.Text; ... } }
sumber
Saya yakin ini selalu menjadi bug di Compact Framework. Itu pasti telah terbawa ke WP7.
sumber
Tentu tampak seperti bug bagi saya, jika Anda mencoba memunculkan acara setiap kali teks berubah, Anda dapat mencoba menggunakan penjilidan dua arah, sayangnya ini tidak akan memunculkan peristiwa perubahan pers per tombol (hanya jika bidang kehilangan fokus). Berikut solusi jika Anda membutuhkannya:
this.textBox1.TextChanged -= this.TextBoxChanged; textBlock1.Text += "Text changed " + (counter++) + "\r\n"; this.textBox1.TextChanged += this.TextBoxChanged;
sumber
textBlock1.Text
perubahan - saya akan mencobanya. (Solusi yang akan saya coba adalah membuat eventhandler saya menjadi stateful, mengingat teks sebelumnya. Jika belum benar-benar berubah, abaikan :)Penafian- Saya tidak terbiasa dengan nuansa xaml dan saya tahu ini kedengarannya tidak masuk akal ... tapi bagaimanapun- pikiran pertama saya adalah mencoba menyampaikan hanya sebagai eventarg daripada textchangedeventargs. Tidak masuk akal, tapi mungkin bisa membantu? Sepertinya ketika saya telah melihat penembakan ganda seperti ini sebelumnya bahwa itu baik karena bug atau karena entah bagaimana menambahkan panggilan penangan kejadian terjadi di belakang layar ... Saya tidak yakin yang mana?
Jika Anda perlu cepat dan kotor, sekali lagi, saya tidak berpengalaman dengan xaml- langkah saya selanjutnya adalah melewatkan xaml untuk kotak teks itu sebagai solusi cepat ... lakukan kotak teks itu sepenuhnya di c # untuk saat ini sampai Anda dapat menunjukkan bug atau kode rumit ... yaitu, jika Anda membutuhkan solusi sementara.
sumber
Saya tidak berpikir itu adalah bug .. Ketika Anda menetapkan nilai ke properti teks di dalam acara textchanged, nilai kotak teks berubah yang akan memanggil lagi acara teks berubah ..
coba ini di Aplikasi Formulir Windows, Anda mungkin mendapatkan kesalahan
"Pengecualian tidak tertangani dari jenis 'System.StackOverflowException' terjadi di System.Windows.Forms.dll"
sumber
StefanWick benar, pertimbangkan untuk menggunakan template ini
<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>
sumber
Ini adalah topik lama, tetapi alih-alih mengganti template (yang tidak berfungsi untuk saya, saya tidak melihat kotak teks lain dengan Blend) Anda dapat menambahkan boolean untuk memeriksa apakah acara sudah berfungsi atau tidak.
boolean already = false; private void Tweet_SizeChanged(object sender, EventArgs e) { if (!already) { already = true; ... } else { already = false; } }
Saya sadar itu BUKAN cara yang sempurna, tapi menurut saya itu cara sederhana untuk melakukannya. Dan itu berhasil.
sumber