Answered by:
event fires twice on custom control

Question
-
I have created my custom usercontrol based on TextBox with TextBox template inside
<TextBox x:Class="MyProj.MyTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" > <TextBox.Template> <ControlTemplate TargetType="TextBox"> <Grid> <TextBox Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" AcceptsReturn="True" TextWrapping="Wrap" /> </Grid> </ControlTemplate> </TextBox.Template></TextBox>
But now when event TextChanged fires twice when I use this control.
I'v seen couple topics like this TextBox.TextChanged event fire twice on the Phone
But in my case I need textbox inside my control. Have some thoughts about cancel bubbling, but not sure, that it is possible there. Is there any way to let event be fired only once?
Tuesday, September 3, 2013 2:58 PM
Answers
-
Hi
Yes, Changing to "OneWay" is not a good option, it will not binding the data properly.
I download your code and modify the code a bit, and it works now, I upload to skydrive: http://sdrv.ms/1egIwGR. It seems that the TextChanged event will only fire once.
Basically I modifed your WaterMarkedTextBox.xaml and change the binding target from "Text" to "WaterMark":
<TextBox Text="{Binding WaterMark, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" AcceptsReturn="True" TextWrapping="Wrap" />
Furthermore I add some test binding on MainPage.xaml to see if the binding can works.
So if any questions, feel free to ask me.
--James
<THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
Thanks
MSDN Community Support
Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.- Marked as answer by Programmer SommerMVP Thursday, September 5, 2013 5:43 PM
Thursday, September 5, 2013 3:13 AMModerator
All replies
-
Can you post the control code?
The reason is I had this happened to me once and it took me pulling half my hair out to figure out why it fired twice.
- Edited by RandyPete Tuesday, September 3, 2013 4:25 PM
Tuesday, September 3, 2013 4:23 PM -
Hi,
I found a similar topic at WPF forum, but I think it should be the same: http://social.msdn.microsoft.com/Forums/en-US/7de87678-8257-4948-8537-d474e6a5a204/custom-textbox-textchanged-event-fired-twice
the solution provided by the user is "inherited my WatermarkedTextBox and AutoCompleteTextBox direct from TextBox". You can try it and if the problem still exist, share your code with us via skydrive and we can trying to analysis the code.
Best Regards,
--James
<THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
Thanks
MSDN Community Support
Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.Wednesday, September 4, 2013 2:09 AMModerator -
Thank you!
I'v seeing this topic also. But my custom control is already inherited from TextBox.
Here is link to folder on skydrive http://sdrv.ms/18DcG12
I have a little bit simplify project - so here is just an example.
Nothing really special. Just XAML as I have posted and code like:
namespace demo2events { public sealed partial class WaterMarkedTextBox : TextBox { public string WaterMark { get { return (string)GetValue(WaterMarkProperty); } set { SetValue(WaterMarkProperty, value); } } public static readonly DependencyProperty WaterMarkProperty = DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkedTextBox), new PropertyMetadata("")); public WaterMarkedTextBox() { this.InitializeComponent(); } } }
Wednesday, September 4, 2013 3:19 PM -
I have found that if yo change binding in textbox inside template to OneWay then event fires only once, but in this case binding to data in ICollectionView in MainPage doesn't works..
<ControlTemplate TargetType="TextBox"> <Grid> <TextBox Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent},Mode=OneWay}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" AcceptsReturn="True" TextWrapping="Wrap" /> </Grid> </ControlTemplate>
Wednesday, September 4, 2013 4:49 PM -
Hi
Yes, Changing to "OneWay" is not a good option, it will not binding the data properly.
I download your code and modify the code a bit, and it works now, I upload to skydrive: http://sdrv.ms/1egIwGR. It seems that the TextChanged event will only fire once.
Basically I modifed your WaterMarkedTextBox.xaml and change the binding target from "Text" to "WaterMark":
<TextBox Text="{Binding WaterMark, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" AcceptsReturn="True" TextWrapping="Wrap" />
Furthermore I add some test binding on MainPage.xaml to see if the binding can works.
So if any questions, feel free to ask me.
--James
<THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
Thanks
MSDN Community Support
Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.- Marked as answer by Programmer SommerMVP Thursday, September 5, 2013 5:43 PM
Thursday, September 5, 2013 3:13 AMModerator -
That's a very good idea! Thank you.
I have add one more property WaterText and this property has currently Text of custom control
Here is example ( I have took a code of custom control from somewhere in web, but there are some changes! )
<TextBox x:Class="DemoWaterMark.WaterMarkedTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:RedactoR" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Name="uc" d:DesignHeight="100" d:DesignWidth="400"> <TextBox.Template> <ControlTemplate TargetType="TextBox"> <Grid> <TextBox Text="{Binding WaterText, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" AcceptsReturn="True" TextWrapping="Wrap" /> <TextBlock TextWrapping="Wrap" Text="{Binding WaterMark, RelativeSource={RelativeSource TemplatedParent}}" FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}" Foreground="Gray" Margin="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Visibility="Collapsed" IsHitTestVisible="False"/> </Grid> </ControlTemplate> </TextBox.Template> </TextBox>
using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace DemoWaterMark { public sealed partial class WaterMarkedTextBox : TextBox { private bool _isFocused; public string WaterMark { get { return (string)GetValue(WaterMarkProperty); } set { SetValue(WaterMarkProperty, value); } } public static readonly DependencyProperty WaterMarkProperty = DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkedTextBox), new PropertyMetadata("")); public string WaterText { get { return (string)GetValue(WaterTextProperty); } set { SetValue(WaterTextProperty, value); } } public static readonly DependencyProperty WaterTextProperty = DependencyProperty.Register("WaterText", typeof(string), typeof(WaterMarkedTextBox), new PropertyMetadata("")); public WaterMarkedTextBox() { this.InitializeComponent(); Loaded += WaterMarkedTextBox_Loaded; } void WaterMarkedTextBox_Loaded(object sender, RoutedEventArgs e) { if (this.Visibility == Visibility.Collapsed) return; // if someone deside to change visibility var grid = (Grid)VisualTreeHelper.GetChild(this, 0); TextBox innerTextBox = (TextBox)grid.Children[0]; innerTextBox.GotFocus += WaterMarkedTextBox_GotFocus; innerTextBox.LostFocus += WaterMarkedTextBox_LostFocus; innerTextBox.TextChanged+=innerTextBox_TextChanged; ChangeWatermarkTextVisibility(); } private void innerTextBox_TextChanged(object sender, TextChangedEventArgs e) { ChangeWatermarkTextVisibility(); } void WaterMarkedTextBox_LostFocus(object sender, RoutedEventArgs e) { _isFocused = false; ChangeWatermarkTextVisibility(); } void WaterMarkedTextBox_GotFocus(object sender, RoutedEventArgs e) { _isFocused = true; ChangeWatermarkTextVisibility(); } private void ChangeWatermarkTextVisibility() { var grid = (Grid)VisualTreeHelper.GetChild(this, 0); TextBlock watermarkText = (TextBlock)grid.Children[1]; if (!string.IsNullOrEmpty(WaterText) || _isFocused) { watermarkText.Visibility = Visibility.Collapsed; } else { watermarkText.Visibility = Visibility.Visible; } } } }
Thursday, September 5, 2013 5:48 PM