ImageGetter cambio immagini DataTreeListView

di il
11 risposte

ImageGetter cambio immagini DataTreeListView

Ciao a tutti,

   nell'esempio sotto la procedura imagegetter modifica l'immagine della radice dell'albero con un semplice + se il nodo ha un figlio. Vorrei poter accedere all'oggetto row in modo da modificare l'immagine scelta all'interno della raccolta imagelist a seconda se il nodo ha oppure no il figlio ed eventualmente inserire una immagine diversa anche nel figlio. Esempio questo:

Alcune soluzioni indicano di utilizzare un cast ma non saprei come implementarlo. 

Grazie in anticipo per i vostri suggerimenti.

namespace ObjectListViewDemo
{
    public partial class TabDataTreeListView : OlvDemoTab {

        public TabDataTreeListView()
        {
            InitializeComponent();
            this.ListView = this.olvDataTree;
        }

        protected override void InitializeTab() {

            // The whole point of a DataTreeListView is to write no code. So there is very little code here.

            // Put some images against each row
            this.olvColumn41.ImageGetter = delegate(object row) { return "user"; };

            // The DataTreeListView needs to know the key that identifies root level objects.
            // DataTreeListView can handle that key being any data type, but the Designer only deals in strings.
            // Since we want a non-string value to identify keys, we have to set it explicitly here.
            this.olvDataTree.RootKeyValue = 0u;

            // Finally load the data into the UI
            LoadXmlIntoTreeDataListView();

            // This does a better job of auto sizing the columns
            this.olvDataTree.AutoResizeColumns();
        }

        private void LoadXmlIntoTreeDataListView() {
            DataSet ds = Coordinator.LoadDatasetFromXml(@"Data\FamilyTree.xml");

            if (ds.Tables.Count <= 0) {
                Coordinator.ShowMessage(@"Failed to load data set from Data\FamilyTree.xml");
                return;
            }

            this.dataGridView2.DataSource = ds;
            this.dataGridView2.DataMember = "Person";

            // Like DataListView, the DataTreeListView can handle binding to a variety of sources
            // And again, you could create a BindingSource in the designer, and assign that BindingSource
            // to DataSource, removing the need to even write these few lines of code.

            //this.olvDataTree.DataSource = new BindingSource(ds, "Person");
            //this.olvDataTree.DataSource = ds.Tables["Person"];
            //this.olvDataTree.DataSource = new DataView(ds.Tables["Person"]);
            //this.olvDataTree.DataMember = "Person"; this.olvDataTree.DataSource = ds;
            this.olvDataTree.DataMember = "Person";
            this.olvDataTree.DataSource = new DataViewManager(ds);
        }

        #region UI event handlers

        private void filterTextBox_TextChanged(object sender, EventArgs e)
        {
            Coordinator.TimedFilter(this.ListView, ((TextBox)sender).Text);
        }

        private void buttonResetData_Click(object sender, EventArgs e)
        {
            LoadXmlIntoTreeDataListView();
        }

        #endregion
    }
}

