Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8946965
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 15, 20262026-06-15T12:37:42+00:00 2026-06-15T12:37:42+00:00

Problem: In the sample below, I have a TreeView in a left column and

  • 0

Problem:

In the sample below, I have a TreeView in a left column and a ListBox in a right column. The TreeView displays a small list of sample items. When a user selects a TreeViewItem and presses F2, the item goes into ‘edit mode’ by replacing its TextBlock with a TextBox.

Now, if I select the first TreeViewItem and put it in edit mode, and then left click on the second TreeViewItem, the first item leaves edit mode, as would be expected.

However, if I put the first TreeViewItem in edit mode and then click inside the ListBox, the TreeViewItem remains in edit mode.

What’s a robust way of causing the TreeViewItem to leave edit mode when a user clicks outside of its TreeView? Naturally, please don’t propose that I simply add a mouse listener to the ListBox; I’m looking for a robust solution.


My best attempt to solve:

I tried adding an IsKeyboardFocusWithinChanged event listener to the TreeView:

private static void IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var treeView = sender as TreeView;
    if (treeView != null && !treeView.IsKeyboardFocusWithin)
    {
        EditEnding(treeView, false);
    }
}

While this did solve my problem, it had two bad side effects:

  1. When a MessageBox appears, the TreeViewItem is forced to leave edit mode.
  2. If I right click inside a TreeViewItem in edit mode, it causes the TreeViewItem to leave edit mode. This prevents me from using context menus in my TreeViewItem’s TextBox.

Sample code:

(This sample can be downloaded from Skydrive)

MainWindow.xaml:

<Window 
x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
    <DataTemplate x:Key="viewNameTemplate">
        <TextBlock 
            Text="{Binding Name}"
            FontStyle="Normal"
            VerticalAlignment="Center"
            />
    </DataTemplate>

    <DataTemplate x:Key="editNameTemplate">
        <TextBox
            Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
            VerticalAlignment="Center"
            />
    </DataTemplate>

    <Style x:Key="editableContentControl"
        TargetType="{x:Type ContentControl}"
        >
        <Setter
            Property="ContentTemplate"
            Value="{StaticResource viewNameTemplate}"
            />
        <Setter
            Property="Focusable"
            Value="False"
            />
        <Style.Triggers>
            <DataTrigger
                Binding="{Binding Path=IsInEditMode}"
                Value="True"
                >
                <Setter
                    Property="ContentTemplate"
                    Value="{StaticResource editNameTemplate}"
                    />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <TreeView
        Grid.Column="0"
        wpfApplication3:EditSelectedItemBehavior.IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=IsVisible}"
        ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type wpfApplication3:MainWindow}}, Path=Files}"
        >
        <TreeView.ItemTemplate>
            <DataTemplate>
                <ContentControl 
                    Content="{Binding}" 
                    Focusable="False"
                    Style="{StaticResource editableContentControl}" 
                    />
            </DataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
    <ListBox
        Grid.Column="1"
        ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type wpfApplication3:MainWindow}}, Path=Files}"
        />
</Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        Files = new ObservableCollection<File>();
        Files.Add(new File("A.txt"));
        Files.Add(new File("B.txt"));
        Files.Add(new File("C.txt"));
        Files.Add(new File("D.txt"));

        InitializeComponent();
    }

    public ObservableCollection<File> Files { get; private set; }
}

EditSelectedItemBehavior.cs

public static class EditSelectedItemBehavior
{
    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached(
            "IsEnabled",
            typeof(bool),
            typeof(EditSelectedItemBehavior),
            new UIPropertyMetadata(false, OnIsEnabledChanged));

    private static void OnIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var treeView = obj as TreeView;
        if (treeView == null)
        {
            return;
        }

        if (e.NewValue is bool == false)
        {
            return;
        }

