我有一个非常简单的测试应用程序,只是为了使用Windows Phone 7.我刚刚在标准UI模板中添加了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";
}
}
{1}}事件在XAML中连接到TextBox.TextChanged
:
TextBoxChanged
但是,每当我在模拟器(屏幕键盘或物理键盘,按下Pause以启用后者)中按下某个键时,它会使计数器递增两次,在{{1中显示两行}}。我尝试的所有东西都表明这个事件真的发射了两次,我不知道为什么。我已经验证它只被订阅了一次 - 如果我在<TextBox Height="72" HorizontalAlignment="Left" Margin="6,37,0,0"
Name="textBox1" Text="" VerticalAlignment="Top"
Width="460" TextChanged="TextBoxChanged" />
构造函数中取消订阅,当文本发生变化时,根本没有任何事情发生(对于文本块)。
我在常规的Silverlight应用程序中尝试过等效的代码,并没有在那里发生。目前我没有手机可以重现这一点。我还没有找到任何关于Windows Phone 7中已知问题的记录。
任何人都可以解释我做错了什么,或者我应该将其报告为错误?
编辑:为了减少使用两个文本控件的可能性,我尝试完全删除TextBlock
,并将TextBoxChanged方法更改为只是增量{{1 }}。然后我在模拟器中运行,输入10个字母然后然后在MainPage
行放置一个断点(只是为了摆脱闯入调试器导致问题的任何可能性) - 它显示TextBlock
为20。
编辑:我现在asked in the Windows Phone 7 forum ......我们会看到会发生什么。
答案 0 :(得分:75)
{1}}事件在WP7中触发两次的原因是TextChanged
如何模仿Metro外观的副作用。
如果您在Blend中编辑TextBox
模板,您会看到它包含已禁用/只读状态的辅助TextBox
。作为副作用,这会导致事件发生两次。
如果您不需要这些状态,可以更改模板以删除额外的TextBox
(及相关状态),或修改模板以在禁用/只读状态下实现不同的外观,使用辅助TextBox
。
这样,事件只会发射一次。
答案 1 :(得分:18)
我会去找错误,主要是因为如果你把KeyDown
和KeyUp
事件放在那里,它会显示它们只被触发一次(每个都被触发)但{{{ 1}}事件被触发两次
答案 2 :(得分: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
行。
答案 3 :(得分:2)
尼斯!我通过搜索相关问题找到了这个问题,并在我的代码中发现了这个烦人的事情。在我的情况下,Double事件会占用更多的CPU资源。所以,我用这个解决方案修复了我的实时过滤器文本框:
private string filterText = String.Empty;
private void SearchBoxUpdated( object sender, TextChangedEventArgs e )
{
if ( filterText != filterTextBox.Text )
{
// one call per change
filterText = filterTextBox.Text;
...
}
}
答案 4 :(得分:1)
我认为这一直是Compact Framework中的一个错误。它必须被转移到WP7中。
答案 5 :(得分:0)
对我来说肯定看起来像个错误,如果你试图在每次文本更改时尝试引发一个事件,你可以尝试使用双向绑定,不幸的是,这不会引起按键更改事件(仅限当场失去焦点时)。如果您需要,可以使用以下解决方法:
this.textBox1.TextChanged -= this.TextBoxChanged;
textBlock1.Text += "Text changed " + (counter++) + "\r\n";
this.textBox1.TextChanged += this.TextBoxChanged;
答案 6 :(得分:0)
免责声明 - 我不熟悉xaml的细微差别,我知道这听起来不合逻辑......但无论如何 - 我的第一个想法是尝试传递只是简单的eventargs而不是textchangedeventargs。没有意义,但可能有帮助吗?看起来我之前看过这样的双击,或者是由于一个错误或由于某种方式在幕后发生了2次添加事件处理程序调用......我不确定哪个呢?
如果你需要快速和肮脏,再次,我没有经验xaml-我的下一步将只是跳过xaml为该文本框作为一个快速解决方法...现在完全在c#中执行该文本框直到你可以查明错误或棘手的代码......也就是说,如果你需要临时解决方案。
答案 7 :(得分:0)
我不认为这是一个错误.. 将值分配给textchanged事件内的text属性时,会更改文本框值,这将再次调用text changed事件。
在Windows窗体应用程序中尝试此操作,您可能会收到错误
“System.Windows.Forms.dll中发生了'System.StackOverflowException'类型的未处理异常”
答案 8 :(得分: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>
答案 9 :(得分:0)
这是一个古老的主题,但不是更改模板(这对我不起作用,我看不到另一个带Blend的文本框)你可以添加布尔值来检查事件是否已经完成了该功能。
boolean already = false;
private void Tweet_SizeChanged(object sender, EventArgs e)
{
if (!already)
{
already = true;
...
}
else
{
already = false;
}
}
我知道这不是完美的方式,但我认为这是一种简单的方法。它有效。