11 Risposte

  • Re: ImageGetter cambio immagini DataTreeListView

    Ciao,

    prova ad usare la GetChildren() per ottenere la lista dei figli se sono presenti oppure no.

    if (this.olvDataTree.GetChildren(row).Count > 0)

    :
    Fare attenzione se carichi i nodi della datatree con il metodo Lazy 

  • Re: ImageGetter cambio immagini DataTreeListView

    Grazie By65Franco, sicuramente la tua riga di codice mi servirà come controllo.

    ieri sera prima di andare a letto mi è venuta una idea :-) . Provata questa mattina e sembra funzionare. Da ottimizzare naturalmente.

    this.olvDataTree.AllColumns[0].ImageGetter = delegate (object row) 
    { 
        DataRowView ds = (DataRowView)row;
        DataRow r= ds.Row;
        object x = r.ItemArray[1];
        string h = x.ToString();
        if (h == "0") { 
            return 1;  
        }
        else
        {
            return 0;
        }
    };
  • Re: ImageGetter cambio immagini DataTreeListView

    15/05/2025 - KronS ha scritto:

    ieri sera prima di andare a letto mi è venuta una idea :

    Ciao,

    prova a semplificare e vai di lambata ;-)    ...dovrebbe funzionare, fai test.

    this.olvDataTree.AllColumns[0].ImageGetter = row =>
    {
        var r = ((DataRowView)row).Row;
        return r[1].ToString() == "0" ? 1 : 0;
    };

    Evita array e variabili, risulta più leggero e performante

  • Re: ImageGetter cambio immagini DataTreeListView

    15/05/2025 - By65Franco ha scritto:

    prova a semplificare e vai di lambata ;-)    ...dovrebbe funzionare, fai test.

    this.olvDataTree.AllColumns[0].ImageGetter = row =>
    {
        var r = ((DataRowView)row).Row;
        return r[1].ToString() == "0" ? 1 : 0;
    };

    Questa mi è piaciuta!

    Provata e funziona correttamente. Grazie.

  • Re: ImageGetter cambio immagini DataTreeListView

    Domanda se posso... solo per capire meglio.

    tu vuoi ottenere un effetto di questo tipo ?

    dove nei nodi di tipo Folder l'immagine della cartella si Apre e si Chiude secondo se hai espanso o meno il ramo della TreeView ?

  • Re: ImageGetter cambio immagini DataTreeListView

    Questo sarebbe il top. 

    Mi sono autolimitato a inserire una immagine diversa a seconda se la riga è un nodo padre o è un nodo figlio. Quindi l'immagine rimane la stessa sia espansa che no.

    Almeno per ora.

  • Re: ImageGetter cambio immagini DataTreeListView

    15/05/2025 - KronS ha scritto:

    Mi sono autolimitato a inserire una immagine diversa a seconda se la riga è un nodo padre o è un nodo figlio. Quindi l'immagine rimane la stessa sia espansa che no

    Ora ho capito meglio il tuo intento...

    Che dire, le tecniche possono essere diverse.
    Personalmente cerco sempre di semplificare e alleggerire il codice quanto più possibile.

    Nell'esempio postato in precedenza, mi sono fermato a 3 immagini. Due immagini per la Folder chiusa e aperta e Un immagine per i Files.
    Si potrebbe anche utilizzare un immagine diversa sulla base del tipo di file.... Ma in questo caso specifico non ho ritenuto opportuno appesantire il tutto in quanto non sarebbe risultata un esperienza utile per l'utente.
    Comunque tutto dipende dagli scenari e, si possono fare diverse cose.

    Considerando che attualmente la TreeView contiene più di 33.000 Files e più di 1.600 Cartelle ed è destinata a crescere, ho utilizzato il "metodo Lazy".
    Questo metodo consente di avere una visualizzazione e navigazione praticamente istantanea e molto fluida. (tempi di attesa di caricamento praticamente pari a zero)

    Se vuoi posso farti vedere come ho approcciato questa TreeView per i file di Backup....

    • Lo scopo è quello di visualizzare un elenco di Cartelle e Files che ho mappato in un percorso di rete con la root U:\
      • si possono avere una o più Radici. In questo caso ne vediamo una sola.
      • si visualizzano tutte le cartelle e i files che vengono salvati come backup. E' previsto di :
        • visualizzare i singoli files, le Proprietà e il loro Contenuto
          • per visualizzare il contenuto dei files, viene utilizzata la funzione classica di Windows "Apri con" dove si sceglie con quale applicazione aprire il file
        • scaricare il file. Selezionado il file con una Open Dialog "Save As" si può decidere di copiare il file di Backup in una cartella a proprio piacimento

    :
    Caricamento della Treeview:

    1. Caricamento dell'immagini   -  Folder Chiusa  -  Folder Aperta  -  File (document image) 

                  // Set image list for treeview
                  ImageList imageListTree = new ImageList();
                  imageListTree.Images.Add("folder", Properties.Resources.DataTreeFolder);
                  imageListTree.Images.Add("file", Properties.Resources.DataTreeDocument);
                  imageListTree.Images.Add("folder_open", Properties.Resources.DataTreeFolderOpen);
                  this.TreeViewBackup.ImageList = imageListTree;
      
    2. Caricamento delle solo Radici... Da una tabella del database si prende la Radice o le Radici che saranno caricate nella TreeView. 
      Con queste radici si imposta la e/o le Root (primo livello) della TreeView:

              // LOAD ROOT BACKUP FOLDER AND LOAD TREEVIEW LAZY METHOD
              private void MyGetRootFolderPair()
              {
                  // Clear treeview
                  this.TreeViewBackup.Nodes.Clear();
      
                  // Set connection database string and open 
                  using (SqlConnection connection = new SqlConnection(ClassSetup.cnnString))
                  {
                      connection.Open();
      
                      // Read pairing table
                      using (SqlCommand command = new SqlCommand("SELECT DISTINCT PairFolderBackup FROM TblFolderPair;", connection))
                      {
                          using (SqlDataReader reader = command.ExecuteReader())
                          {
                              while (reader.Read())
                              {
                                  // Get root pair backup and load treeview
                                  string stringRoot = reader.GetString(reader.GetOrdinal("PairFolderBackup"));
                                  // Add root node with image and tag
                                  TreeNode rootNode = new TreeNode(stringRoot)
                                  {
                                      Tag = stringRoot,
                                      ImageKey = "folder_open",
                                      SelectedImageKey = "folder_open"
                                  };
                                  this.TreeViewBackup.Nodes.Add(rootNode);
      
                                  // Load folders, subfolders and files - Lazy Method 
                                  MyLoadSubDirectoriesLazy(rootNode, stringRoot);
                              }
                          }
                      }
                  }
              }
      
    3. Inizializzazione/Caricamento TreeView con il primo livello Radici Padri Figli

              // LOAD TREEVIEW - LAZY METHOD THAT ADDS ONLY THE FIRST-LEVEL DIRECTORIEW AND FILE
              private void MyLoadSubDirectoriesLazy(TreeNode parentNode, string path)
              {
                  try
                  {
                      // Adds all the first-level directories
                      foreach (var directory in Directory.GetDirectories(path))
                      {
                          // Add root node with image and tag
                          TreeNode folderNode = new TreeNode(Path.GetFileName(directory))
                          {
                              Tag = directory,
                              ImageKey = "folder",
                              SelectedImageKey = "folder"
                          };
                          folderNode.Nodes.Add("Loading...");
                          parentNode.Nodes.Add(folderNode);
                      }
                      // Adds all files in the folder
                      foreach (var file in Directory.GetFiles(path))
                      {
                          // Add root node with image and tag
                          TreeNode fileNode = new TreeNode(Path.GetFileName(file))
                          {
                              Tag = file,
                              ImageKey = "file",
                              SelectedImageKey = "file"
                          };
                          parentNode.Nodes.Add(fileNode);
                      }
                  }
                  catch (UnauthorizedAccessException)
                  {
                      // Set access denied
                      parentNode.Nodes.Add(new TreeNode("[Access denied]"));
                  }
              }
      
    4. Caricamento "Lazy" per tutti gli altri nodi padri e figli  -  metodo ricorsivo per caricare cartelle e file ad ogni richiesta di espansione dei nodi

              // TREEVIEW EXPAND FIRST LEVEL - RECORSIVE METHOD
              private void MyExpandFirstLevels(TreeNodeCollection nodes, int currentLevel, int maxLevel)
              {
                  if (currentLevel > maxLevel) { return; }
                  foreach (TreeNode node in nodes)
                  {
                      node.Expand();
                      if (node.Nodes.Count > 0) { MyExpandFirstLevels(node.Nodes, currentLevel + 1, maxLevel); }
                  }
              }
      
    5. Espansione Nodi - Si sfruttano i due eventi "BeforeExpand" e "BeforeCollapse"
      All'apertura e chiusura dei Nodi si "cambiano le immagini" 

              // TREEVIEW - LOAD WITH LAZY METHOD - EVENT THAT ACTUALLY LOADS THE NODES WHEN THEY ARE EXPANDED 
              private void TreeViewBackup_BeforeExpand(object sender, TreeViewCancelEventArgs e)
              {
                  // Retrieve click node select
                  TreeNode node = e.Node;
      
                  // Change image node - folder open 
                  if (Directory.Exists(node.Tag?.ToString() ?? ""))
                  {
                      node.ImageKey = "folder_open";
                      node.SelectedImageKey = "folder_open";
                  }
      
                  // Check if the node has no children and if it is a folder 
                  if (node.Nodes.Count == 1 && node.Nodes[0].Text == "Loading...")
                  {
                      node.Nodes.Clear();
                      MyLoadSubDirectoriesLazy(node, node.Tag.ToString());
                  }
              }
      
              // TREEVIEW - SET NODE IMAGE
              private void TreeViewBackup_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
              {
                  // Retrieve click node select
                  TreeNode node = e.Node;
      
                  // Change image node - folder close
                  if (Directory.Exists(node.Tag?.ToString() ?? ""))
                  {
                      node.ImageKey = "folder";
                      node.SelectedImageKey = "folder";
                  }
              }
      

    :
    Come puoi vedere ci sono alcune differenza rispetto il tuo approccio...

    Esempio... per assegnare l'immagini, ho preferito usare  l'accesso tramite "Chiave" e non per "Indice" come hai fatto tu.
    Questo facilita e/o agevola la scrittura e la rilettura del codice. 

    Altro Esempio... utilizzo della Tag ; utile per il caricamento con il "metodo Lazy". Nella Tag viene salvata la Path di ogni Nodo e questo consente di caricare in modo "Lazy" via via i vari nodi nel momento in cui vengono espansi. 

    Il resto del codice utilizza semplicemente metodi molto classici e/o comuni.

    E' tutto molto semplice e anche il codice è abbastanza commentato... se ti può tornare utile puoi prendere alcuni spunti.

  • Re: ImageGetter cambio immagini DataTreeListView

    Grazie Franco,

    Se vuoi posso farti vedere come ho approcciato questa TreeView per i file di Backup....

    Mi troverai sempre disponibile ad imparare qualcosa di nuovo. Il metodo Lazy non lo conoscevo ed è sicuramente interessante.

    Visto che abbiamo allargato il contesto aggiungo il perchè ho scelto il DataTreeListView. L'unico motivo è che mi permette di inserire nativamente all'interno di una riga uno o più link a directory. In sostanza tutto questo mi serve per creare una tabella organizzata ad albero dove visualizzare i link di directory che uso di frequente o che uso sporadicamente e che non ricordo l'indirizzo. Sarà l'età :-D

    Ovviamente questa parte esce dal contesto dell'oggetto ma ho voluto inserirla per completezza.

  • Re: ImageGetter cambio immagini DataTreeListView

    16/05/2025 - KronS ha scritto:

    perchè ho scelto il DataTreeListView.

    Ciao,

    DataTreeListView non ho mai avuto occasione di utilizzarlo... tu parli della libreria ObjectListView ?

  • Re: ImageGetter cambio immagini DataTreeListView

    DataTreeListView non ho mai avuto occasione di utilizzarlo... tu parli della libreria ObjectListView ?

    Esatto. Ci sono alcuni piccoli bug ma permette di inserire i link direttamente nei treelist abilitando il parametro Hyperlink.

  • Re: ImageGetter cambio immagini DataTreeListView

    17/05/2025 - KronS ha scritto:

    DataTreeListView non ho mai avuto occasione di utilizzarlo... tu parli della libreria ObjectListView ?

    Esatto. Ci sono alcuni piccoli bug ma permette di inserire i link direttamente nei treelist abilitando il parametro Hyperlink.

    Ok,   ... ho visto che ha molte funzionalità, diciamo che è più potente della TreeLitView standard.

    SI possono fare effettivamente molte cosine utili... da studiare e approfondire.

    Per eperienza personale preferisco stare sullo standard per non aver nessun tipo di problematica legata alla compatibilità, sicurezza, etc... soprattutto nel futuro.

    Ma per propria utilità... perchè no. E' sempre una buona esperienza.

    Come ti dicevo preferisco stare sulle cose semplici, assodate, robuste e testate, alla fine come nel tuo caso, puoi riuscire a fare le stesse  cose anche con la Tree View standard.

    Bene bene, bravo! ... allora buon lavoro.  ;-)

Devi accedere o registrarti per scrivere nel forum
11 risposte