在我的应用程序中,我有一个允许拖放的TreeView。我的所有功能都运行正常,但是在拖动时突出显示TreeViewItem很困难。这是我的treeview项目的样式。拖动时IsMouseOver触发器不起作用,因为拖动似乎阻止了其他鼠标事件。任何人都可以帮我在拖动时触发我的treeview项目上相同的边框更改吗?
<Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton
x:Name="PART_Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
/>
<Border
x:Name="OuterBorder"
Grid.Column="1"
SnapsToDevicePixels="True"
BorderThickness="1"
CornerRadius="3"
BorderBrush="Transparent"
Background="Transparent"
>
<Border
x:Name="InnerBorder"
SnapsToDevicePixels="True"
BorderThickness="1"
CornerRadius="2"
BorderBrush="Transparent"
Background="Transparent"
>
<ContentPresenter
x:Name="PART_Content"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
/>
</Border>
</Border>
<ItemsPresenter
x:Name="PART_ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" SourceName="OuterBorder" Value="True">
<Setter TargetName="OuterBorder" Property="BorderBrush" Value="Blue" />
<Setter TargetName="OuterBorder" Property="Background" Value="Red" />
<Setter TargetName="InnerBorder" Property="BorderBrush" Value="White" />
</Trigger>
<MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
答案 0 :(得分:18)
我正在使用附加属性,然后在我的xaml文件中使用该属性来更改树视图项的背景颜色:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace SKNotes.Utilities
{
/// <summary>
/// Implements an attached property used for styling TreeViewItems when
/// they're a possible drop target.
/// </summary>
public static class TreeViewDropHighlighter
{
#region private variables
/// <summary>
/// the TreeViewItem that is the current drop target
/// </summary>
private static TreeViewItem _currentItem = null;
/// <summary>
/// Indicates whether the current TreeViewItem is a possible
/// drop target
/// </summary>
private static bool _dropPossible;
#endregion
#region IsPossibleDropTarget
/// <summary>
/// Property key (since this is a read-only DP) for the IsPossibleDropTarget property.
/// </summary>
private static readonly DependencyPropertyKey IsPossibleDropTargetKey =
DependencyProperty.RegisterAttachedReadOnly(
"IsPossibleDropTarget",
typeof( bool ),
typeof( TreeViewDropHighlighter ),
new FrameworkPropertyMetadata( null,
new CoerceValueCallback( CalculateIsPossibleDropTarget ) ) );
/// <summary>
/// Dependency Property IsPossibleDropTarget.
/// Is true if the TreeViewItem is a possible drop target (i.e., if it would receive
/// the OnDrop event if the mouse button is released right now).
/// </summary>
public static readonly DependencyProperty IsPossibleDropTargetProperty = IsPossibleDropTargetKey.DependencyProperty;
/// <summary>
/// Getter for IsPossibleDropTarget
/// </summary>
public static bool GetIsPossibleDropTarget( DependencyObject obj )
{
return (bool)obj.GetValue( IsPossibleDropTargetProperty );
}
/// <summary>
/// Coercion method which calculates the IsPossibleDropTarget property.
/// </summary>
private static object CalculateIsPossibleDropTarget( DependencyObject item, object value )
{
if ( ( item == _currentItem ) && ( _dropPossible ) )
return true;
else
return false;
}
#endregion
/// <summary>
/// Initializes the <see cref="TreeViewDropHighlighter"/> class.
/// </summary>
static TreeViewDropHighlighter( )
{
// Get all drag enter/leave events for TreeViewItem.
EventManager.RegisterClassHandler( typeof( TreeViewItem ),
TreeViewItem.PreviewDragEnterEvent,
new DragEventHandler( OnDragEvent ), true );
EventManager.RegisterClassHandler( typeof( TreeViewItem ),
TreeViewItem.PreviewDragLeaveEvent,
new DragEventHandler( OnDragLeave ), true );
EventManager.RegisterClassHandler( typeof( TreeViewItem ),
TreeViewItem.PreviewDragOverEvent,
new DragEventHandler( OnDragEvent ), true );
}
#region event handlers
/// <summary>
/// Called when an item is dragged over the TreeViewItem.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="args">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
static void OnDragEvent( object sender, DragEventArgs args )
{
lock ( IsPossibleDropTargetProperty )
{
_dropPossible = false;
if ( _currentItem != null )
{
// Tell the item that previously had the mouse that it no longer does.
DependencyObject oldItem = _currentItem;
_currentItem = null;
oldItem.InvalidateProperty( IsPossibleDropTargetProperty );
}
if ( args.Effects != DragDropEffects.None )
{
_dropPossible = true;
}
TreeViewItem tvi = sender as TreeViewItem;
if ( tvi != null )
{
_currentItem = tvi;
// Tell that item to re-calculate the IsPossibleDropTarget property
_currentItem.InvalidateProperty( IsPossibleDropTargetProperty );
}
}
}
/// <summary>
/// Called when the drag cursor leaves the TreeViewItem
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="args">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
static void OnDragLeave( object sender, DragEventArgs args )
{
lock ( IsPossibleDropTargetProperty )
{
_dropPossible = false;
if ( _currentItem != null )
{
// Tell the item that previously had the mouse that it no longer does.
DependencyObject oldItem = _currentItem;
_currentItem = null;
oldItem.InvalidateProperty( IsPossibleDropTargetProperty );
}
TreeViewItem tvi = sender as TreeViewItem;
if ( tvi != null )
{
_currentItem = tvi;
tvi.InvalidateProperty( IsPossibleDropTargetProperty );
}
}
}
#endregion
}
}
然后在xaml文件中:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="utils:TreeViewDropHighlighter.IsPossibleDropTarget" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
答案 1 :(得分:4)
查看DragOver事件(可能还有DragEnter / DragLeave)而不是IsMouseOver。
答案 2 :(得分:1)
这篇文章只是将Stefan对VB的强烈回应移植到VB上,对于我们这些在这些范围内工作的人来说;除了希望我没有把任何事情搞得太糟糕之外,我什么也没提供。它似乎对我有用:
Namespace SKNotes.Utilities
''' <summary>
''' Implements an attached property used for styling TreeViewItems when
''' they are a possible drop target.
''' </summary>
Public Class TreeViewDropHighlighter
''' <summary>
''' The TreeViewItem that is the current drop target
''' </summary>
Private Shared _CurrentItem As TreeViewItem = Nothing
''' <summary>
''' Indicates whether the current TreeView Item is a possible drop target
''' </summary>
''' <remarks></remarks>
Private Shared _DropPossible As Boolean
''' <summary>
''' Property Key (since this is a read only DP) for the IsPossibleDropTarget property.
''' </summary>
''' <remarks></remarks>
Private Shared ReadOnly IsPossibleDropTargetKey As DependencyPropertyKey = _
DependencyProperty.RegisterAttachedReadOnly _
( _
"IsPossibleDropTarget", _
GetType(Boolean), _
GetType(TreeViewDropHighlighter), _
New FrameworkPropertyMetadata(Nothing, _
New CoerceValueCallback(AddressOf CalculateIsPossibleDropTarget)
)
)
''' <summary>
''' Dependency Property IsPossibleDropTarget.
''' Is true if the TreeViewItem is a possible drop target (ie, if it would receive the
''' OnDrop even if the mouse button is release right now).
''' </summary>
''' <remarks></remarks>
Public Shared ReadOnly IsPossibleDropTargetProperty As DependencyProperty = IsPossibleDropTargetKey.DependencyProperty
''' <summary>
''' Getter for IsPossibleDropTarget
''' </summary>
Public Shared Function GetIsPossibleDropTarget(ByVal obj As DependencyObject) As Boolean
Return CBool(obj.GetValue(IsPossibleDropTargetProperty))
End Function
''' <summary>
''' Coercion method which calculates the IsPossibleDropTarget property
''' </summary>
Private Shared Function CalculateIsPossibleDropTarget(item As DependencyObject, value As Object) As Object
If item.Equals(_CurrentItem) And _
_DropPossible Then
Return True
Else
Return False
End If
End Function
''' <summary>
''' Initializes the TreeViewDropHighlighter class
''' </summary>
Shared Sub New()
EventManager.RegisterClassHandler(GetType(TreeViewItem), _
TreeViewItem.PreviewDragEnterEvent, _
New DragEventHandler(AddressOf OnDragEvent), True)
EventManager.RegisterClassHandler(GetType(TreeViewItem), _
TreeViewItem.PreviewDragLeaveEvent,
New DragEventHandler(AddressOf OnDragLeave), True)
EventManager.RegisterClassHandler(GetType(TreeViewItem), _
TreeViewItem.PreviewDragOverEvent, _
New DragEventHandler(AddressOf OnDragEvent), True)
End Sub
''' <summary>
''' Called when an item is dragged over the TreeView Item
''' </summary>
''' <param name="sender">The sender</param>
''' <param name="args">The System.Windows.DragEventArgs instance containing the event data</param>
''' <remarks></remarks>
Shared Sub OnDragEvent(sender As Object, args As DragEventArgs)
SyncLock (IsPossibleDropTargetProperty)
_DropPossible = False
If Not IsNothing(_CurrentItem) Then
'Tell the item that previously had the mouse that it no longer does.
Dim OldItem As DependencyObject = _CurrentItem
_CurrentItem = Nothing
OldItem.InvalidateProperty(IsPossibleDropTargetProperty)
End If
If args.Effects <> DragDropEffects.None Then
_DropPossible = True
End If
Dim tvi As TreeViewItem = CType(sender, TreeViewItem)
If Not IsNothing(tvi) Then
_CurrentItem = tvi
'Tell that item to recalculate the IsPossibleDropTarget property
_CurrentItem.InvalidateProperty(IsPossibleDropTargetProperty)
End If
End SyncLock
End Sub
Shared Sub OnDragLeave(sender As Object, args As DragEventArgs)
SyncLock (IsPossibleDropTargetProperty)
_DropPossible = False
If Not IsNothing(_CurrentItem) Then
'Tell the item that previously had the mouse that it no longer does
Dim OldItem As DependencyObject = _CurrentItem
_CurrentItem = Nothing
OldItem.InvalidateProperty(IsPossibleDropTargetProperty)
End If
Dim tvi As TreeViewItem = CType(sender, TreeViewItem)
If Not IsNothing(tvi) Then
_CurrentItem = tvi
tvi.InvalidateProperty(IsPossibleDropTargetProperty)
End If
End SyncLock
End Sub
End Class
结束命名空间
答案 3 :(得分:1)
除了Stefan的回答,我发现还需要添加Drop事件:
static void OnDragDrop(object sender, DragEventArgs args)
{
lock (IsPossibleDropTargetProperty)
{
_dropPossible = false;
if (_currentItem != null)
{
_currentItem.InvalidateProperty(IsPossibleDropTargetProperty);
}
TreeViewItem tvi = sender as TreeViewItem;
if (tvi != null)
{
tvi.InvalidateProperty(IsPossibleDropTargetProperty);
}
}
}
并注册drop事件:
EventManager.RegisterClassHandler(typeof(TreeViewItem),
TreeViewItem.PreviewDropEvent,
new DragEventHandler(OnDragDrop), true);
否则,如果一个treeItem发生丢弃,则背景可能不会改变。如果按ESC键也一样。