2009-01-29 4 views
9

Ich habe ein ziemlich lustiges Problem mit WPF. Ich habe eine Baumansicht und die Auswahl von Elementen funktioniert soweit. Das Problem ist, ich möchte das aktuell ausgewählte Element abwählen, wenn der Benutzer in den leeren Bereich der Baumansicht klickt. Standardmäßig hält das treeview das aktuelle Element ausgewählt, und ich habe ein Kontextmenü-Option hinzugefügt, um es zu deaktivieren, was ziemlich hardcore ist:Wie Sie alle ausgewählten Elemente in einer WPF-Strukturansicht abwählen, wenn Sie auf einen leeren Bereich klicken?

// Note: This is done recursivly from the start, so it 
// works for child items as well 
treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem) as TreeViewItem).IsSelected = false; 

Darüber hinaus ist dies kontraintuitiv, da es dem Benutzer erfordert, Klicken Sie mit der rechten Maustaste zuerst, und zweitens, nachdem Sie auf diese Weise die Auswahl aufgehoben haben, kann der Benutzer sie nicht mehr auswählen, indem er auf das Element klickt. Wie soll das funktionieren?

Edit: Einige weitere Informationen: Ich habe einen Handler zum TreeView hinzugefügt Mausklickereignisse zu handhaben, aber der Absender ist immer eine TreeView Instanz, auch wenn ich direkt auf einem TreeViewItem klicken. Wenn ich stattdessen einen Handler zu meinem TreeView.ItemTemplate hinzufüge (d. H. Dem ersten Kind in der Vorlage), erhalte ich niemals Ereignisse, wenn ich auf den leeren Bereich klicke (was ziemlich logisch ist). Der Code sieht wie folgt aus:

private void MyTreeView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     if ((sender as TreeViewItem) == null) 
     { 
      // Always triggered 
      System.Diagnostics.Trace.Write("Empty area clicked"); 
     } 
    } 

Und die XAML hierfür ist:

<TreeView x:Name="MyTreeView" Margin="3" MouseUp="MyTreeView_MouseUp"> 

Antwort

0

Dies wird die aktuell ausgewählte TreeViewItem deaktivieren, wenn keine angeklickt wurden:

private void MyTreeView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { 
    if ((sender as TreeViewItem) == null) { 
     TreeViewItem item = MyTreeView.SelectedItem as TreeViewItem; 
     if(item != null){ 
      item.IsSelected = false;      
     } 
    } 
} 

Hoffnung das ist, was Du hast gesucht!

+0

Funktioniert nicht, weil der Absender nach der Auswahl eines Elements an das aktuell ausgewählte Element gebunden ist - das heißt, auch wenn ich in den leeren Bereich klicke, Absender == das aktuell ausgewählte Element. – Anteru

+0

Hmm. Wenn Sie auf die TreeView selbst klicken, sollte der Absender eine TreeView (kein TreeViewItem) sein. Hast du diesen Handler zur TreeView oder zu jedem TreeViewItem hinzugefügt? Verwenden Sie das Standard-TreeView oder ein benutzerdefiniertes? – Pwninstein

+0

Ahh das Problem ist, ich bekomme kein TreeViewItem, sondern eine Instanz meiner viewmodel Klasse, für die ich das entsprechende TreeViewItem finden muss. Schlimmer noch, nachdem ich ein Element programmgesteuert deaktiviert habe, kann ich es nicht erneut auswählen, indem ich darauf klicke. – Anteru

5

Das nicht auswählbare Problem kann mit einem Aufruf von Focus auf der TreeView nach dem Festlegen von TreeViewItem.IsSelected behoben werden.

+1

Nett, guter Fang! Ich habe mich gefragt, warum ich nicht in der Lage war, denselben Knoten auszuwählen, wenn er nicht ausgewählt wurde. Danke! – HaxElit

6

Ich fand dies viel besser für mich arbeiten. Ich überprüfe die Originaldatenquelle, die für mich, wenn es ein TreeViewitem kommt, ein Bild oder ein Textblock ist. Ich verwende auch ein View-Objekt mit einer HierarchicalDataTemplate und die BasicTreeViewBase ist die Basisklasse für alle meine verschiedenen Objekte. Hier ist der Code.

private void TemplateTreeView_MouseDown(object sender, MouseButtonEventArgs e) 
    { 
     if (e.ChangedButton == MouseButton.Right && !(e.OriginalSource is Image) && !(e.OriginalSource is TextBlock)) 
     { 
      BasicTreeViewBase item = TemplateTreeView.SelectedItem as BasicTreeViewBase; 
      if (item != null) 
      { 
       TemplateTreeView.Focus(); 
       item.IsSelected = false; 
      } 
     } 
    } 
+0

Warum brauchen Sie 'TemplateTreeView.Focus();'? –

+0

@DavidRefaeli das war so lange her, ich erinnere mich nicht, warum ich es hatte. Ich weiß, dass es nicht funktioniert hat, als ich es geschrieben habe. – Erin

+0

