0

假设我有一个名为 mainFrm 的表单和一个名为 objectA 的对象,该对象包含正在运行的线程。当这两种情况发生时,我的程序应该关闭:

(1)。用户单击 mainFrm 中的“X”按钮(因此引发 mainFrm.FormClosing)

(2)。在 objectA 中引发了一个事件(我们将其命名为“connectionClosed”)

因此,无论是否触发(1)(2),此事件链应始终包括:

  1. 任何对象的终止底层线程。(我已经知道如何使用位于 objectA 中的代码优雅地终止它们)
  2. 当然,mainFrm 的关闭

解决这个问题的最佳方法是什么?

我就是这样解决的

不知道为什么这个问题没有得到社区的好评。我认为这是相当清晰和直接的。这是我解决它的方法,我希望这也有助于更好地定义我的意思。如果您有任何其他疑问,请告诉我 =)

在表单类中:

...
this.FormClosed += objectA.kill;
objectA.connectionClosed +=closeForm;
...

private void closeForm(object sender, FormClosedEventArgs e)
{
    try
    {
        this.Invoke(new MethodInvoker(delegate { this.Close(); }));
    }
    catch { }
}

在 objectA 的类中:

...
//connectionClosed is raised in different parts of objectA's   threads code
connectionClosed += killClient; 
...

public void killClient(object sender, FormClosedEventArgs e)
{
    //event should go past this point just once
    if (!_connectionClosed)
    {
        _connectionClosed = true;

        try
        {
            ... //close connection killing all threads
        }
        catch { }
    }
}

根据开头所述的 (1) 和 (2) 用例,这就是应该发生的事情(如果我没记错的话)

(1)。用户单击“X”按钮 -> 表单关闭 -> formclosed 被引发 -> objectA.kill 方法委托被执行 -> 内部线程引发一些 connectionClosed 事件,这将触发更多 objectA.kill 执行,但这不会造成任何损害,这要归功于volatile bool _connectionClosed (当然,因为有一个 try/catch 无论如何都可以工作,但对我来说不再执行此类代码更有意义)-> 线程由 objectA.kill 的唯一完全执行终止-> SUCCESS

(2)。服务器关闭连接或网络错误 -> objectA 的内部线程检测到连接错误并引发多个 connectionClosed 事件 -> 不同的线程将尝试执行 objectA.kill 方法委托。-> 同时,在主窗体中,closeForm 被执行,关闭窗体 -> 这也触发了另一个 objectA.kill 执行(感谢 this.FormClosed += _client.killClient; ) -> 再次,这不会造成伤害,因为 _connectionClosed volatile bool 将只让一个线程实际执行代码(引发事件的第一个)-> 线程通过 objectA.kill 的唯一完整执行优雅地终止-> SUCCESS

下一步应该是找到一种更方便的方法,以便 connectionClosed 可能只上升一次,我现在就去谷歌搜索 =)

4

2 回答 2

1

在事件上调用 Close() 有什么问题?如果您在 FormClose 上切换一个布尔值,那么您可以忽略接下来的事件。如果您想在关闭表单之前中断用户操作,请仅使用 FormClosing。使用 FormClosing 您可以防止关闭论坛。这主要用于,如果某些数据未保存并且您询问用户是否要关闭表单而不保存,否则您取消关闭。

所以不要使用FormClosing,使用FormClosed来清理实例。

于 2013-09-06T22:29:42.953 回答
1

我不确定这是否可以帮助您解决问题,但您应该参考以下代码。这是一个使用线程对象更改表单颜色的示例。当事件引发 20 次Form1时自动关闭( :您可以将此操作视为您的事件 connectionClosed 引发);或者您可以在线程运行时通过单击“X”按钮随时关闭。_objectA.DoSomethingif(count > 20)Form1Form1

public delegate void ObjectADoSomethingEventHandler(object sender, ObjectADoSomethingEventArgs e);
public class ObjectADoSomethingEventArgs : EventArgs
{
    public int Value { get; private set; }
    public ObjectADoSomethingEventArgs(int value)
    {
        Value = value;
    }
}


public class ObjectA
{
    public event ObjectADoSomethingEventHandler DoSomething;
    protected void OnDoSomething(int value)
    {
        if (DoSomething != null)
            DoSomething(this, new ObjectADoSomethingEventArgs(value));
    }

    public event EventHandler Closed;
    protected void OnClosed()
    {
        if (Closed != null)
            Closed(this, new EventArgs());
    }


    private BackgroundWorker _worker;
    public ObjectA()
    {
        _worker = new BackgroundWorker();
        _worker.DoWork += new DoWorkEventHandler(_objectA_DoWork);
        _worker.ProgressChanged += new ProgressChangedEventHandler(_objectA_ProgressChanged);
        _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_objectA_RunWorkerCompleted);
        _worker.WorkerReportsProgress = true;
        _worker.WorkerSupportsCancellation = true;
    }

    public void Start()
    {
        _worker.RunWorkerAsync();
    }

    public void Kill()
    {
        if (_worker != null && _worker.IsBusy)
        {
            _worker.CancelAsync();
        }
    }

    private void _objectA_DoWork(object sender, DoWorkEventArgs e)
    {
        int count = 0;
        while (true)
        {
            _worker.ReportProgress(count);
            count++;
            if (count > 20)
            {
                return; // exit thread.
            }

            if (_worker.CancellationPending)
            {
                e.Cancel = true;
                return; // Thread cancelled.
            }
            Thread.Sleep(500);
        }
    }

    private void _objectA_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        OnDoSomething(e.ProgressPercentage);
    }

    private void _objectA_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        OnClosed();
    }
}


public partial class Form1 : Form
{
    private ObjectA _objectA;

    public Form1()
    {
        InitializeComponent();
        _objectA = new ObjectA();
        _objectA.DoSomething += _objectA_DoSomething;
        _objectA.Closed += _objectA_Closed;
        _objectA.Start();
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        _objectA.Kill();
    }

    private int _red = 128;
    private int _green = 128;
    private int _blue = 128;
    void _objectA_DoSomething(object sender, ObjectADoSomethingEventArgs e)
    {
        _red += 15;
        if (_red > 255) _red = 128;
        _green -= 15;
        if (_green < 0) _green = 128;
        _blue += 15;
        if (_blue > 255) _blue = 128;
        this.BackColor = Color.FromArgb(_red, _green, _blue);
        this.Text = string.Format("Count = {0}", e.Value);
    }

    void _objectA_Closed(object sender, EventArgs e)
    {
        Close();
    }
}
于 2013-09-06T23:20:11.467 回答