Выполненный код UI распараллеливает без существующего объекта управления

Онлайн для публичного использования или для передачи кому-то конкретному (другу или кому-то еще)?

Если это с другом, вы можете попробовать перенаправить трафик с вашего маршрутизатора на ваш ПК с определенным портом. Затем создайте простой веб-сайт (например, с Flask, так как он использует python), чтобы сделать игру играбельной. Наконец, другие могут сыграть в игру, зайдя на ваш сайт через ваш общедоступный IP-адрес.

11
задан Martin Moser 19 January 2009 в 10:57
поделиться

4 ответа

Существует лучший, более абстрактный способ сделать это, которое работает и над WinForms и над WPF:

System.Threading.SynchronizationContext.Current.Post(theMethod, state);

Это работает, потому что WindowsForms устанавливает a WindowsFormsSynchronizationContext возразите как текущий синхронизирующий контекст. WPF делает что-то подобный, устанавливающий свой собственный специализированный контекст синхронизации (DispatcherSynchronizationContext).

.Post соответствует control.BeginInvoke, и .Send соответствует control.Invoke.

19
ответ дан 3 December 2019 в 04:14
поделиться

Поместите управление UI в метод на форме, которой будут управлять, и передайте делегата в коде, который работает на фоновом потоке, а-ля APM. Вы не должны использовать params object p, можно сильно ввести его для удовлетворения собственным целям. Это - просто простой универсальный образец.

delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
  if (InvokeRequired) 
    BeginInvoke(d,p);        
  else
  {
    //do stuff to UI
  }
}

Этот подход утвержден на том, что делегат обращается к методу на конкретном экземпляре; путем создания реализации методом формы Вы приносите форму в объем как this. Следующее семантически идентично.

delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
  if (this.InvokeRequired) 
    this.BeginInvoke(d,p);        
  else
  {
    //do stuff to UI
  }
}
1
ответ дан 3 December 2019 в 04:14
поделиться

Вы правы, не хорошо передать средства управления потокам. Средства управления Winforms являются однопоточными, передавание их к нескольким потокам может вызвать условия состязания или повредить Ваш UI. Вместо этого необходимо сделать функции потока доступными для UI и позволять ему назвать поток, когда UI хорош и готов. Если Вы хотите иметь фоновые потоки, инициировали изменения UI, выставляют фоновое событие и подписываются на него от UI. Поток может исчерпать события каждый раз, когда он хочет, и UI может ответить на них, когда он может.

Создание этой двунаправленной связи между потоками, которая не блокирует поток UI, является большой работой. Вот высоко сокращенный пример с помощью класса BackgroundWorker:

public class MyBackgroundThread : BackgroundWorker
{
    public event EventHandler<ClassToPassToUI> IWantTheUIToDoSomething;

    public MyStatus TheUIWantsToKnowThis { get { whatever... } }

    public void TheUIWantsMeToDoSomething()
    {
        // Do something...
    }

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        // This is called when the thread is started
        while (!CancellationPending)
        {
            // The UI will set IWantTheUIToDoSomething when it is ready to do things.
            if ((IWantTheUIToDoSomething != null) && IHaveUIData())
                IWantTheUIToDoSomething( this, new ClassToPassToUI(uiData) );
        }
    }
}


public partial class MyUIClass : Form
{
    MyBackgroundThread backgroundThread;

    delegate void ChangeUICallback(object sender, ClassToPassToUI uiData);

    ...

    public MyUIClass
    {
        backgroundThread = new MyBackgroundThread();

        // Do this when you're ready for requests from background threads:
        backgroundThread.IWantTheUIToDoSomething += new EventHandler<ClassToPassToUI>(SomeoneWantsToChangeTheUI);

        // This will run MyBackgroundThread.OnDoWork in a background thread:
        backgroundThread.RunWorkerAsync();
    }


    private void UserClickedAButtonOrSomething(object sender, EventArgs e)
    {
        // Really this should be done in the background thread,
        // it is here as an example of calling a background task from the UI.
        if (backgroundThread.TheUIWantsToKnowThis == MyStatus.ThreadIsInAStateToHandleUserRequests)
            backgroundThread.TheUIWantsMeToDoSomething();

        // The UI can change the UI as well, this will not need marshalling.
        SomeoneWantsToChangeTheUI( this, new ClassToPassToUI(localData) );
    }

    void SomeoneWantsToChangeTheUI(object sender, ClassToPassToUI uiData)
    {
        if (InvokeRequired)
        {
            // A background thread wants to change the UI.
            if (iAmInAStateWhereTheUICanBeChanged)
            {
                var callback = new ChangeUICallback(SomeoneWantsToChangeTheUI);
                Invoke(callback, new object[] { sender, uiData });
            }
        }
        else
        {
            // This is on the UI thread, either because it was called from the UI or was marshalled.
            ChangeTheUI(uiData)
        }
    }
}
2
ответ дан 3 December 2019 в 04:14
поделиться

Что относительно того, чтобы передать Систему. ComponentModel. ISynchronizeInvoke? Тем путем можно постараться не передавать Управление.

1
ответ дан 3 December 2019 в 04:14
поделиться
Другие вопросы по тегам:

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