在TreeView中禁用修饰元素时,如何启用编辑修饰符?

时间:2018-07-01 17:37:11

标签: wpf treeview adorner

WPF

我有一个TreeView(见下文),为此我创建了一个Editing Adorner。 一切正常。但是,我想在编辑过程中禁用TreeView。禁用TreeView时-以及装饰元素进行编辑-禁用装饰器。

如何禁用TreeView(IsEnabled = false),但仍允许启用Adorner进行编辑?

TIA

namespace Doctor_Desk.Views.Adorners
{
    public class EditSelectedItemAdorner : Adorner
    {
        private VisualCollection _Visuals;
        private UIElement _UIElement;
        private bool _IsCancel = false;
        private TextBox _Textbox;

        protected override int VisualChildrenCount
        {
            get
            {
                return _Visuals.Count;
            }
        }

        // Be sure to call the base class constructor.
        public EditSelectedItemAdorner(UIElement adornedElement, IConsultantTreeItem selectedItem)
          : base(adornedElement)
        {
            _UIElement = adornedElement;
            adornedElement.Visibility = Visibility.Hidden;

            _Textbox = new TextBox
            {
                Background = Brushes.Pink,
                Text = selectedItem.GetText()
            };

            // The VisualCollection will hold the content of this Adorner.
            _Visuals = new VisualCollection(this)
            {
                // The _Textbox is a logical child of the VisualCollection of the Adorner. The ArrangeOverride and MeasureOverride 
                // will set up the Grid control for correct rendering.
                _Textbox   // Adding a single control for display.
            };

        }



        /// The adorner placement is always relative to the top left corner of the adorned element. The children of the adorner are located by
        /// implementing ArrangeOverride. The only other way to position the Adorner content is to use the AdornerPanel Class 
        /// with it's AdornerPlacementCollection Methods.
        /// 
        /// Overriding the default ArrangeOverride and MeasureOverride allows a control to be placed and diplayed in the VisualCollection.
        protected override Size ArrangeOverride(Size finalSize)
        {
            //TextBox child = _Visuals[0] as TextBox;
            //FrameworkElement element = _UIElement as FrameworkElement;
            //if (element != null)
            //{
            //    Size textBoxSize = new Size(Math.Max(150, element.DesiredSize.Width), Math.Max(30, element.DesiredSize.Height));
            //    Point location = new Point((this.Width - textBoxSize.Width) / 2,
            //        (textBoxSize.Height - this.Height) / 2);
            //    child.Arrange(new Rect(location, textBoxSize));
            //}

            TextBox child = _Visuals[0] as TextBox;
            Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
            child.Arrange(adornedElementRect);

            return base.ArrangeOverride(finalSize);
        }

        // Overriding the default ArrangeOverride and MeasureOverride allows a control to be diplayed in the VisualCollection.
        protected override Size MeasureOverride(Size constraint)
        {
            _Textbox.Measure(constraint);
            return _Textbox.DesiredSize;
        }

        protected override Visual GetVisualChild(int index)
        {
            return _Visuals[index];
        }

        // A common way to implement an adorner's rendering behavior is to override the OnRender
        // method, which is called by the layout system as part of a rendering pass.
        protected override void OnRender(DrawingContext drawingContext)
        {
            Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);

            // Some arbitrary drawing implements.
            SolidColorBrush renderBrush = new SolidColorBrush(Colors.Green)
            {
                Opacity = 0.2
            };
            Pen renderPen = new Pen(new SolidColorBrush(Colors.Navy), 1.5);
            double renderRadius = 5.0;

