Reputation: 163
I'm filling TreeView
programmatically (in different thread if it matters).
I want the first level of nodes to be expanded when TreeView
loads to window. I've tried almost everywhere (in worker thread, in main thread, in event handlers of Form.Load
, Form.Shown
etc.), but TreeView
is still collapsed.
What am I doing wrong ?
UPDATE
treeView.UpdateTree((object tree) => {
treeView.Nodes[0].Nodes.Add(text);
});
public static void UpdateTree(this Control ctrl, Action<object> code) {
if (ctrl.InvokeRequired) {
ctrl.BeginInvoke(code, (TreeView)ctrl);
}
else {
code.Invoke((TreeView)ctrl);
}
}
UPDATE 2
private void btnFillTree_Click(object sender, EventArgs e) {
......
treeDirectoryContents.Nodes.Add("GeneralFolder");
......
//there I create Thread() that fills treeDirectoryContents
......
treeDirectoryContents.ExpandAll();
}
Upvotes: 0
Views: 3492
Reputation: 3338
As far I know (.NET 3.5) you cannot acces GUI elements from different thread (you can prepare some data but must access TreeView.Nodes
from main thread only - use Control.BeginInvoke
for that ... you can as well check Control.InvokeRequired
).
After filling all the nodes you can just do
foreach (TreeNode node in treeView) node.Expand()
EDIT after UPDATE2:
Control.InvokeRequired
)Invoke()
is synchronous (like BeginInvoke + EndInvoke)Thread.Join()
from main thread (use BackgroundWorker.IsBusy
or mimic that by some state variable e.g. bool done = false; thread.Start(); while(!done) Application.DoEvents()
Example from MSDN:
// Start the download operation in the background.
this.backgroundWorker1.RunWorkerAsync();
// Disable the button for the duration of the download.
this.downloadButton.Enabled = false;
// Once you have started the background thread you
// can exit the handler and the application will
// wait until the RunWorkerCompleted event is raised.
// Or if you want to do something else in the main thread,
// such as update a progress bar, you can do so in a loop
// while checking IsBusy to see if the background task is
// still running.
while (this.backgroundWorker1.IsBusy)
{
progressBar1.Increment(1);
// Keep UI messages moving, so the form remains
// responsive during the asynchronous operation.
Application.DoEvents();
}
EDIT - How I thing it should be done (using Threads)
using System;
using System.Threading;
using System.Windows.Forms;
class MyForm : Form {
public static void Main() {
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
TreeView tree = new TreeView() { Dock = DockStyle.Fill };
MyForm() {
Controls.Add(tree);
tree.Nodes.Add("Loading...");
}
protected override void OnLoad(EventArgs e) {
new Thread(Fill).Start();
base.OnLoad(e);
}
void Create(string text) {
if (InvokeRequired) Invoke(new Action<string>(this.Create), text);
else tree.Nodes[0].Nodes.Add(text);
}
void Finish() {
if (InvokeRequired) Invoke(new Action(this.Finish));
else {
tree.Nodes[0].Text = "The Nodes";
tree.ExpandAll();
}
}
void Fill() {
for (int i = 0; i < 10; i++) {
Create("Node #" + i.ToString());
Thread.Sleep(100);
}
Finish();
}
}
Upvotes: 5