1

How I can set programmatically Binding "Header" property of newTableList.Items elements to TableModel.TABLE_NAME ?

foreach (SchemaModel schema in connection.schemas)
{ 
 TreeViewItem newSchema = new TreeViewItem() 
 { 
     Header = schema.SCHEMA_NAME.ToString() 
 };
 Binding newTableBinding = new Binding();     
 newTableBinding.Source = schema.tables;

 TreeViewItem newTableList = new TreeViewItem()
 {
      Header = "Tables",
 };

 BindingOperations.SetBinding( newTableList, TreeViewItem.ItemsSourceProperty, newTableBinding);

newSchema.Items.Add(newTableList);
newTVI.Items.Add(newSchema);

}

My old, very slow code looks like that:

foreach (TableModel table in schema.tables)
{
   newTableList.Items.Add(new TreeViewItem()
   {
       Header = table.TABLE_NAME.ToString()
   });
}

OLD TOPIC ( FOR BETTER VIEW )

I try to build custom TreeView and change my "VERY SLOW METHOD" with fastest with Binding to list of custom objects.

I have SchemaModel which contains

List<TableModel> tables

and every TableModel have

string TABLE_NAME.

My previous very slow method Was :

/*  VERY SLOW METHOD !!! */
//foreach (TableModel table in schema.tables)
//{
//    newTableList.Items.Add(new TreeViewItem()
//    {
//        Header = table.TABLE_NAME.ToString()
//    });
//}

Creating each time TreeViewItem is slowing my UI which I cannot repair with multitasking.

I decided to programmatically Bind to list of TableModels like that :

Binding newTableBinding = new Binding();
newTableBinding.Source = schema.tables;

TreeViewItem newTableList = new TreeViewItem()
{
    Header = "Tables",
    // ItemsSource = schema.tables // also works 
};
BindingOperations.SetBinding( newTableList, TreeViewItem.ItemsSourceProperty, newTableBinding);

How Can i Bind the Header property to "TABLE_NAME" for Items based on schema.tables list?

My full code

Code:

foreach (ConnectionModel connection in aliases)
{
    TreeViewItem newTVI = new TreeViewItem() { Header = connection.alias.ToString() };

    foreach (SchemaModel schema in connection.schemas)
    {
        TreeViewItem newSchema = new TreeViewItem() { Header = schema.SCHEMA_NAME.ToString() };

        Binding newTableBinding = new Binding();
        newTableBinding.Source = schema.tables;
        // newTableBinding.Path = new PropertyPath("TABLE_NAME");

        TreeViewItem newTableList = new TreeViewItem()
        {
            Header = "Tables",
            // ItemsSource = schema.tables
        };
        BindingOperations.SetBinding( newTableList, TreeViewItem.ItemsSourceProperty, newTableBinding);

       TreeViewItem newIndexList = new TreeViewItem() { Header = "Indexes" };

      /*  VERY SLOW METHOD !!! */
       //foreach (TableModel table in schema.tables)
       //{
       //    newTableList.Items.Add(new TreeViewItem()
       //    {
       //        Header = table.TABLE_NAME.ToString()
       //    });
       //}

       newSchema.Items.Add(newTableList);
       newSchema.Items.Add(newIndexList);
       newTVI.Items.Add(newSchema);
   }
   tmpAliasTree.Items.Add(newTVI);
}

tmpAliasTree is my TreeView.

My ConnectionModel

[Serializable()]
public class ConnectionModel
{

    private int    _id;

    private string _dsn;
    private string _alias   ;

    private string _host    ;
    private string _port    ;

    private string _database;

    private string _username;
    private string _password;

    public List<SchemaModel> schemas = new List<SchemaModel>();

  }

My SchemaModel :

[Serializable()]
public class SchemaModel
{
    [System.Xml.Serialization.XmlElement("SCHEMA_NAME")]
    public string SCHEMA_NAME { get; set; } = "";

    [XmlArray("tables"), XmlArrayItem("TableModel", typeof(TableModel), ElementName = "TableModel")]
    public List<TableModel> tables = new List<TableModel>();

}

My TableModel

[Serializable()]
public class TableModel
{
    [System.Xml.Serialization.XmlElement("TABLE_CAT")]
    public string TABLE_CAT     { get; set; }  = "";
    [System.Xml.Serialization.XmlElement("TABLE_SCHEM")]
    public string TABLE_SCHEM   { get; set; }  = "";
    [System.Xml.Serialization.XmlElement("TABLE_NAME")]
    public string TABLE_NAME    { get; set; }  = "";
    [System.Xml.Serialization.XmlElement("TABLE_TYPE")]
    public string TABLE_TYPE    { get; set; }  = "";
    [System.Xml.Serialization.XmlElement("REMARKS")]
    public string REMARKS       { get; set; } = "";
}

Thank You for any advise.

Wiktor
  • 754
  • 1
  • 7
  • 24
  • Your model isn't so bad, but your models should [implement INotifyPropertyChanged](http://stackoverflow.com/a/1316417/424129) and they should use ObservableCollection for children instead of List. Delete all your TreeView code from your codebehind, and do that part with Bindings and templates in XAML instead. This should help you get started on the XAML part: http://stackoverflow.com/questions/5894650/wpf-hierarchicaldatatemplate-treeview?rq=1 – 15ee8f99-57ff-4f92-890c-b56153 Jan 08 '16 at 14:23
  • @Ed Plunkett : Why I should to use ObservableCollection? – Wiktor Jan 08 '16 at 15:10
  • 1
    Because when you add or remove an item in an `ObservableCollection`, it notifies the XAML control. A List doesn't do that. That's the same reason you implement `INotifyPropertyChanged`, to notify the XAML when property values change. – 15ee8f99-57ff-4f92-890c-b56153 Jan 08 '16 at 15:10

1 Answers1

0

Although I agree that you should consider moving your view definition to XAML, you can achieve what you're asking by utilizing ItemsControl.ItemContainerStyle property (both TreeView and TreeViewItem derive from ItemsControl). Basically, you need to define a style targeting TreeViewItem and add a setter for TreeViewItem.HeaderProperty with value holding an appropriate binding, and then assign that style either to your tree view, or particular items (depending on your needs). Here's an example:

TreeViewItem newTVI = new TreeViewItem() { Header = connection.alias.ToString() };
var tableModelItemStyle = new Style(typeof(TreeViewItem));
tableModelItemStyle.Setters.Add(new Setter
{
    Property = TreeViewItem.HeaderProperty,
    //since items will present instances of TableModel, the DataContext will hold
    //the model, so we can define the binding using only the property name
    Value = new Binding("TABLE_NAME"),
});
foreach(...)
{
    ...
    TreeViewItem newTableList = new TreeViewItem
    {
        ...
        ItemContainerStyle = tableModelItemStyle,
    };
    ...
}

If you want to set the style for all items in the tree view (which I do not recommend), you can do it like so:

newTVI.ItemContainerStyle = tableModelItemStyle;
Grx70
  • 10,041
  • 1
  • 40
  • 55