        if ((bool)e.NewValue)
        {
            treeView.CommandBindings.Add(new CommandBinding(TransactionCommands.Cancel, CancelExecuted));
            treeView.CommandBindings.Add(new CommandBinding(TransactionCommands.Commit, CommitExecuted));
            treeView.CommandBindings.Add(new CommandBinding(TransactionCommands.Edit, EditExecuted));

            treeView.InputBindings.Add(new KeyBinding(TransactionCommands.Cancel, Key.Escape, ModifierKeys.None));
            treeView.InputBindings.Add(new KeyBinding(TransactionCommands.Commit, Key.Enter, ModifierKeys.None));
            treeView.InputBindings.Add(new KeyBinding(TransactionCommands.Edit, Key.F2, ModifierKeys.None));

            treeView.SelectedItemChanged += SelectedItemChanged;
            treeView.Unloaded += Unloaded;
        }
        else
        {
            for (var i = treeView.CommandBindings.Count - 1; i >= 0; i--)
            {
                var commandBinding = treeView.CommandBindings[i];
                if (commandBinding != null && (commandBinding.Command == TransactionCommands.Cancel || commandBinding.Command == TransactionCommands.Commit || commandBinding.Command == TransactionCommands.Edit))
                {
                    treeView.CommandBindings.RemoveAt(i);
                }
            }

            for (var i = treeView.InputBindings.Count - 1; i >= 0; i--)
            {
                var keyBinding = treeView.InputBindings[i] as KeyBinding;
                if (keyBinding != null && (keyBinding.Command == TransactionCommands.Cancel || keyBinding.Command == TransactionCommands.Commit || keyBinding.Command == TransactionCommands.Edit))
                {
                    treeView.InputBindings.RemoveAt(i);
                }
            }

            treeView.SelectedItemChanged -= SelectedItemChanged;
            treeView.Unloaded -= Unloaded;
        }
    }

    private static void SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var treeView = sender as TreeView;
        if (treeView != null)
        {
            EditEnding(treeView, true);
        }
    }

    private static void Unloaded(object sender, RoutedEventArgs e)
    {
        var treeView = sender as TreeView;
        if (treeView != null)
        {
            EditEnding(treeView, false);
        }
    }

    private static void EditExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        var treeView = sender as TreeView;
        if (treeView != null)
        {
            EditExecuted(treeView);
        }
    }

    private static void CommitExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        var treeView = sender as TreeView;
        if (treeView != null)
        {
            EditEnding(treeView, true);
        }
    }

    private static void CancelExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        var treeView = sender as TreeView;
        if (treeView != null)
        {
            EditEnding(treeView, false);
        }
    }

    private static void EditExecuted(TreeView treeView)
    {
        if (!TreeViewAttachedProperties.GetIsEditingObject(treeView))
        {
            var editableObject = treeView.SelectedItem as IEditableObject;
            TreeViewAttachedProperties.SetEditableObject(treeView, editableObject);

            if (editableObject != null)
            {
                TreeViewAttachedProperties.SetIsEditingObject(treeView, true);
                editableObject.BeginEdit();
            }
        }
    }

    private static void EditEnding(TreeView treeView, bool commitEdit)
    {
        if (TreeViewAttachedProperties.GetIsEditingObject(treeView))
        {
            TreeViewAttachedProperties.SetIsEditingObject(treeView, false);

            var editableObject = TreeViewAttachedProperties.GetEditableObject(treeView);
            if (editableObject != null)
            {
                if (commitEdit)
                {
                    try
                    {
                        editableObject.EndEdit();
                    }
                    catch (ArgumentOutOfRangeException aex)
                    {
                        // This is a hackaround for renaming a Biml file in Mist's project tree view,
                        // where committing an edit triggers an OutOfRange exception, despite the edit working properly.
                        Console.WriteLine(aex.Message + " " + aex.InnerException);
                    }
                }
                else
                {
                    editableObject.CancelEdit();
                }
            }
        }
    }
}  

TreeViewAttachedProperties.cs

public static class TreeViewAttachedProperties
{
    public static readonly DependencyProperty EditableObjectProperty =
           DependencyProperty.RegisterAttached(
               "EditableObject",
               typeof(IEditableObject),
               typeof(TreeViewAttachedProperties));

    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Derived type is intentionally used to restrict the parameter type.")]
    public static void SetEditableObject(TreeView treeView, IEditableObject obj)
    {
        treeView.SetValue(EditableObjectProperty, obj);
    }

    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Derived type is intentionally used to restrict the parameter type.")]
    public static IEditableObject GetEditableObject(TreeView treeView)
    {
        return (IEditableObject)treeView.GetValue(EditableObjectProperty);
    }

    public static readonly DependencyProperty IsEditingObjectProperty =
        DependencyProperty.RegisterAttached(
           "IsEditingObject",
           typeof(bool),
           typeof(TreeViewAttachedProperties));

    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Derived type is intentionally used to restrict the parameter type.")]
    public static void SetIsEditingObject(TreeView treeView, bool value)
    {
        treeView.SetValue(IsEditingObjectProperty, value);
    }

    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Derived type is intentionally used to restrict the parameter type.")]
    public static bool GetIsEditingObject(TreeView treeView)
    {
        return (bool)treeView.GetValue(IsEditingObjectProperty);
    }
}

