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
}
}
答案 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颜色,但编辑装饰物除外。因此,用户不会选择任何其他树项目。