T
T
termsl2014-04-17 11:56:10
.NET
termsl, 2014-04-17 11:56:10

C# How to update form control from another thread?

Forgive the slowpack, but how to update the control on the form from another thread?
I tried to attach a delegate here, but somehow unsuccessfully.
The transfer must occur from the SendStr function.

using ...;

namespace Ping_test
{
    public delegate void Del(string str);

    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
             Del Call = new Del(UpdateRes);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            
                 new PingExample().Start( "192.168.1.1",10);
        }

   
       }
    public class PingExample
    {
            private int Count = 0;
            private int Cycle = 0;
            private string ip = string.Empty;

            public PingExample()
            {
                TTimer = new System.Threading.Timer(new TimerCallback(OnTimer), TimerRun, System.Threading.Timeout.Infinite, 1000);

            }


            public void Start(string ip_str, int Raz)
            {
                Count = 1;
                Cycle = Raz;
                ip = ip_str;
                TTimer.Change(0, 1000);
            }
            private void OnTimer(object state)
            {
                if (Count <= Cycle)
                {
                    Go();
                }
            }
            public void Go()
            {
                AutoResetEvent waiter = new AutoResetEvent(false);
                Ping pingSender = new Ping();
                pingSender.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
                string data = "ID:<" + String.Format(@"{0,5:d}", Count.ToString()) + ">**********************";
                byte[] buffer = Encoding.ASCII.GetBytes(data);
                int timeout = 1000;
                PingOptions options = new PingOptions(64, true);
                pingSender.SendAsync(ip, timeout, buffer, options, waiter);
            }

            private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
            {
                // If the operation was canceled, display a message to the user.
                if (e.Cancelled)
                {
                    Console.WriteLine("Ping canceled.");
                    ((AutoResetEvent)e.UserState).Set();
                }

                if (e.Error != null)
                {
                    Console.WriteLine("#" + Count.ToString() + " " + ip + " Ping failed: ");
                    Console.WriteLine(e.Error.ToString());
                    ((AutoResetEvent)e.UserState).Set();
                }

                PingReply reply = e.Reply;

                DisplayReply(reply);
                ((AutoResetEvent)e.UserState).Set();
                Count++;
            }

            public void DisplayReply(PingReply reply)
            {
                if (reply == null)
                    return;
                string Num = "#" + String.Format(@"{0,5:d}", Count.ToString());

                if (reply.Status == IPStatus.Success)
                {
                    string res = Num + " " + reply.Address.ToString() + " RTT " + reply.RoundtripTime.ToString() + " TTL " + reply.Options.Ttl.ToString() + " BUFFER " + reply.Buffer.Length.ToString();
                    res += " \"" + System.Text.ASCIIEncoding.ASCII.GetString(reply.Buffer) + "\"";
                    SendStr(res);
                }
                else
                {
                    string res = Num + " " + ip + " ERROR: " + reply.Status.ToString();
                    SendStr(res);
                }
            }

            void SendStr(string str);
            {

            }
}

Answer the question

In order to leave comments, you need to log in

8 answer(s)
V
Vitaly, 2014-04-22
@termsl

can be even easier

BeginInvoke(new MethodInvoker(delegate
            {
                //здесь твой код в основном потоке
            }));

D
Denis Morozov, 2014-04-17
@morozovdenis

BackgroundWorker:
msdn.microsoft.com/en-us/library/system.componentm...
it has an OnProgressChanged event that will be called on the form's thread. to generate an event in doWork, you need to call the ReportProgress method msdn.microsoft.com/ru-ru/library/a3zbdb1t.aspx it
is not necessary to define methods, you can use lambdas:

backgroundWorker.DoWork += (sender, e) => { ... };
backgroundWorker.DoWork += delegate { ... };

S
Sergey Mozhaykin, 2014-04-17
@smozhaykin

Remember Dispatcher.CurrentDispatcher when creating the form, and update the UI from another thread using Dispatcher.BeginInvoke.

G
gleb_kudr, 2014-04-17
@gleb_kudr

Well, for example like this:

// some background thread code
Form1.Dispatcher.Invoke(DispatcherPriority.ContextIdle, new Action(delegate()
            {
                label1.Content="invoked from background thread";
            }));

Those. we take a UI element, take a dispatcher from it, and in this dispatcher we make a procedure invocation. You can also use the static Application.Current.Dispatcher.

T
termsl, 2014-04-17
@termsl

How to call BackgroundWorker.OnProgressChanged from
I understand that in order to take advantage of the charms of the BackgroundWorker - you need to shove a procedure into it that will run in the background and it will already be able to call OnProgressChanged.
I have a slightly different situation.

T
termsl, 2014-04-17
@termsl

There is no example, or describe in a couple of lines?

T
termsl, 2014-04-18
@termsl

Neither the Form1 class nor the PingExample class can
insert this.

O
Ogoun Er, 2014-08-05
@Ogoun

If the thread is running somewhere in the business layer and does not know about the form, then a synchronization context can be used. Like this:
When creating the form:

SynchronizationContext uiContext = SynchronizationContext.Current;
Thread thread = new Thread(Run);
// Запустим поток и установим ему контекст синхронизации,
// таким образом этот поток сможет обновлять UI
thread.Start(uiContext);

Stream code:
private void Run(object state)
    {
        // вытащим контекст синхронизации из state'а
        SynchronizationContext uiContext = state as SynchronizationContext;
         // говорим что в UI потоке нужно выполнить метод UpdateUI 
         // и передать ему в качестве аргумента строку
         uiContext.Post(UpdateUI, "Hello world!");
    }

And the code that performs the action to change the UI
/// <summary>
/// Этот метод исполняется в основном UI потоке
/// </summary>
private void UpdateUI(object state)
{
    sampleListBox.Items.Add((string)state);
}

At the same time, no beginInvoke's in the UpdateUI method will be required anymore, because code is uniquely executed on the UI thread.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question