C # - Updating a GUI using a non-core theme

I have a program that has classes

  • GUI
  • Download
  • and a buffer between two classes - i.e. used for communication between two classes.

The class is Uploadused Processto run an FTP command line application. I want to return what result created by the FTP application will be displayed in textboxthe GUI.
I tried using the following code, which was truncated.

Load class (beginProcess () is the method used to start Thread (not shown here)):

public delegate void WputOutputHandler(object sender, DataReceivedEventArgs e);
class Upload
{
    private WputOutputHandler wputOutput;

    beginProcess()
    {
        Process pr = new Process();                                                 
        pr.StartInfo.FileName = @"wput.exe";                                        
        pr.StartInfo.RedirectStandardOutput = true;
        pr.StartInfo.UseShellExecute = false;
        pr.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        pr.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
        pr.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceived);
        pr.Start();                                                                 
        pr.BeginOutputReadLine();
        pr.WaitForExit();
    }


    public void OnDataReceived(object sender, DataReceivedEventArgs e)
    {
        if(wputOutput != null)
        {
            wputOutput(sender, e);
        }
    }


    public event WputOutputHandler WputOutput
    {
        add
        {
            wputOutput += value;
        }
        remove
        {
            wputOutput -= value;
        }
    }
}

Buffer class:

public void EventSubscriber()
{
    uploadSession.WputOutput += Main.writeToTextBoxEvent;
}

Main class:

public void writeToTextBoxEvent(object sender, DataReceivedEventArgs e)
{
    if(this.textBox1.InvokeRequired)
    {
        MethodInvoker what now?
    }
    else
    {
        textBox1.Text = e.Data;
    }
}

, Main writeToTextBoxEvent, . , - . - , .

+3
5

:

public void writeToTextBoxEvent(object sender, DataReceivedEventArgs e)
{
    if(this.textBox1.InvokeRequired)
    {
        // In .Net 2.0
        this.textBox1.BeginInvoke(new MethodInvoker(() => writeToTextBoxEvent(sender, e)));

        // In .Net 3.5 (above is also possible, but looks nicer)
        this.textBox1.BeginInvoke(new Action(() => writeToTextBoxEvent(sender, e)));
    }
    else
    {
        textBox1.Text = e.Data;
    }
}

- ( BeginInvoke() else).

Update

.Net 3.5, :

public static class ControlExtensions
{
    public static void SafeInvoke(this Control control, Action action)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }

    public static void SafeBeginInvoke(this Control control, Action action)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(action);
        }
        else
        {
            action();
        }
    }
}

:

public void writeToTextBoxEvent(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    // Write it as a single line
    this.textBox1.SafeBeginInvoke(new Action(() => textBox1.Text = e.Data));

    this.textBox1.SafeBeginInvoke(new Action(() =>
        {
            //Write it with multiple lines
            textBox1.Text = e.Data;
        }));
}
+3
if(this.textBox1.InvokeRequired)
{
   Action a = () => { textBox1.Text = e.Data; };
  textBox1.Invoke(a);
}

.. ( ) Invoke. , . Invoke , .

, (BeginInvoke).

EDIT: , Invoke Delegate, local. NB, , , , .

+2

:

public static void InvokeIfRequired(this System.Windows.Forms.Control c,
                                    Action action) {
    if (c.InvokeRequired) {
        c.Invoke((Action)(() => action()));
    }
    else {
        action();
    }
}

:

public void writeToTextBoxEvent(object sender, DataReceivedEventArgs e) {
    this.textBox1.InvokeIfRequired(() => { textBox1.Text = e.Data; }
}
+2

, .

I think you need a workflow to search for the received data, and then use a delegate from the workflow to write the data to your TextBox.

Sort of:

public delegate void textBoxWriteDelegate(string msg);

private void textBoxWrite(string sMess) {
  textBox.AppendText(sMess);
}

And from the workflow:

Invoke(new textBoxWriteDelegate(textBoxWrite), new object [] { "Launching ftp cmd line .... \n" });

Sorry, no version 1.1;) There's a better way to write delegates in 2.0 and above ...

0
source

I created a little helper for this:

class LayoutsEngine 
{
    internal static void ThreadSafeDoer(Form Form, Delegate Whattodo)
    {
        if (!Form.IsDisposed)
        {
            if (Form.InvokeRequired)
            {
                Form.Invoke(Whattodo);
            }
            else
            {
                Whattodo.DynamicInvoke();
            }
        }
    }
}

and use it as follows:

    LayoutsEngine.ThreadSafeDoer(this, new MethodInvoker(delegate()
    {
         txtWhatever.Text=whatever();
         //  and any other GUI meddling
    }));

Also, if anyone has a way to downsize MethodInvoker()here, please comment.

0
source

Source: https://habr.com/ru/post/1769733/


All Articles