当child-items是同一个对象时,在treeview中获取parent-note

时间:2013-12-22 23:25:01

标签: c# wpf silverlight xaml treeview

我在xaml createt TreeViewItems中有一个相同的TreeView。并且一个注释将ObservableCollection作为ItemSource。这就像一个魅力。但是现在我想要列表中的每个项目使用相同的Notes(以便更好地组织)。所以我这样做:

这是我的HierarchicalDataTemplate for liste

<HierarchicalDataTemplate DataType="{x:Type classes:Connection}" ItemsSource="{Binding Source={StaticResource ConnectionChilds}}" >
    <TextBlock Text="{Binding DisplayName}" />
</HierarchicalDataTemplate>

还有ItemsSource:

<collections:ArrayList x:Key="ConnectionChilds">
    <classes:TreeItemObject ItemsSourcePath="Child1" />
    <classes:TreeItemObject ItemsSourcePath="Child2" />
    <classes:TreeItemObject ItemsSourcePath="Child3" />
</collections:ArrayList>

TreeItemObject是一个简单的类:

public class TreeItemObject
{
    public string ItemsSourcePath { get; set; }
}

最后但并非最不重要的是TreeItemObject的HierarchicalDataTemplate:

<DataTemplate DataType="{x:Type classes:TreeItemObject}">
    <TextBlock Margin="5,0" Text="{Binding Path=ItemsSourcePath}"/>
</DataTemplate>

看起来像这样

Connection 1
    Child1
    Child2
    Child3
Connection 2
    Child1
    Child2
    Child3
Connection 3
    Child1
    Child2
    Child3

作品perfekt。但现在如果我选择&#34;连接2 \ Child3&#34;我得到了像#34; Connection 1 \ Child3&#34;或&#34;连接3 \ Child3&#34;。好的,因为基于相同的对象。在这种情况下,我没有机会找到关于OnSelectedItemChanged的父笔记。

因为如果我使用此扩展程序类进行搜索。我只获得了第一个扩展的连接注释。

http://social.msdn.microsoft.com/Forums/silverlight/en-US/84cd3a27-6b17-48e6-8f8a-e5737601fdac/treeviewitemcontainergeneratorcontainerfromitem-returns-null?forum=silverlightnet

有没有办法在TreeView中找到真正的父级?

3 个答案:

答案 0 :(得分:0)

我认为您唯一的选择是在将子项添加到TreeView之前克隆您的子项,至少允许子节点之间存在二进制差异。

如果这样做,不是处理OnSelectedItemChanged事件并遍历对象图,而是向其每个子项添加父项的WeakReference。这将允许您立即引用子项中的父项,并允许.Net正确清理对象图。

使用SelectedItemChanged事件处理程序中的WeakReference属性的示例如下

private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    var treeView = sender as TreeView;
    var item = treeView.SelectedItem as TreeItemObject;
    if (item.Parent.IsAlive)
    {
        var parent = item.Parent.Target;
    }
}

为简洁起见,我删除了异常管理和空检查。

我希望这会有所帮助。

答案 1 :(得分:0)

我个人不喜欢在转换器中创建克隆的想法,但我不知道问题的全部范围。因此,使用您在此处提供的内容,我们可以通过MultiValueConverter实现为每个TreeItemObject分配父级。

WPF有一个名为MultiBinding的强大功能。它将1个或多个源值处理为单个目标。为此,它需要一个多值转换器。

因此,将TreeItemObject更改为

public class TreeItemObject
{
    public string ItemsSourcePath { get; set; }
    public WeakReference Parent { get; set; }
}

Connection类型的hierarchicalDataTemplate将变为

<HierarchicalDataTemplate DataType="{x:Type classes:Connection}">
    <HierarchicalDataTemplate.ItemsSource>
        <MultiBinding Converter="{StaticResource items2Clones}">
            <Binding Source="{StaticResource ConnectionChilds}" />
            <Binding />
        </MultiBinding>
    </HierarchicalDataTemplate.ItemsSource>
    <TextBlock Text="{Binding DisplayName}" />
