ContextMenu가 표시되기 직전에 마우스 오른쪽 버튼을 클릭하여 WPF TreeView 노드를 선택하고 싶습니다.
WinForms의 경우 컨텍스트 메뉴 에서 클릭 한 Find 노드 와 같은 코드를 사용할 수 있습니다 . WPF 대안은 무엇입니까?
답변
트리가 채워진 방식에 따라 보낸 사람과 e.Source 값이 다를 수 있습니다 .
가능한 솔루션 중 하나는 e.OriginalSource를 사용하고 VisualTreeHelper를 사용하여 TreeViewItem을 찾는 것입니다.
private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);
if (treeViewItem != null)
{
treeViewItem.Focus();
e.Handled = true;
}
}
static TreeViewItem VisualUpwardSearch(DependencyObject source)
{
while (source != null && !(source is TreeViewItem))
source = VisualTreeHelper.GetParent(source);
return source as TreeViewItem;
}
답변
XAML 전용 솔루션을 원하는 경우 Blend Interactivity를 사용할 수 있습니다.
가정 TreeView
가진 뷰 모델의 계층 컬렉션에 데이터 바인딩이다 Boolean
재산 IsSelected
과 String
재산 Name
뿐만 아니라라는 이름의 하위 항목의 컬렉션을 Children
.
<TreeView ItemsSource="{Binding Items}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseRightButtonDown">
<ei:ChangePropertyAction PropertyName="IsSelected" Value="true" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
두 가지 흥미로운 부분이 있습니다.
-
TreeViewItem.IsSelected
속성은 바인딩 된IsSelected
뷰 모델에 대한 속성입니다.IsSelected
뷰 모델 의 속성을 true로 설정하면 트리에서 해당 노드가 선택됩니다. -
경우
PreviewMouseRightButtonDown
(이 샘플 A의 노드의 시각적 부분 화재TextBlock
)를IsSelected
뷰 모델에 속성이 참으로 설정된다. 1로 돌아 가면 트리에서 클릭 한 해당 노드가 선택된 노드가되는 것을 볼 수 있습니다.
프로젝트에서 Blend Interactivity를 얻는 한 가지 방법은 NuGet 패키지 Unofficial.Blend.Interactivity 를 사용하는 것 입니다.
답변
“item.Focus ();”사용 “item.IsSelected = true;”를 사용하여 100 % 작동하지 않는 것 같습니다. 않습니다.
답변
XAML에서 XAML에 PreviewMouseRightButtonDown 처리기를 추가합니다.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- We have to select the item which is right-clicked on -->
<EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown"/>
</Style>
</TreeView.ItemContainerStyle>
그런 다음 다음과 같이 이벤트를 처리합니다.
private void TreeViewItem_PreviewMouseRightButtonDown( object sender, MouseEventArgs e )
{
TreeViewItem item = sender as TreeViewItem;
if ( item != null )
{
item.Focus( );
e.Handled = true;
}
}
답변
alex2k8의 원래 아이디어를 사용하여 Wieser Software Ltd의 비 비주얼, Stefan의 XAML, Erlend의 IsSelected 및 정적 메서드 Generic을 만드는 데 기여한 내용을 올바르게 처리합니다.
XAML :
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- We have to select the item which is right-clicked on -->
<EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown"
Handler="TreeViewItem_PreviewMouseRightButtonDown"/>
</Style>
</TreeView.ItemContainerStyle>
뒤에 C # 코드 :
void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem treeViewItem =
VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject);
if(treeViewItem != null)
{
treeViewItem.IsSelected = true;
e.Handled = true;
}
}
static T VisualUpwardSearch<T>(DependencyObject source) where T : DependencyObject
{
DependencyObject returnVal = source;
while(returnVal != null && !(returnVal is T))
{
DependencyObject tempReturnVal = null;
if(returnVal is Visual || returnVal is Visual3D)
{
tempReturnVal = VisualTreeHelper.GetParent(returnVal);
}
if(tempReturnVal == null)
{
returnVal = LogicalTreeHelper.GetParent(returnVal);
}
else returnVal = tempReturnVal;
}
return returnVal as T;
}
편집 : 이전 코드는이 시나리오에서 항상 잘 작동했지만 다른 시나리오에서는 LogicalTreeHelper가 값을 반환 할 때 VisualTreeHelper.GetParent가 null을 반환하므로이를 수정했습니다.
답변
거의 맞지만, 트리에서 비 시각적 요소 (예 :)를주의해야합니다 Run
.
static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
{
while (source != null && source.GetType() != typeof(T))
{
if (source is Visual || source is Visual3D)
{
source = VisualTreeHelper.GetParent(source);
}
else
{
source = LogicalTreeHelper.GetParent(source);
}
}
return source;
}
답변
클래스 핸들러를 등록하는 것이 트릭을해야한다고 생각합니다. 다음과 같이 app.xaml.cs 코드 파일에있는 TreeViewItem의 PreviewMouseRightButtonDownEvent에 라우트 된 이벤트 핸들러를 등록하기 만하면됩니다.
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.PreviewMouseRightButtonDownEvent, new RoutedEventHandler(TreeViewItem_PreviewMouseRightButtonDownEvent));
base.OnStartup(e);
}
private void TreeViewItem_PreviewMouseRightButtonDownEvent(object sender, RoutedEventArgs e)
{
(sender as TreeViewItem).IsSelected = true;
}
}