0

I use 4 WPF User Controls in a single Application. Each of the User Controls launch their own threads to do stuff at the end of which I want them to only update the ListBox present in their respective User Control.

I tried using a static variable in the User Control code to hold either the instance of the User Control or even its ListBox, but that results in only the last User Control ListBox being written to (by the wrong thread).

I've even tried stuff like this

private static ListBox1 = null;
private static ListBox2 = null;
private static ListBox3 = null;
private static ListBox4 = null;
private static ListBoxToUse;

then on initialization of each UserControl

if (ListBox1 == null)
{
    ListBox1 = this;
    ListToUse = this;
}
else if (ListBox2 == null)
{
    ListBox2 = this;
    ListToUse = this;
} ...

and then

ListBoxToUse.Dispatcher.BeginInvoke(new Action(delegate()
{
    ListBoxToUse.Items.Add("......");
}));

But that didn't work either. Any suggestions please?

Edit 1 :-

Following is my thread code

    private class CopyPortDevFileThread
    {
        public MyWorkingDirectoryInfo WorkingDirectory { get; set; }
        public PortableDeviceFile PortDevFileToCopy { get; set; }
        public string DestinationDir { get; set; }

        public void CopyFile()
        {
            Debug.WriteLine("CopyFile DestinationDir " + DestinationDir);
            // To fix Samsung NT-7000 bug of giving the Id when Path.GetFilename() is called
            string gfn = Path.GetFileName(PortDevFileToCopy.Id);
            string fn = DestinationDir + "\\" + gfn;
            WorkingDirectory.USBDevice.DownloadFile(PortDevFileToCopy, DestinationDir);
            if (!IsValidFilename(gfn))
            {
                // Rename file if name is okay
                if (IsValidFilename(PortDevFileToCopy.Name))
                {
                    int sec = 5;
                    while (sec > 0)
                    {
                        if (IsFileReady(fn))
                        {
                            File.Move(fn, Path.Combine(DestinationDir, PortDevFileToCopy.Name));
                            fn = Path.Combine(DestinationDir, PortDevFileToCopy.Name);
                            sec = 0;
                        }
                        else
                        {
                            Console.WriteLine("Waiting .....");
                            System.Threading.Thread.Sleep(1000);
                        }
                        sec -= 1;
                    }
                }
            }
        }
    }

Then the call to the thread from the code of the User Control

    private void CopyPortDevDocument(PortableDeviceFile _file, string _destDir)
    {
        Debug.WriteLine("CopyPortDevDocument with destination directory " + _destDir);
        if (_file == null)
        {
            return;
        }
        if (_destDir == null)
        {
            return;
        }
        if ((System.IO.Directory.Exists(_destDir)))
        {
            CopyPortDevFileThread cpdft = new CopyPortDevFileThread();
            cpdft.WorkingDirectory = Pwd;
            cpdft.PortDevFileToCopy = _file;
            cpdft.DestinationDir = _destDir;
            Thread cpdfThread = new Thread(new ThreadStart(cpdft.CopyFile));
            cpdfThread.Start();

            LogOutput(@"creating " + _destDir + "\\" + _file.Name);
        }
    }
3
  • Using the dispatcher of the ListBox is the right approach. Not sure what your problem is - please explain it more specifically. Commented Apr 17, 2014 at 7:09
  • In order for a thread to write something onto the UI control that launched it, the way is to declare a static variable pointing to the UI control instance and then assigning values to that variable. The problem is that if there are multiple instances of that UI control then the static variable receives the last assignment. In my case, the output only appears in the last ListBox. Commented Apr 17, 2014 at 8:57
  • "In order for a thread to write something onto the UI control that launched it, the way is to declare a static variable pointing to the UI control instance and then assigning values to that variable". This is not the only way, and certainly not an elegant one. Show how you are starting your threads. Commented Apr 17, 2014 at 9:12

1 Answer 1

1

You don't need these static fields. Just assign the x:Name property of the ListBox control in the UserControl XAML. Then you can access the ListBox as member of the UserControl class:

<UserControl x:Class="UserControlTest.MyUserControl" ...>
    <Grid>
        <ListBox x:Name="list" .../>
        ...
    </Grid>
</UserControl>

The above XAML creates a field list of type ListBox in class MyUserControl.


Update: Change the CopyFile method of your thread class so that it accepts a parameter of type object and then cast that object to a UserControl reference:

public void CopyFile(object parameter)
{
    var userControl = parameter as MyUserControl;
    ...
}

Then start your thread with the UserControl reference parameter like this:

var cpdfThread = new Thread(new ParameterizedThreadStart(cpdft.CopyFile));
cpdfThread.Start(this); // where this is the UserControl reference

Another alternative would be to just add the UserControl reference as property to your CopyPortDevFileThread class.

Instead of creating a new Thread for excuting the CopyFile method you may also use a ThreadPool thread by e.g. calling ThreadPool.QueueUserWorkItem.

Sign up to request clarification or add additional context in comments.

5 Comments

I am writing from a thread. I can't see any instantiated controls from the thread. Only static variables.
You could easily pass the UserControl reference to the thread (e.g. by a ParameterizedThreadStart). If you would show us how you start your threads, you may get more precise information.
Hi thanks for your help. I've tried what you recommended in the code portion above but I get a "InvalidOperationException" at the call to userControl.BrowserOutput.Items.Add("Hello"); and I've checked that both userControl and userControl.BrowserOutput are non-null.
Have you used the UserControl's Dispatcher to add the ListBox items?
When you've finally got this running the next step would be to separate the view from thread logic. You should take a look at the MVVM pattern, and create a view model class that does the threading. That class would expose an items property which the ListBox in the UserControl would bind its ItemsSource property to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.