1

I have code that runs in a different thread than the UI's one, and it has to create a control (windows forms). However, I don't have a reference to any control from the UI (that way, I could use myControl.Invoke( methodThatAddsControlToUI ) ). Is there a way to do it in the .net compact framework?

I would be interested in a solution that doesn't use references to other controls, if possible (tracking all created forms, for example, would not be a good workaround, as my code will be in a library). In the full framework version, there is the Application.OpenForms property, but this doesn't exit in the CF.

EDIT:

The main purpose of this is calling a method on the UI thread:

class Worker
{
    public MyMethod()
    {
        // I need to call a method on the UI (this code doesn't run in the UI thread), 
        // but I don't have any field  in this object holding an UI control
        // value. So, I can't write myControlField.Invoke(...),
        // but I still need to call a method on the UI thread
    }
}

Any suggestions?

Leandro Gomide
  • 998
  • 1
  • 10
  • 31
  • I'm probably missing something, but what are you going to do with the new control if you have no other control to assign it to? – Bruno Brant Jul 19 '12 at 15:30
  • I want to use it to invoke a method on the UI, someting like newControl.Invoke(myMethod) – Leandro Gomide Jul 19 '12 at 15:32
  • 1
    Can you give us some code example? I'm having a hard time to understand what is that you are trying to do! Sorry about that. – Bruno Brant Jul 19 '12 at 15:37
  • Perhaps you're looking for Dispatcher (http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx)? Is that in CF? http://stackoverflow.com/questions/269988/how-to-invoke-a-function-on-parent-thread-in-net – Matt Razza Jul 19 '12 at 15:42
  • @MattRazza, the dispatcher is a WPF component, not WinForms. (http://stackoverflow.com/questions/303116/system-windows-threading-dispatcher-and-winforms) – Bruno Brant Jul 19 '12 at 17:06

4 Answers4

2

From a library there's really no way to guarantee your thread context, so your safest bet is to have the consume provide the invoker and leave it to them to ensure it was created in the proper context. Something like this pattern:

class Foo
{
    private Control m_invoker;

    public Foo()
        : this(null)
    {
    }

    public Foo(Control invoker)
    {
        if (invoker == null)
        {
            // assume we are created on the UI thread, 
            // if not bad things will ensue
            m_invoker = new Control();
        }
        else
        {
            m_invoker = invoker;
        }
    }

    public void Bar()
    {
        m_invoker.Invoke(new Action(delegate
        {
            // do my UI-context stuff here
        }));
    }
}
ctacke
  • 66,480
  • 18
  • 94
  • 155
1

I'm sorry if this isn't a real answer, but I think it may help:

The reason why WinForms has this approach -- using a Control or Form reference to access a Invoke method that enables you to run code on the UI Thread -- is that the only reason you should have to run a code in the UI Thread is if you are going to write/change the state of UI components.

Of course, if you are going to do that, you must have a reference to a UI component. So you'd have access to its Invoke method. I cannot think of any other reason you'd have to access the UI thread from a component other than to modify a visual element.

Bruno Brant
  • 8,226
  • 7
  • 45
  • 90
  • makes sense...mean while, I'll take the approach suggested by ctacke, and may refactor my application afterwards to solve this problem... thanks anyway for the info! – Leandro Gomide Jul 19 '12 at 17:32
  • One example I know of (because I had to deal with it in the OpenNETCF IoC library) is that if a library needs to be able to raise events to the consumer and you'd like those events, for the sake of playing nice, to be raised on the UI thread, you need this capability. You're not affecting UI elements, but you are allowing consumers to receive events without having to do their own thread migration. – ctacke Jul 19 '12 at 18:17
  • @ctacke, I get it, but am not sure if it's the best example. If this library knows nothing about the UI, that's, isn't a UI library, it isn't its responsibility to marshal the code to the UI. What if there's no UI? Maybe you are using this component to build a service. – Bruno Brant Jul 19 '12 at 18:44
  • I'm really not criticizing @ctacke's answer, since I was actually about to suggest the same thing, but I must alert that using that approach means your library - whatever it is - now have a explicit dependency on the UI, so make sure that's what you want. You just diminished its reuse possibilities... – Bruno Brant Jul 19 '12 at 18:47
  • Also, can't you use the SynchronizationContext of your thread to marshal the code to the UI thread? – Bruno Brant Jul 19 '12 at 23:01
  • Actually, the problem appeared in some code that uses OpenNETCF's BackgroundWorker class. The problem is that the code was built (at least, this was the idea) to provide functionality to any consumer from any thread. Now I see this was design flaw. As for the SynchronizationContext, I'll look into that. – Leandro Gomide Jul 19 '12 at 23:24
  • 1
    @Igomide, here's a good place to start: http://msdn.microsoft.com/en-us/magazine/gg598924.aspx. – Bruno Brant Jul 20 '12 at 13:41
0

It must be invoke ... But invoke have to wait still main thread i mean you not get error this way but this is not exacly working parallel if you want to go more than one process at same time just create more then one thread

Thread thread = new Thread(new delegate_method(method));
thread.start ();
Thread thread2 = new Thread(new delegate_method(method2));
thread.start ();

handle two process same time

    void method ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}

void method2 ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}

void finish_thread()
{
if(invoke.Required)
{
//Here you have to call delegate method here with UI
BeginInvoke(new delegate_method(finish_thread));
}
else
{
//Now you can control UI thread from here and also you finished background work
//Do something working with UI thread
textBox.Text = "";
}
}
Toprak
  • 283
  • 1
  • 4
  • 11
0
//Declare this in class
public delegate void delege();

//Write this lines when you want to background thread start
    Thread thread = new Thread(new ThreadStart(() => {
    //Do what you what with backgorund threading , can not use any interface comand here
         BeginInvoke(new delege(() => { 
           //Do here any main thread thread job,this can do interface and control jobs without any error 
         }));
    }));
    thread.Start();
Toprak
  • 283
  • 1
  • 4
  • 11