2009-03-12 4 views
5

내 응용 프로그램에는 끌어서 놓기를 허용하는 TreeView가 있습니다. 나는 모든 기능을 잘 작동하지만 TreeViewItem을 드래그 할 때이를 강조하는 데 어려움을 겪고 있습니다. 여기 내 treeview 항목에 대한 내 스타일입니다. 드래그하는 동안 다른 마우스 이벤트를 차단하는 것처럼 보이기 때문에 IsMouseOver 트리거는 드래그하는 동안 작동하지 않습니다. 누구든지 드래그하는 동안 내 treeview 항목에 동일한 테두리 변경 트리거 할 수 있습니까? 대신 IsMouseOver의 (아마도과의 dragEnter/DragLeave)하이라이트 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> 

답변

16

나는 트리 뷰 항목의 배경색을 변경하려면이에 대한 연결된 속성을 사용하고 내 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> 
+0

그것은 아름다운 것입니다, 정말 고마워요! –

+2

이것은 정확히 내가 오늘날 필요로했던 것입니다. Stefan, 정말 고마워! 내 treeview에서 자동으로 내 방울에서 하이라이트를 제거하지 않을 것으로 나타 났으므로 드롭 이벤트를 등록하고 _dropPossible을 false로 다시 설정하고 IsPossibleDropTargetProperty를 무효화하는 간단한 함수를 작성했습니다. 아마 다른 사람에게 유용할까요? – chocojosh

+0

위대한 작품! #chocojosh가 추가 된 것 외에 추가 한 한 가지는 OnDragEvent 이벤트에 항목이있는 경우 확장하도록 TreeViewItem에 지시하는 것입니다. 다음과 같이 추가하면됩니다. if (_currentItem.HasItems) _currentItem.IsExpanded = true; – Brent

4

DragOver 행사에서 봐.

+0

"DragOver"는 "IsMouseOver"와 같은 방식으로 트리거를 설정하는 유효한 속성이 아닙니다. EventTrigger를 사용할 수 있지만 StoryBoards 만 받아들이는 것처럼 보이고 IsMouseOver Setter에서와 같은 방식으로 StoryBoard 내 테두리 속성을 설정하는 방법을 알 수 없습니다. –

+0

DropViewDropHighlighter() 생성자에 한 줄을 추가하여 놓기가 완료된 후에도 변경 내용을 제거해야했습니다 .... EventManager.RegisterClassHandler (typeof (TreeViewItem), TreeViewItem.PreviewDropEvent, new DragEventHandler (OnDragLeave), true) ; –

+0

이벤트입니다. 미안하지만 분명하지 않았어! 스타일에 이벤트 설정기를 사용하여 모든 트리보기 항목에 이벤트 설정자를 추가 할 수 있습니다. –

1

이 포스트는 VB에서 위의 Stefan의 놀라운 반응을 포팅 한 것입니다. 나는 아무것도 나쁘지 않게 망치지 않기를 바랄 때를 제외하고는 제공 할 것이 아무것도 없다. 나를 위해 일 나타납니다

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 

최종 네임 스페이스

+0

감사합니다 dansan, 완벽하게 작동합니다! 우리 VB 사람들은 죽어가는 품종이고 함께 붙어 있어야합니다! –

1

는 스테판의 대답에 더하여, 그 또한 드롭 이벤트 추가 할 필요가 발견

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); 
     } 
    } 
} 

도 등록 놓기 이벤트를 :

EventManager.RegisterClassHandler(typeof(TreeViewItem), 
      TreeViewItem.PreviewDropEvent, 
      new DragEventHandler(OnDragDrop), true); 

그렇지 않으면 한 트리 항목이 다른 트리 항목보다 떨어지는 경우 배경 변경되지 않을 수도 있습니다. 당신이 ESC를 누르면 똑같이됩니다.