            // Draw a circle at each corner.
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius);
        }



        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(EditSelectedItemAdorner), new PropertyMetadata(string.Empty));


    }
}



 <TreeView  Grid.Row="2"  Grid.Column="2"  Grid.RowSpan="4"  Width="400"
                   ItemsSource="{Binding SpecialityTree}" 
                   >
            <TreeView.Resources>


                <HierarchicalDataTemplate DataType="{x:Type tree:SpecialityTreeItem}" ItemsSource="{Binding Offices}" >
                    <TextBlock Text="{Binding Title}" />
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type tree:OfficeTreeItem}" ItemsSource="{Binding Doctors}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>

                <DataTemplate DataType="{x:Type tree:DoctorTreeItem}">
                    <StackPanel Orientation="Horizontal" >
                        <TextBlock Text="{Binding FirstName}" />
                        <TextBlock Text="  " />
                        <TextBlock Text="{Binding LastName}" />
                    </StackPanel>
                </DataTemplate>
            </TreeView.Resources>
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsExpanded" Value="True"/>
                </Style>
            </TreeView.ItemContainerStyle>

            <i:Interaction.Behaviors>
                <b:ConsultantTreeViewBehavior 
                    EditSelectedItem="{Binding IsEditing}"
                    SelectedItem="{Binding SelectedTreeItem, Mode=TwoWay}"
                    Text="{Binding EditingResult, Mode=OneWayToSource}"
                     />
            </i:Interaction.Behaviors>





namespace Doctor_Desk.Views.Behaviors
{
    public class ConsultantTreeViewBehavior : Behavior<TreeView>
    {
        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            if (AssociatedObject != null)
            {
                AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
            }
        }

        private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            SelectedItem = e.NewValue;
        }

        #region SelectedItem Property

        public object SelectedItem
        {
            get { return GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(object), typeof(ConsultantTreeViewBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));

        private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue is TreeViewItem item)
            {
                item.SetValue(TreeViewItem.IsSelectedProperty, true);
            }
        }

        #endregion

        #region [EditSelectedItem]

        public bool EditSelectedItem
        {
            get { return (bool)GetValue(EditSelectedItemProperty); }
            set { SetValue(EditSelectedItemProperty, value); }
        }

        private EditSelectedItemAdorner _Adorner;

        public AdornerLayer myAdornerLayer { get; set; }

        // Using a DependencyProperty as the backing store for EditSelectedItem.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EditSelectedItemProperty =
            DependencyProperty.Register("EditSelectedItem", typeof(bool), typeof(ConsultantTreeViewBehavior), new PropertyMetadata(false, OnEditSelectedItem));

        private static void OnEditSelectedItem(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                var d = sender as ConsultantTreeViewBehavior;
                var h = d.AssociatedObject as TreeView;

                TreeViewItem tvi = h
                       .ItemContainerGenerator
                       .ContainerFromItemRecursive(h.SelectedItem);

                if (tvi is UIElement myItem)
                {
                    d._Adorner = new EditSelectedItemAdorner(myItem, (IConsultantTreeItem)h.SelectedItem);

                    // Must have BindingMode.TwoWay for the Adorner to update this ConsultantTreeViewBehavior.
                    var bindingText = new Binding
                    {
                        Source = d,
                        Path = new PropertyPath(TextProperty),
                        Mode = BindingMode.TwoWay
                    };
                    // The TextProperty binds the Text from the EditSelectedItemAdorner to the ConsultantManagerViewModel.
                    BindingOperations.SetBinding(d._Adorner, EditSelectedItemAdorner.TextProperty, bindingText);

                    d.myAdornerLayer = AdornerLayer.GetAdornerLayer(myItem);
                    d.myAdornerLayer.Add(d._Adorner);
                }
            }
        }

        #endregion

        #region[Text - xaml binding]
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(ConsultantTreeViewBehavior), new PropertyMetadata(string.Empty,
                (s, e) =>
                {

                }));
        #endregion

    }

}

1 个答案:

答案 0 :(得分:0)

好吧,在任何其他答案中,看来在TreeView中禁用选择会禁用TreeView的所有元素-包括所选分支。当选定的分支被禁用时,其编辑装饰器也将被禁用。因此,我的解决方法只是覆盖正在显示的TreeView的那一部分。

尤其是在OnRender替代中,添加:

 // Find offset of selected item from top of the tree.
        GeneralTransform gt = AdornedElement.TransformToVisual(_TreeView);
        Point offset_to_tree_top = gt.Inverse.Transform(new Point(0, 0));
        drawingContext.DrawRectangle(Brushes.DimGray, null, new Rect( 
        offset_to_tree_top, _TreeView.DesiredSize));

这会在整个树上添加DimGray颜色,但编辑装饰物除外。因此,用户不会选择任何其他树项目。