locked
Data Binding to a data type that inherits from TreeViewItem RRS feed

  • Question

  • I have a TreeView that is binded to a data type called "File". Everything works fine until I make the "File" data type inherit from "TreeViewItem".

    Working example:

    Data Type:

    public class File
        {
            public string FileName { get; set; }
            public string IconSource { get; set; }
            public ObservableCollection<File> Items { get; set; }
            public File()
            {
                Items = new ObservableCollection<File>();
            }
    
            public File(string name) : this()
            {
                FileName = name;
                this.IconSource = "/GameMaker;component/Resources/Icons/File.ico";
            }
        }

    C# Code:

    public MainWindow()
            {
                InitializeComponent();
    
                List<File> FileTree = new List<File>();
                Folder objFolder = new Folder("Objects"),
                                spriteFolder = new Folder("Sprites"),
                                scenesFolder = new Folder("Scenes");
    
                File object0 = new File("object0"),
                                object1 = new File("object1"),
                                object2 = new File("object2");
    
                objFolder.Items.Add(object0);
                objFolder.Items.Add(object1);
                objFolder.Items.Add(object2);
    
                FileTree.Add(objFolder);
                FileTree.Add(spriteFolder);
                FileTree.Add(scenesFolder);
    
                fileViewer.ItemsSource = FileTree;
                
            }

    XAML:

    <Window x:Class="GameMaker.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:GameMaker"
            mc:Ignorable="d"
            Title="LurkaEngine" Height="350" Width="525">
        <Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary 
                      Source="Resources/ResourceDictionary.xaml">
                    </ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Window.Resources>
        
        <Grid>
            
            <TreeView x:Name="fileViewer" Height="281" VerticalAlignment="Top" Margin="0,18,0,0" >
    
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource="{Binding Path=Items}">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=IconSource}" />
                            <TextBlock Text="{Binding Path=FileName}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
    
            </TreeView>
    </Window>
    

    This example works perfectly. The treeview displays like an explorer that shows folders and files with name and icons.

    Changes made to the Data Type:

    public class File : TreeViewItem
        {
            public string FileName { get; set; }
            public string IconSource { get; set; }
            //public ObservableCollection<File> Items { get; set; }
            public File()
            {
                //Items = new ObservableCollection<File>();
            }
    
            public File(string name) : this()
            {
                FileName = name;
                this.IconSource = "/GameMaker;component/Resources/Icons/File.ico";
            }
        }

    Result: THe icons and header of the file disappear (actually I see nothing but the triangle that expends the "Objects" folder.)

    I can't add images for some reason.

    * NOTE: the "FOLDER" data type inherits from the "FILE" data type.

    What should I do?

    The reason I want the data type to inherit from "TreeViewItem" is so I can add some event handlers to the "File" objects.

    Saturday, November 5, 2016 12:13 PM

Answers

  • >>What should I do?

    Don't inherit from TreeViewItem.

    1. A data object like your File type should not inherit from a visual container type like TreeViewItem.
    2. The ItemTemplate of a TreeView won't be applied to elements of type TreeViewItem so this won't work.

    >>The reason I want the data type to inherit from "TreeViewItem" is so I can add some event handlers to the "File" objects.

    Then you should define new events in the Data class yourself. Please refer to MSDN for more information on how to do this.

    How to: Raise and Consume Events:...

    Or you could handle any event of the TreeViewItem container that gets created automatically as a wrapper around your ItemTemplate by defining an ItemContainerStyle, e.g.:

    <TreeView x:Name="fileViewer" Height="281" VerticalAlignment="Top" Margin="0,18,0,0" >
                <TreeView.ItemContainerStyle>
                    <Style TargetType="TreeViewItem">
                        <EventSetter Event="Loaded" Handler="OnLoaded" />
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource="{Binding Path=Items}">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=IconSource}" />
                            <TextBlock Text="{Binding Path=FileName}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
    private void OnLoaded(object sender, RoutedEventArgs e)
            {
                //....
            }
    But the data object type should not inherit from the TreeViewItem container type.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Thanks for your answer. I received the desired result by setting an event like you did and getting the File object from the Sender like so:

            private void ExplorerItemDoubleClick(object sender, EventArgs e)
            {
                Console.WriteLine((((TreeViewItem)sender).Header as GameMaker.File).FileName);
            }


    • Edited by Toalp Tuesday, November 15, 2016 9:36 AM
    • Marked as answer by Toalp Tuesday, November 15, 2016 9:36 AM
    Tuesday, November 15, 2016 9:22 AM