es ist eine nette Lösung, ich musste einige Anpassungen vornehmen, da Sie hier Ihre eigenen Klassen verwenden (TemplateTreeView, BasicTreeViewBase) - aber für mich muss ich die .Focus() nicht ändern, um das Element abzuwählen . –

2

Ich implementiert einmal eine allgemeine Auswahlkontrolle und erforderte dieses Verhalten. Diese

ist, wie meine Methode sah (für treeview angepasst):

protected override void OnMouseUp(MouseButtonEventArgs e) 
{ 
    base.OnMouseUp(e); 

    DependencyObject dpSource = e.OriginalSource as DependencyObject; 

    if (dpSource.FindVisualAncestor(o => typeof(TreeViewItem).IsAssignableFrom(o.GetType())) == null) 
      UnselectAll(); 
} 

Grundsätzlich den Baum von der Quelle zu Fuß auf. Wenn ein TreeViewItem nicht gefunden wurde, klickte der Benutzer auf den leeren Bereich.

4

Es kann zwei weitere Probleme:

  1. Die treeview binded wird so die SelectedItem ist ein Element der binded Sammlung.
  2. Es gibt viele Ebenen ItemContainerGenerator nicht so enthalten tiefsten Ebene

für all diesem Grund habe ich diese Funktion verwenden, Objekte, aber die Auswahl alle Ereignisse nicht ausgelöst müssen.

private void UnselectTreeViewItem(TreeView pTreeView) 
{ 
    if(pTreeView.SelectedItem == null) 
    return; 

    if(pTreeView.SelectedItem is TreeViewItem) 
    { 
    (pTreeView.SelectedItem as TreeViewItem).IsSelected = false; 
    } 
    else 
    { 
    TreeViewItem item = pTreeView.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem; 
    if (item != null) 
    { 
     item.IsSelected = true; 
     item.IsSelected = false; 
    } 
    } 
} 
1

die Erweiterungsklasse Verwenden Sie unter

public static class TreeViewExtensions 
{ 
    public static TreeViewItem ContainerFromItem(this TreeView treeView, object item) 
    { 
     TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item); 
     if (containerThatMightContainItem != null) 
      return containerThatMightContainItem; 
     else 
      return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item); 
    } 

    private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item) 
    { 
     foreach (object curChildItem in itemCollection) 
     { 
      TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem); 
      TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item); 
      if (containerThatMightContainItem != null) 
       return containerThatMightContainItem; 

      TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item); 
      if (recursionResult != null) 
       return recursionResult; 
     } 
     return null; 
    } 
} 

Dann in MouseDown- Falle treeview wie unten die Erweiterungsmethode verwenden:

private void trview_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     if ((sender as TreeViewItem) == null) 
     { 
      if (this.trview.ContainerFromItem(trview.SelectedItem) != null) 
      { 
       this.trview.ContainerFromItem(trview.SelectedItem).IsSelected = false; 
      } 
     } 
     this.trview.Focus(); 
    } 

Hoffe, dass es für Sie arbeitet. Ich habe es auf diese Weise funktioniert ...

+0

Das funktioniert, ist einfach und in sich abgeschlossen. Vielen Dank! – fabspro

1

Ich war in dieser Situation selbst mit einer benutzerdefinierten Tree List View Implementierung nach dem Suchen nach einer langen Zeit lief ich endlich eine Lösung, die für mich arbeitete.

Die vollständige Erklärung finden Sie unter http://social.msdn.microsoft.com/Forums/vstudio/en-US/36aca7f7-0b47-488b-8e16-840b86addfa3/getting-treeviewitem-for-the-selected-item-in-a-treeview

Die Grundidee ist, Sie erfassen die TreeViewItem.Selected Ereignis und speichern Sie die Quelle des Ereignisses in das Tag Attribut auf Ihrem TreeView finden. Dann, wenn Sie es löschen müssen, können Sie auf das Attribut Tag auf Ihrem Steuerelement zugreifen und den IsSelected Wert auf False setzen. Dies funktioniert für mich mit 2 Ebenen von verschachtelten Kindern. Hoffentlich wird es für dich arbeiten.

Für Persistenz zuliebe:

TreeView Erklärung

<TreeView Name="myTreeView" TreeViewItem.Selected="OnItemSelected" 
    ItemsSource="{Binding Source={StaticResource myHierarchicalData}}"/> 

Event Handler

private void OnItemSelected(object sender, RoutedEventArgs e) 
{ 
    myTreeView.Tag = e.OriginalSource; 
} 

Auswahl löschen Logik

if (myTreeView.SelectedItem != null) 
{ 
    TreeViewItem selectedTVI = myTreeView.Tag as TreeViewItem; 
    // add your code here mine was selectedTVI.IsSelected = false; 
} 
0

Für eine C# treeview Sie treeview.Select verwenden edNode = null; Ich bin mir nicht sicher, ob das für WPF funktioniert.

+0

Es funktioniert nicht, da 'SelectedItem' in WPF schreibgeschützt ist. –

Verwandte Themen