TransactionCommands.cs:

public static class TransactionCommands
{
    private static readonly RoutedUICommand _edit = new RoutedUICommand("Edit", "Edit", typeof(TransactionCommands));

    public static RoutedUICommand Edit
    {
        get { return _edit; }
    }

    private static readonly RoutedUICommand _cancel = new RoutedUICommand("Cancel", "Cancel", typeof(TransactionCommands));

    public static RoutedUICommand Cancel
    {
        get { return _cancel; }
    }

    private static readonly RoutedUICommand _commit = new RoutedUICommand("Commit", "Commit", typeof(TransactionCommands));

    public static RoutedUICommand Commit
    {
        get { return _commit; }
    }

    private static readonly RoutedUICommand _delete = new RoutedUICommand("Delete", "Delete", typeof(TransactionCommands));

    public static RoutedUICommand Delete
    {
        get { return _delete; }
    }

    private static readonly RoutedUICommand _collapse = new RoutedUICommand("Collapse", "Collapse", typeof(TransactionCommands));

    public static RoutedUICommand Collapse
    {
        get { return _collapse; }
    }
}

File.cs:

public class File : IEditableObject, INotifyPropertyChanged
{
    private bool _editing;
    private string _name;

    public File(string name)
    {
        _name = name;
    }

    public string Name
    {
        get
        {
            return _name;
        }

        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    #region IEditableObject

    [Browsable(false)]
    protected string CachedName
    {
        get;
        private set;
    }

    [Browsable(false)]
    public bool IsInEditMode
    {
        get { return _editing; }
        private set
        {
            if (_editing != value)
            {
                _editing = value;
                OnPropertyChanged("IsInEditMode");
            }
        }
    }

    public virtual void BeginEdit()
    {
        // Save name before entering edit mode.
        CachedName = Name;
        IsInEditMode = true;
    }

    [EnvironmentPermission(SecurityAction.Demand, Unrestricted = true)]
    public virtual void EndEdit()
    {
        CachedName = string.Empty;
        IsInEditMode = false;
    }

    public void CancelEdit()
    {
        if (IsInEditMode)
        {
            if (CachedName != null)
            {
                Name = CachedName;
            }

            CachedName = string.Empty;
            IsInEditMode = false;
        }
    }

    public void SetCachedName(string cachedName)
    {
        CachedName = cachedName;
    }

    #endregion

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    #endregion
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-15T12:37:44+00:00Added an answer on June 15, 2026 at 12:37 pm

    You can add an event handler for when you lose focus on the TreeViewItem.

    Event handler method in viewmodel (or data context):

     /// <summary>
     /// This is a template method to show that something occurs when you lose focus on the TreeViewItem
     /// </summary>
     /// <param name="sender">TreeViewItem</param>
     /// <param name="e">Routed Event arguments</param>
     public void treeView_FocusLoser(object sender, RoutedEventArgs e) {
          MessageBox.Show("Argg!");
     }
    

    XAML for TreeViewItem LostFocus:

     <TreeView Name="myTreeView">
          <TreeView.ItemContainerStyle>
               <Style TargetType="{x:Type TreeViewItem}">
                    <EventSetter Event="TreeViewItem.LostFocus" Handler="treeView_FocusLoser" />
               </Style>
          </TreeView.ItemContainerStyle>
     </TreeView>
    

    Xaml for TreeView LostFocus:

     <TreeView Name="myTreeView">
          <TreeView.Style>
               <Style TargetType="{x:Type TreeView}">
                    <EventSetter Event="TreeView.LostFocus" Handler="treeView_FocusLoser" />
               </Style>
          </TreeView.Style>
     </TreeView>
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have this sample code ( below ), example1() method works with no problem,
I have no problem to run the sample code below in a iPhone simulator,
I have problem with CPaneDialog. I tested with SetPaneSize MFC feature pack sample projects.
I have problem with text drawing around Circle. I found great sample in C#
I'm loading a TreeView from a list, and the user has a button to
I am still learning Sweave and R . I have below a sample code
I have the following setup: <asp:treeview cssclass=draggable><items...> <table /> And I set it up
Have a look at the sample below which is not completely implemented but demonstrates
Check out the small html structure sample below for context. Check out this fiddle
Consider the simple example below of implementing a method in an Enum. One problem

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.