All replies


  • Hi  Toalp,

    >>The reason I want the data type to inherit from "TreeViewItem" is so I can add some event handlers to the "File" objects.

    You can try to implement the INotifyPropertyChanged interface to add event handling. You can refer the following link.

    TreeView - Selection/Expansion state:
    http://www.wpf-tutorial.com/treeview-control/handling-selection-expansion-state/

    I think that probably what we will need to do is create a custom control that subclasses TreeViewItem and add a couple of dependency properties that the parent class doesn't provide.

    TreeViewItem: Implements a selectable item in a TreeView control
    https://msdn.microsoft.com/en-us/library/system.windows.controls.treeviewitem%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    TreeViewItem Events:
    https://msdn.microsoft.com/en-us/library/system.windows.controls.treeviewitem_events.aspx

    You can upload a sample project that can be compiled and run on any computer to OneDrive and post the link to it here. It will help anyone to be able to point out why you get an exception somewhere in your code.

    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.

    Best Regards,

    Yohann Lu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, November 7, 2016 6:27 AM
  • >>What should I do?

    Don't inherit from TreeViewItem.

    1. A data object like your File type should not inherit from a visual container type like TreeViewItem.
    2. The ItemTemplate of a TreeView won't be applied to elements of type TreeViewItem so this won't work.

    >>The reason I want the data type to inherit from "TreeViewItem" is so I can add some event handlers to the "File" objects.

    Then you should define new events in the Data class yourself. Please refer to MSDN for more information on how to do this.

    How to: Raise and Consume Events: https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx

    Or you could handle any event of the TreeViewItem container that gets created automatically as a wrapper around your ItemTemplate by defining an ItemContainerStyle, e.g.:

    <TreeView x:Name="fileViewer" Height="281" VerticalAlignment="Top" Margin="0,18,0,0" >
                <TreeView.ItemContainerStyle>
                    <Style TargetType="TreeViewItem">
                        <EventSetter Event="Loaded" Handler="OnLoaded" />
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource="{Binding Path=Items}">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=IconSource}" />
                            <TextBlock Text="{Binding Path=FileName}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
    private void OnLoaded(object sender, RoutedEventArgs e)
            {
                //....
            }
    But the data object type should not inherit from the TreeViewItem container type.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Tuesday, November 8, 2016 6:28 AM
  • >>What should I do?

    Don't inherit from TreeViewItem.

    1. A data object like your File type should not inherit from a visual container type like TreeViewItem.
    2. The ItemTemplate of a TreeView won't be applied to elements of type TreeViewItem so this won't work.

    >>The reason I want the data type to inherit from "TreeViewItem" is so I can add some event handlers to the "File" objects.

    Then you should define new events in the Data class yourself. Please refer to MSDN for more information on how to do this.

    How to: Raise and Consume Events:...

    Or you could handle any event of the TreeViewItem container that gets created automatically as a wrapper around your ItemTemplate by defining an ItemContainerStyle, e.g.:

    <TreeView x:Name="fileViewer" Height="281" VerticalAlignment="Top" Margin="0,18,0,0" >
                <TreeView.ItemContainerStyle>
                    <Style TargetType="TreeViewItem">
                        <EventSetter Event="Loaded" Handler="OnLoaded" />
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource="{Binding Path=Items}">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=IconSource}" />
                            <TextBlock Text="{Binding Path=FileName}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
    private void OnLoaded(object sender, RoutedEventArgs e)
            {
                //....
            }
    But the data object type should not inherit from the TreeViewItem container type.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Thanks for your answer. I received the desired result by setting an event like you did and getting the File object from the Sender like so:

            private void ExplorerItemDoubleClick(object sender, EventArgs e)
            {
                Console.WriteLine((((TreeViewItem)sender).Header as GameMaker.File).FileName);
            }


    • Edited by Toalp Tuesday, November 15, 2016 9:36 AM
    • Marked as answer by Toalp Tuesday, November 15, 2016 9:36 AM
    Tuesday, November 15, 2016 9:22 AM
  • I am glad it worked for you but please remember to mark the post that provided a solution to your issue as answer.

    Thanks in advance.

    Tuesday, November 15, 2016 5:30 PM