</HierarchicalDataTemplate>

根据上面的绑定,要在转换器中设置父级,转换中的Convert方法将沿着这些行

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    var destinationItems = new Collection<TreeItemObject>();

    var items = values[0] as Collection<TreeItemObject>;
    var parent = values[1] as Connection;

    // null checks are required here for items and parent

    foreach (var item in items)
    {
        var destinationItem = item.Clone(); // Assumed extension method
        destinationItem.Parent = new WeakReference(parent);
        destinationItems.Add(destinationItem);
    }

    return destinationItems;
}

最后,SelectedItemChanged事件处理程序将类似于

private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    var item = (TreeItemObject)e.NewValue;
    if ((item != null) && (item.Parent != null) && (item.Parent.IsAlive))
    {
        // do stuff - Console.WriteLine(((Connection)item.Parent.Target).DisplayName);
    }
}

为了简洁,我删除了异常管理和一些空检查。

我希望这会有所帮助

答案 2 :(得分:0)

很难从treeView项中获取父项,所以我所做的是,我有一个父类型父项的成员属性,它保存对父项的引用,如下所示

public class FileSystem :NotifyChange, IEnumerable
{
#region Private members
private ObservableCollection<FileSystem> subDirectoriesField;
#endregion

#region Public properties
/// <summary>
/// Gets and sets all the Files in the current folder
/// </summary>
public ObservableCollection<FileSystem> SubDirectories
{
    get
    {
        return subDirectoriesField;
    }
    set
    {
        if (subDirectoriesField != value)
        {
            subDirectoriesField = value;
            RaisePropertyChanged("SubDirectories");
        }
    }
}
/// <summary>
/// Gets or sets name of the file system 
/// </summary>
public string Name
{
    get;
    set;
}
/// <summary>
/// Gets or sets full path of the file system
/// </summary>
public string FullPath
{
    get;
    set;
}
/// <summary>
/// object of parent, null if the current node is root
/// </summary>
public FileSystem Parent
{
    get;
    set;
}
public FileSystem(string fullPath, FileSystem parent)
{
    Name = fullPath != null ? fullPath.Split(new char[] { System.IO.Path.DirectorySeparatorChar },
        StringSplitOptions.RemoveEmptyEntries).Last()
    FullPath = fullPath;
    Parent = parent;
    AddSubDirectories(fullPath);
}

public IEnumerator GetEnumerator()
{
    return SubDirectories.GetEnumerator();
}

private void AddSubDirectories(string fullPath)
{
    string[] subDirectories = Directory.GetDirectories(fullPath);
    SubDirectories = new ObservableCollection<FileSystem>();
    foreach (string directory in subDirectories)
    {
        SubDirectories.Add(new FileSystem(directory, this));
    }
}
}

我的viewModel如下所示

public class ViewModel:NotifyChange
{
  private ObservableCollection<FileSystem> directories;
  public ObservableCollection<FileSystem> Directories
  {
    get
    {
        return directoriesField;
    }
    set
    {
        directoriesField = value;
        RaisePropertyChanged("Directories");
    }
  }
  public ViewModel()
  {
   //The below code has to be moved to thread for better user expericen since when UI is loaded it might not respond for some time since it is looping through all the drives and it;s directories
   Directories=new  ObservableCollection<FileSystem>();
   Directories.Add(new FileSystem("C:\\", null);
   Directories.Add(new FileSystem("D:\\", null);
   Directories.Add(new FileSystem("E:\\", null);
  }
}

由于每个孩子都知道它;现在你可以遍历s父节点,root节点parent将为null

Xmal将有以下

 <TreeView Grid.Row="1" Background="Transparent" ItemsSource="{Binding Directories}" Margin="0,10,0,0" Name="FolderListTreeView"
            Height="Auto" HorizontalAlignment="Stretch" Width="300"  >
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:FileSystem}" ItemsSource="{Binding SubDirectories}">
                    <Label Content="{Binding Path= Name}" Name="NodeLabel" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>

希望这有助于你