Is there any way to detect a change in the Text property of a TextBlock element using events?
(I'm trying to provide an animation for highlighting the TextBlocks whose Text property change within a DataGrid)
Is there any way to detect a change in the Text property of a TextBlock element using events?
(I'm trying to provide an animation for highlighting the TextBlocks whose Text property change within a DataGrid)
It's easier than that! Late answer, but much simpler.
// assume textBlock is your TextBlock var dp = DependencyPropertyDescriptor.FromProperty( TextBlock.TextProperty, typeof(TextBlock)); dp.AddValueChanged(textBlock, (sender, args) => { MessageBox.Show("text changed"); }); This is like the code from the link in bioskope's answer, but simplified. You need the TargetUpdated event and add NotifyOnTargetUpdated=True to the binding.
<TextBlock Text="{Binding YourTextProperty, NotifyOnTargetUpdated=True}" TargetUpdated="YourTextEventHandler"/> As far as I can understand there isn't any textchanged event in TextBlock. Looking at your requirement, I feel that re-templating a textbox will also not be a viable solution. From my preliminary searching around, this seems to be a possible solution.
<TextBlock x:Name="tbMessage" Text="{Binding Path=StatusBarText, NotifyOnTargetUpdated=True}"> <TextBlock.Triggers> <EventTrigger RoutedEvent="Binding.TargetUpdated"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0″ To="1.0″ /> <DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:2″ From="1.0″ To="0.0″ BeginTime="0:0:5″ /> </Storyboard> </BeginStoryboard> </EventTrigger> </TextBlock.Triggers> </TextBlock> Bind the Text property to a DependencyProperty, which has an event trigger:
public static string GetTextBoxText(DependencyObject obj) { return (string)obj.GetValue(TextBoxTextProperty); } public static void SetTextBoxText(DependencyObject obj, string value) { obj.SetValue(TextBoxTextProperty, value); } public static readonly DependencyProperty TextBoxTextProperty = DependencyProperty.RegisterAttached( "TextBoxText", typeof(string), typeof(TextBlockToolTipBehavior), new FrameworkPropertyMetadata(string.Empty, TextBoxTextChangedCallback) ); private static void TextBoxTextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { TextBlock textBlock = d as TextBlock; HandleTextChange(textBlock); } In the XAML Bind to the TextBlock text Property:
<TextBlock Text="{Binding SomeProperty, UpdateSourceTrigger=PropertyChanged}" th:TextBlockBehavior.TextBoxText="{Binding Text, RelativeSource={RelativeSource Self}}" /> Here is a similar example on MSDN using code-behind: http://msdn.microsoft.com/en-us/library/system.windows.data.binding.targetupdated.aspx
Here's something you can use I picked up from Jerry Nixon and Daren May at the Microsoft Virtual Academy "Developing Universal Windows Apps with C# and XAML" and the code that contains the DependencyObject logic is here "(W8.1-WP8.1) UNIVERSAL APP FOR MVA".
namespace App1.Behaviors { // <summary> /// Helper class that allows you to monitor a property corresponding to a dependency property /// on some object for changes and have an event raised from /// the instance of this helper that you can handle. /// Usage: Construct an instance, passing in the object and the name of the normal .NET property that /// wraps a DependencyProperty, then subscribe to the PropertyChanged event on this helper instance. /// Your subscriber will be called whenever the source DependencyProperty changes. /// </summary> public class DependencyPropertyChangedHelper : DependencyObject { /// <summary> /// Constructor for the helper. /// </summary> /// <param name="source">Source object that exposes the DependencyProperty you wish to monitor.</param> /// <param name="propertyPath">The name of the property on that object that you want to monitor.</param> public DependencyPropertyChangedHelper(DependencyObject source, string propertyPath) { // Set up a binding that flows changes from the source DependencyProperty through to a DP contained by this helper Binding binding = new Binding { Source = source, Path = new PropertyPath(propertyPath) }; BindingOperations.SetBinding(this, HelperProperty, binding); } /// <summary> /// Dependency property that is used to hook property change events when an internal binding causes its value to change. /// This is only public because the DependencyProperty syntax requires it to be, do not use this property directly in your code. /// </summary> public static DependencyProperty HelperProperty = DependencyProperty.Register("Helper", typeof(object), typeof(DependencyPropertyChangedHelper), new PropertyMetadata(null, OnPropertyChanged)); /// <summary> /// Wrapper property for a helper DependencyProperty used by this class. Only public because the DependencyProperty syntax requires it. /// DO NOT use this property directly. /// </summary> public object Helper { get { return (object)GetValue(HelperProperty); } set { SetValue(HelperProperty, value); } } // When our dependency property gets set by the binding, trigger the property changed event that the user of this helper can subscribe to private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var helper = (DependencyPropertyChangedHelper)d; helper.PropertyChanged(d, e); } /// <summary> /// This event will be raised whenever the source object property changes, and carries along the before and after values /// </summary> public event EventHandler<DependencyPropertyChangedEventArgs> PropertyChanged = delegate { }; } } Usage XAML:
<TextBlock Grid.Row="0" x:Name="WritingMenuTitle" HorizontalAlignment="Left" FontSize="32" FontWeight="SemiBold" Text="{Binding WritingMenu.Title}" TextAlignment="Left" TextWrapping="Wrap"/> Usage xaml.cs:
Behaviors.DependencyPropertyChangedHelper helper = new Behaviors.DependencyPropertyChangedHelper(this.WritingMenuTitle, Models.CommonNames.TextBlockText); helper.PropertyChanged += viewModel.OnSenarioTextBlockTextChangedEvent; Usage viewmodel.cs:
public async void OnSenarioTextBlockTextChangedEvent(object sender, DependencyPropertyChangedEventArgs args) { StringBuilder sMsg = new StringBuilder(); try { Debug.WriteLine(String.Format(".....WritingMenuTitle : New ({0}), Old ({1})", args.NewValue, args.OldValue)); } catch (Exception msg) { #region Exception ..... #endregion } }