标题说明了我正在尝试做的事情。这是我所拥有的:
我正在使用此CodeProject 贡献将 RubberBand 行为附加到 ListBox,以便我可以使用鼠标进行拖动选择。我能够对其进行修改,以便在 ListBox 的实例化过程中禁用它,以便在我需要 ListBox 非交互式且仅显示项目时禁用它。
ListBox 嵌入在 UserControl 中,并包含一个显示元素的画布,在我的程序的一个部分中,我需要 UserControl 作为这些元素的非交互式表示,而在另一部分中,我需要它是交互式的。但是现在,我需要能够在这两种状态之间切换,不幸的是,这不适用于我拥有 ATM 的实现,我不明白为什么。
我已将附加属性“IsActive”绑定到我的 UserControl-ViewModel 的属性“IsEditable”中,我在修改后的 RubberBand 版本(参见下面的代码)中添加了该属性,但由于某种原因,方法“IsActiveProperty_Changed”不执行,当'IsEditable' 改变。
这是我正在使用行为并绑定到“IsEditable”:
<i:Interaction.Behaviors>
<behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}"/>
</i:Interaction.Behaviors>
我也试过这个,它也不起作用:
<behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable, UpdateSourceTrigger=PropertyChanged}"/>
要禁用 ListBox 的命中检测,我还绑定到“IsEditable”,它确实可以正常工作:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}" Value="False">
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Focusable" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
因此,我怀疑这与我对 RubberBandBehavior 的实施/修改有关,因为我仍然没有实施附加属性的经验。我希望有人能发现我的错误。
修改后的 RubberBandBehavior.cs
public class RubberBandBehavior : Behavior<ListBox>
{
private RubberBandAdorner band;
private AdornerLayer adornerLayer;
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register("IsActive", typeof(bool), typeof(RubberBandBehavior),
new PropertyMetadata(IsActiveProperty_Changed));
private static void IsActiveProperty_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs args)
{
RubberBandBehavior rubberBandBehavior = (RubberBandBehavior)sender;
if (args.Property.Name == "IsActive")
{
bool newIsActiveValue = (bool)args.NewValue;
bool oldIsActiveValue = (bool)args.OldValue;
if (newIsActiveValue != oldIsActiveValue)
{
rubberBandBehavior.IsActive = newIsActiveValue;
if (rubberBandBehavior.AssociatedObject != null)
{
if (newIsActiveValue == true)
{
rubberBandBehavior.AttachBehavior();
}
else
{
rubberBandBehavior.DetachBehavior();
}
}
}
}
}
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
protected override void OnAttached()
{
AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnAttached();
}
void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
if (IsActive == true)
{
AttachBehavior();
}
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnDetaching();
}
private void AttachBehavior()
{
band = new RubberBandAdorner(AssociatedObject);
adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
adornerLayer.Add(band);
}
private void DetachBehavior()
{
adornerLayer.Remove(band);
}
}
RubberBandAdorner.cs:
public class RubberBandAdorner : Adorner
{
private Point startpoint;
private Point currentpoint;
private Brush brush;
private bool flag;
private ScrollViewer viewer;
private ScrollBar scrollbar;
public RubberBandAdorner(UIElement adornedElement)
:base(adornedElement)
{
IsHitTestVisible = false;
adornedElement.MouseMove += new MouseEventHandler(adornedElement_PreviewMouseMove);
adornedElement.MouseLeftButtonDown += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonDown);
adornedElement.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonUp);
brush = new SolidColorBrush(SystemColors.HighlightColor);
brush.Opacity = 0.3;
}
void adornedElement_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DisposeRubberBand();
}
void adornedElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ListBox _selector = AdornedElement as ListBox;
if (_selector.SelectedItems != null && (_selector.SelectionMode == SelectionMode.Extended || _selector.SelectionMode == SelectionMode.Multiple))
{
_selector.SelectedItems.Clear();
}
startpoint = Mouse.GetPosition(this.AdornedElement);
Mouse.Capture(_selector);
flag = true;
}
public static childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
// Search immediate children first (breadth-first)
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
void adornedElement_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && flag)
{
currentpoint = Mouse.GetPosition(AdornedElement);
Selector _selector = AdornedElement as Selector;
if (viewer == null)
{
viewer = FindVisualChild<ScrollViewer>(_selector);
}
if (scrollbar == null)
{
scrollbar = FindVisualChild<ScrollBar>(viewer);
}
if (_selector.Items.Count > 0)
{
if (currentpoint.Y > ((FrameworkElement)AdornedElement).ActualHeight && viewer.VerticalOffset < _selector.ActualHeight && scrollbar.Visibility == System.Windows.Visibility.Visible)
{
startpoint.Y -= 50;
}
else if (currentpoint.Y < 0 && viewer.VerticalOffset > 0 && scrollbar.Visibility == System.Windows.Visibility.Visible)
{
startpoint.Y += 50;
}
}
InvalidateVisual();
foreach (var obj in _selector.Items)
{
ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem;
if (item != null)
{
Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0));
Rect bandrect = new Rect(startpoint, currentpoint);
Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight);
if (bandrect.IntersectsWith(elementrect))
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
}
}
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect rect = new Rect(startpoint, currentpoint);
drawingContext.DrawGeometry(brush, new Pen(SystemColors.HighlightBrush, 1), new RectangleGeometry(rect));
base.OnRender(drawingContext);
}
private void DisposeRubberBand()
{
currentpoint = new Point(0, 0);
startpoint = new Point(0, 0);
AdornedElement.ReleaseMouseCapture();
InvalidateVisual();
flag = false;
}
}
更新:
这是IsEditable
ViewModel 属性的代码。请注意,我使用的RaisePropertyChanged
是 MvvmLight 中的方法:
private bool isEditable;
public bool IsEditable
{
get { return isEditable; }
set {
if(value != isEditable)
{
isEditable = value;
RaisePropertyChanged("IsEditable");
}
}
}