2013-12-20 57 views
2

我想創建一個遞歸方法來取消選擇WPF TreeView中的所有項目。讓事情變得複雜的是每個TreeViewItem不是一個迷你TreeView。這會導致你不得不做大量的來回投射。所以,這裏是我曾嘗試過的:在WPF中,如何以編程方式取消選擇樹視圖中的所有項目?

TreeViewDeselectAll(myTreeView.Items);  

// Must send in ItemCollection to allow the recursive call 
private void TreeViewDeselectAll(ItemCollection myTreeViewItems) 
{ 
    // The only way to get to the IsSelected property is to turn it back into a TreeViewItem 
    foreach (TreeViewItem currentItem in myTreeViewItems) 
    { 
     currentItem.IsSelected = false; 
     if (currentItem.HasItems) 
     { 
      // Recursify! 
      TreeViewDeselectAll(currentItem.Items); 
     } 
    } 
} 

是否有人成功取消選擇TreeView中的所有項目?你甚至能夠以遞歸方式遍歷TreeView嗎?

Winforms TreeView有一個Nodes集合,它實際上是一個小型TreeView。這允許遞歸就好了。但是WPF TreeView沒有節點。

在.Net 4.0中工作。

+1

我也想指出,除非你做了一些特別的事情,TreeView只允許選擇一個項目。 –

+0

@JoelLucsy沒錯。我試着去玩'ItemContainerStyle'只是爲了找出它不可能用'TreeView'。然而,OP肯定需要多次選擇,這可以通過將選擇狀態移動到Model/ViewModel來實現。看到我的答案。 –

回答

1

每個TreeViewItem都是一個Mini-TreeView。你錯誤的印象或者你讀了關於TreeViewItems的錯誤。

你做錯了什麼是傳遞不包含TreeViewItem類型的子類的Items集合,而是那些數據項。

通過兒童收藏,你應該沒問題。

像這樣:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

    } 

    private bool @switch = false; 

    private void TreeViewDeselectAll(IEnumerable myTreeViewItems, bool value) 
    { 
     if (myTreeViewItems != null) 
     { 
      foreach (var currentItem in myTreeViewItems) 
      { 
       if (currentItem is TreeViewItem) 
       { 
        TreeViewItem item = (TreeViewItem)currentItem; 
        item.IsSelected = value; 
        if (item.HasItems) 
        { 
         TreeViewDeselectAll(LogicalTreeHelper.GetChildren(item), value); 
        } 
       } 
      } 
     } 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     this.TreeViewDeselectAll(LogicalTreeHelper.GetChildren(this.treeView), [email protected]); 
    } 
} 

XAML看起來像這樣的例子:

<StackPanel> 
    <TreeView Name="treeView"> 
     <TreeViewItem Header="First Level"> 
      <TreeViewItem Header="Second Level"/> 
     </TreeViewItem> 
    </TreeView> 
    <Button Click="Button_Click">select/unselect all</Button> 
</StackPanel> 

我改變了你的TreeViewDeselectAll方法一點點。基於交換機,您可以選擇或取消全部選擇。

5

好的。刪除所有的代碼並從頭開始。

如果你正在使用WPF,你真的需要拋棄恐龍技術(如winforms)的所有古老做法,並理解並接受The WPF Mentality

在WPF中,您沒有「編程選擇TreeViewItem」,只是因爲UI is Not Data

UI不負責跟蹤您的數據項的選擇狀態,這些數據項顯示在TreeView或任何其他UI元素中。

相反,您將分別創建適當的DataModel和ViewModel來保存數據和應用程序邏輯。

有一個非常有趣的article作者Josh Smith解釋瞭如何處理WPF中的TreeView,正確的方法。

基本上是這樣的:

<Window x:Class="MiscSamples.MVVMTreeViewSample" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MVVMTreeViewSample" Height="300" Width="300"> 
    <DockPanel> 
     <Button Content="Select All" Click="SelectAll" DockPanel.Dock="Top"/> 
     <Button Content="Select None" Click="SelectNone" DockPanel.Dock="Top"/> 

     <TreeView ItemsSource="{Binding}"> 
      <TreeView.ItemTemplate> 
       <HierarchicalDataTemplate ItemsSource="{Binding Children}"> 
        <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DisplayName}"/> 
       </HierarchicalDataTemplate> 
      </TreeView.ItemTemplate> 
     </TreeView> 
    </DockPanel> 
</Window> 

代碼背後:

public partial class MVVMTreeViewSample : Window 
{ 
    private ObservableCollection<HierarchicalData> Data; 

    public MVVMTreeViewSample() 
    { 
     InitializeComponent(); 
     DataContext = Data = CreateData(); 
    } 

    private void Select(IEnumerable<HierarchicalData> items, bool isselected) 
    { 
     while (items.Any()) 
     { 
      items.ToList().ForEach(x => x.IsSelected = isselected); 
      items = items.SelectMany(x => x.Children); 
     } 
    } 

    private void SelectAll(object sender, RoutedEventArgs e) 
    { 
     Select(Data, true); 
    } 

    private void SelectNone(object sender, RoutedEventArgs e) 
    { 
     Select(Data, false); 
    } 

    private ObservableCollection<HierarchicalData> CreateData() 
    { 
     return new ObservableCollection<HierarchicalData> 
     { 
      //... Dummy Data here 
     } 
    } 
} 

數據項:

public class HierarchicalData : System.ComponentModel.INotifyPropertyChanged 
{ 

    public string DisplayName { get; set; } 

    private bool _isSelected; 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      _isSelected = value; 
      OnPropertyChanged("IsSelected"); 
     } 
    } 

    public ObservableCollection<HierarchicalData> Children { get; private set; } 

    public HierarchicalData() 
    { 
     Children = new ObservableCollection<HierarchicalData>(); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

結果:

enter image description here

  • 瞭解如何處理任何UI元素沒有一行代碼。一切都通過DataBinding簡單,簡單的屬性和INotifyPropertyChanged。這就是你在WPF中編程的方式。不需要複雜的東西,不需要由於UI虛擬化等引起的各種問題的複雜操作。
  • SelectAll()SelectNone()方法中,我只是遍歷Data Items而不是UI元素,並相應地設置它們的值。 WPF然後通過DataBinding引擎更新UI。
  • 瞭解如何不需要向任何東西施加任何東西,以及如何使用我自己的簡單類而不是處理複雜的,神祕的WPF對象模型。
  • 忘記winforms。這是一個無用的恐龍,不支持任何東西。
  • WPF Rocks。只需將我的代碼複製並粘貼到File -> New Project -> WPF Application中即可自行查看結果。請注意,您需要在CreateData()方法中將項目添加到集合中。
  • 讓我知道你是否需要進一步的幫助。
+0

好帖子。我喜歡WPF,儘管我認爲數據綁定被許多程序員濫用。許多人編寫的代碼假設數據庫在任何時候都會非常健壯,並且網絡總是可靠的。 –

+0

@ClayAcord我無法理解你的評論。 WPF的DataBinding與數據庫或網絡連接完全沒有關係。 –

+0

我也很擔心微軟現在採取的方向,或者說更缺乏方向。 .NET和WPF將在Windows 9中過時嗎?誰真的知道? 我很高興MS推薦在ASP.NET中使用MVC,以便取出大量的VIEWSTATE。我需要這個房間填補我需要的3或4個JavaScript庫。

相關問題