2013-02-12 83 views
0

我想寫一個多選擇treeview行爲,但是這樣做時,我得到這個神祕的錯誤「項目集合必須爲空之前使用ItemsSource。」WPF附加行爲錯誤|項目集合必須爲空之前使用ItemsSource

以下是我的XAML代碼:

<Window x:Class="TreeView.Spike.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Spike="clr-namespace:TreeView.Spike" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
    </Window.Resources> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width=".5*"/> 
      <ColumnDefinition Width=".5*"/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*"></RowDefinition> 
      <RowDefinition Height="40"></RowDefinition> 
     </Grid.RowDefinitions> 

     <TreeView ItemsSource="{Binding Nodes}" Grid.Row="0" x:Name="treeView" Grid.Column="0"> 
      <TreeView.ItemTemplate> 
       <HierarchicalDataTemplate ItemsSource="{Binding Nodes}"> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding Name}">     
        </TextBlock> 
        </StackPanel> 
       </HierarchicalDataTemplate> 
      </TreeView.ItemTemplate> 
      <TreeView.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Add"></MenuItem> 
        <MenuItem Header="Delete"></MenuItem> 
       </ContextMenu> 
      </TreeView.ContextMenu> 
      <Spike:MultipleItemSelectionAttachedBehavior AllSelectedItems="{Binding Path=AllSelectedNodes}"/> 
     </TreeView> 

    </Grid> 
</Window> 

我的附加行爲:

public class MultipleItemSelectionAttachedBehavior:Behavior<System.Windows.Controls.TreeView> 
    { 
     public static DependencyProperty AllSelectedItemsProperty = 
     DependencyProperty.RegisterAttached("AllSelectedItems", typeof(object), typeof(MultipleItemSelectionAttachedBehavior), 
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Inherits)); 

     private static readonly PropertyInfo IsSelectionChangeActiveProperty = typeof(System.Windows.Controls.TreeView).GetProperty("IsSelectionChangeActive", 
      BindingFlags.NonPublic | BindingFlags.Instance); 

     public object AllSelectedItems 
     { 
      get 
      { 
       return (object)GetValue(AllSelectedItemsProperty); 
      } 
      set 
      { 
       SetValue(AllSelectedItemsProperty, value); 
      } 
     } 

     public static bool GetAllSelectedItems(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(AllSelectedItemsProperty); 
     } 

     public static void SetAllSelectedItems(DependencyObject obj, bool value) 
     { 
      obj.SetValue(AllSelectedItemsProperty, value); 
     } 

     protected override void OnAttached() 
     { 
      base.OnAttached(); 
      AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged; 
     } 

     protected override void OnDetaching() 
     { 
      base.OnDetaching(); 
      AssociatedObject.SelectedItemChanged -= AssociatedObject_SelectedItemChanged; 
     } 

     void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) 
     { 
      if (IsSelectionChangeActiveProperty == null) return; 

      var selectedItems = new List<Node>(); 

      var treeViewItem = AssociatedObject.SelectedItem as Node; 
      if (treeViewItem == null) return; 

      // allow multiple selection 
      // when control key is pressed 
      if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) 
      { 
       var isSelectionChangeActive = IsSelectionChangeActiveProperty.GetValue(AssociatedObject, null); 

       IsSelectionChangeActiveProperty.SetValue(AssociatedObject, true, null); 
       selectedItems.ForEach(item => item.IsSelected = true); 

       IsSelectionChangeActiveProperty.SetValue(AssociatedObject, isSelectionChangeActive, null); 
      } 
      else 
      { 
       // deselect all selected items except the current one 
       selectedItems.ForEach(item => item.IsSelected = (item == treeViewItem)); 
       selectedItems.Clear(); 
      } 

      if (!selectedItems.Contains(treeViewItem)) 
      { 
       selectedItems.Add(treeViewItem); 
      } 
      else 
      { 
       // deselect if already selected 
       treeViewItem.IsSelected = false; 
       selectedItems.Remove(treeViewItem); 
      } 

      AllSelectedItems = selectedItems; 
     } 
    } 

..和我的ViewModel

public class ViewModel :NotificationObject 
    { 
     public ViewModel() 
     { 
      AllSelectedNodes = new ObservableCollection<Node>(); 
     } 
private ObservableCollection<Node> _allSelectedNodes; 
     public ObservableCollection<Node> AllSelectedNodes 
     { 
      get { return _allSelectedNodes; } 
      set 
      { 
       _allSelectedNodes = value; 
       RaisePropertyChanged(() => AllSelectedNodes); 
      } 
     } 
} 

我的模型:

public class Node:NotificationObject 
    { 

     private string _name; 
     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       _name = value; 
       RaisePropertyChanged(() => Name); 
      } 
     } 




     private bool _isExpanded = true; 
     public bool IsExpanded 
     { 
      get { return _isExpanded; } 
      set 
      { 
       _isExpanded = value; 
       RaisePropertyChanged(() => IsExpanded); 
      } 
     } 

     private bool _isSelected; 

     public bool IsSelected 
     { 
      get { return _isSelected; } 
      set 
      { 
       _isSelected = value; 
       RaisePropertyChanged(() => IsSelected); 

      } 
     } 

     private ObservableCollection<Node> _nodes; 
     public ObservableCollection<Node> Nodes 
     { 
      get { return _nodes; } 
      set 
      { 
       _nodes = value; 
       RaisePropertyChanged(() => Nodes); 
      } 
     } 

     public static IList<Node> Create() 
     { 
      return new List<Node>() 
         { 
          new Node() 
           { 
            Name = "Activity", 
            Nodes = new ObservableCollection<Node>() 
               { 
                new Node() {Name = "Company",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Company1",Existing = false}}}, 
                new Node() {Name = "Strategy",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Strategy1"}}}, 
                 new Node() {Name = "Vehicle",Nodes = new ObservableCollection<Node>(){ new Node() {Name = "Vehicle1",Existing = false}}} 
               } 
           } 
         }; 
     } 
    } 

..和我的初始化clode:

public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      var viewModel = new ViewModel(); 
      this.DataContext = viewModel; 
      viewModel.Nodes = new ObservableCollection<Node>(Node.Create()); 

     } 
} 

我不知道是怎麼回事錯在這裏,你可以請幫助?

回答

3

你缺少<i:Interaction.Behaviors>元素:

取代:

<Spike:MultipleItemSelectionAttachedBehavior AllSelectedItems="{Binding Path=AllSelectedNodes}"/>

爲:

<i:Interaction.Behaviors> 
    <Spike:MultipleItemSelectionAttachedBehavior AllSelectedItems="{Binding Path=AllSelectedNodes}"/> 
</i:Interaction.Behaviors> 

的問題是,對於TreeView控件默認的內容屬性是它的Items屬性,因此將該行爲的XAML元素放在TreeView元素內而不指定<i:Interaction.Behaviors>附加屬性告訴WPF,您希望將您的行爲作爲TreeView中的一個項目,因此當試圖設置其ItemsSource屬性時,您會收到錯誤,因爲其中已有一個Item。

+0

+1該死的你更快:) – dowhilefor 2013-02-12 16:13:39

相關問題