locked
Data binding and IsUndoEnabled RRS feed

  • Question

  • why does the XAML:

    Code Block

    <Window x:Class="WpfApplication4.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300">

    <StackPanel>

    <StackPanel.Resources>

    <Rect x:Key="foo" X="4"/>

    </StackPanel.Resources>

    <TextBox Name="bar" DataContext="{StaticResource foo}" Text="{Binding Path=X}" IsUndoEnabled="False"/>

    </StackPanel>

    </Window>

     

     

    result in the following exception?

    System.Windows.Markup.XamlParseException occurred
      Message="'System.Windows.Data.BindingExpression' value cannot be assigned to property 'Text' of object 'System.Windows.Controls.TextBox'. Cannot use UndoService while it is disabled.  Error at object 'System.Windows.Data.Binding' in markup file 'WpfApplication4;component/window1.xaml' Line 10 Position 64."
      Source="PresentationFramework"
      LineNumber=10
      LinePosition=64
      NameContext="Text"
      StackTrace:
           at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType)
           at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException)
           at System.Windows.Markup.BamlRecordReader.ThrowException(String message, Exception innerException)
           at System.Windows.Markup.BamlRecordReader.SetDependencyComplexProperty(Object currentTarget, BamlAttributeInfoRecord attribInfo, Object o)
           at System.Windows.Markup.BamlRecordReader.SetPropertyValueToParent(Boolean fromStartTag, Boolean& isMarkupExtension)
           at System.Windows.Markup.BamlRecordReader.SetPropertyValueToParent(Boolean fromStartTag)
           at System.Windows.Markup.BamlRecordReader.ReadElementEndRecord(Boolean fromNestedBamlRecordReader)
           at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
           at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord)
           at System.Windows.Markup.TreeBuilderBamlTranslator.ParseFragment()
           at System.Windows.Markup.TreeBuilder.Parse()
           at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
           at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
           at WpfApplication4.Window1.InitializeComponent() in c:\Users\Michael\Documents\Visual Studio 2008\Projects\WpfApplication4\WpfApplication4\Window1.xaml:line 1
           at WpfApplication4.Window1..ctor() in C:\Users\Michael\Documents\Visual Studio 2008\Projects\WpfApplication4\WpfApplication4\Window1.xaml.cs:line 24
      InnerException: System.InvalidOperationException
           Message="Cannot use UndoService while it is disabled."
           Source="PresentationFramework"
           StackTrace:
                at MS.Internal.Documents.UndoManager.Clear()
                at System.Windows.Controls.TextBox.OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
                at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
                at System.Windows.Controls.TextBox.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
                at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
                at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)
                at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal)
                at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
                at System.Windows.Markup.BamlRecordReader.SetDependencyValueCore(DependencyObject dependencyObject, DependencyProperty dependencyProperty, Object value)
                at System.Windows.Markup.BamlRecordReader.SetDependencyValue(DependencyObject dependencyObject, DependencyProperty dependencyProperty, Object value)
                at System.Windows.Markup.BamlRecordReader.SetDependencyComplexProperty(Object currentTarget, BamlAttributeInfoRecord attribInfo, Object o)
           InnerException:

     

    I is a simplified example, I want to implement Undo accross the application.

    Friday, November 16, 2007 3:45 AM

Answers

  • You can use CommandBinding to wire up your custom undo/redo logic, this will bypass the built-in undo/redo processing. Here is an example:

     

    CommandBinding cb = new CommandBinding();

    cb.Command = ApplicationCommands.Undo;

    cb.CanExecute += delegate(object sender, CanExecuteRoutedEventArgs e)

    {

        e.CanExecute = textBox.IsFocused;

    };

    cb.Executed += delegate(object sender, ExecutedRoutedEventArgs e)

    {

        //Custom undo processing comes here.

        e.Handled = true;

    };

    textBox.CommandBindings.Add(cb);

    Hope this helps

    Thursday, November 22, 2007 2:14 AM

All replies

  • When a BindingExpression is applied to TextBox.Text property, the undo and redo stack will be cleared. This will cause troubles if the IsUndoEnabled property is set to false. Specifically speaking why do you need to disable undo at this circumstance?

     

    Tuesday, November 20, 2007 6:28 AM
  • I don't want the text box to handle undo/redo.  I've implemented a command pattern in the data layer to handle undo.  I have other things that need to be on the undo/redo stack, like collection manipulations, and method calls.

    Tuesday, November 20, 2007 6:42 PM
  • Well, Then you'd better not to use binding (or other type of stuff such as DynamicResourceExtension etc which will result in an expression applied to the Text property), because applying expression and disabling undo will run into a conflicting situation.

     

     

     

    Wednesday, November 21, 2007 2:49 AM
  • I'm sorry, but the bundling of undo and data binding seems really tragic (they seem unrelated to me).  Is there a way of intercepting the undo/redo requests before the text boxes handle them? I.e. leaving the IsUndoEnabled value set to true, but bypassing the command?

    Wednesday, November 21, 2007 3:54 AM
  • You can use CommandBinding to wire up your custom undo/redo logic, this will bypass the built-in undo/redo processing. Here is an example:

     

    CommandBinding cb = new CommandBinding();

    cb.Command = ApplicationCommands.Undo;

    cb.CanExecute += delegate(object sender, CanExecuteRoutedEventArgs e)

    {

        e.CanExecute = textBox.IsFocused;

    };

    cb.Executed += delegate(object sender, ExecutedRoutedEventArgs e)

    {

        //Custom undo processing comes here.

        e.Handled = true;

    };

    textBox.CommandBindings.Add(cb);

    Hope this helps

    Thursday, November 22, 2007 2:14 AM