C# Как из другого потока обновить control на форме?

Простите слоупока, но как из другого потока обновить control на форме?
Пробовал сюда прикрутить delegate, но как-то безуспешно.
Передача должна происходить из функции SendStr.

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);
            {

            }
}
  • Вопрос задан
  • 22547 просмотров
Решения вопроса 1
vipuhoff
@vipuhoff
можно еще проще
BeginInvoke(new MethodInvoker(delegate
            {
                //здесь твой код в основном потоке
            }));
Ответ написан
Пригласить эксперта
Ответы на вопрос 7
morozovdenis
@morozovdenis
BackgroundWorker:
msdn.microsoft.com/ru-ru/library/system.componentm...

у него есть событие OnProgressChanged которое будет вызываться в потоке form-ы. что-бы сгенерировать событие в doWork-е надо вызвать метод ReportProgress msdn.microsoft.com/ru-ru/library/a3zbdb1t.aspx

определять методы не обязательно, можете использовать лямбды:
backgroundWorker.DoWork += (sender, e) => { ... };
backgroundWorker.DoWork += delegate { ... };
Ответ написан
@smozhaykin
Запоминать Dispatcher.CurrentDispatcher при создании формы, а из другого потока обновлять UI, используя Dispatcher.BeginInvoke.
Ответ написан
Комментировать
@gleb_kudr
Ну, например так:

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


Т.е. мы берем элемент UI, у него берем диспатчер и в этом диспатчере делаем инвокейшн процедуры. Можно еще использовать статический Application.Current.Dispatcher.
Ответ написан
Комментировать
termsl
@termsl Автор вопроса
Как вызвать BackgroundWorker.OnProgressChanged из
pingSender.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);


Я понимаю для того чтобы воспользоваться прелестями BackgroundWorker - в него надо запихнуть процедуру, которая будет бежать в фоне и она уже сможет вызывать OnProgressChanged.
У меня несколько другая ситуация.
Ответ написан
Комментировать
termsl
@termsl Автор вопроса
Примера нет, или в пару строк описать?
Ответ написан
Комментировать
termsl
@termsl Автор вопроса
Ни в класса Form1, ни в класс PingExample
вставить это не получается.
Ответ написан
Комментировать
Ogoun
@Ogoun
Programmer
Если поток выполняется где-то в бизнес-слое и не знает про форму, то можно использовать контекст синхронизации. Вот так:

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


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


И код который выполняет действие по изменению UI
/// <summary>
/// Этот метод исполняется в основном UI потоке
/// </summary>
private void UpdateUI(object state)
{
    sampleListBox.Items.Add((string)state);
}


При этом никаких beginInvoke'ов в методе UpdateUI уже не потребуется, т.к. код однозначно исполняется в UI потоке.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы