0

ユーザーがボタンをクリックすると、何らかのタスクが開始されます。メイン アプリケーション スレッドをブロックしたくないので、別のスレッドで実行します。ここで、タスクが完了するまでユーザーがボタンをクリックすることを禁止する必要があります。

設定できました

button.Enabled = false;

、しかし、クリックを無視する方法を探しています。

クリック イベント ハンドラーにいくつかのチェックを追加できます。

if (executingThread != null) return;

、しかし、悪い考えである各ハンドラーに対してそれを行う必要があります。

ユーザーのメッセージをフィルタリングする方法があることを知っています。これを行う方法を教えていただけますか?また、すべてのメッセージを除外したくありません。他のいくつかのボタンはクリック可能にしておく必要があるため、特定のコントロール (ボタン、グリッドなど) に来るメッセージを除外する必要があります。

解決

internal class MessagesFilter: IMessageFilter
{
    private readonly IntPtr ControlHandler;

    private const int WM_KEYUP = 0x0101;

    public MessagesFilter(IntPtr ControlHandler)
    {
        this.ControlHandler = ControlHandler;
    }

    #region IMessageFilter Members

    public bool PreFilterMessage(ref Message m)
    {
        // TODO:  Add MessagesFilter.PreFilterMessage implementation
        if (m.Msg == WM_KEYUP)
        {
            if (m.HWnd == ControlHandler)
            {
                Keys k = ((Keys) ((int) m.WParam));

                if (k == Keys.Enter)                    
                    return true;
            }
        }

        return false;
    }

    #endregion
}
4

3 に答える 3

1

As always, the UI should be presented in such a way that user understands what the application is doing and should talk to the user with UI elements.

As Adam Houldsworth suggested I would also prefer keeping the button either disabled or enabled but I would also suggest that the caption of the button should convey the message to the user that the long processing is in progress when the new thread starts..and so the caption of the button should be immediately changed to something like "Processing..Please wait..." (in addition to being disabled or even if you want to keep it enabled), and then if you have kept the button enabled just check the caption of the button (or a isProcessing bool flag) on its click event to return if it says "Processing..Please wait..." or (isProcessing == true).

Lots of the Websites which help users to upload files/images change the Upload button's caption to "Uploading..Please wait..." to inform the user to wait until the upload finishes and additionally some sites also disable the upload button so that the user is not able to click again on Upload button.

You would need to also revert back the caption to normal when the thread finishes long processing.

There may be other advanced ways but the idea is to keep it as simple and basic as possible.

Look at this example on Threading in Windows Forms which shows to disable the button while multi-threading.

于 2012-06-21T09:53:52.523 に答える
0

これまでのすべての提案に対して+1。CSharpVJ示唆するように-My idea was to additionally inform the user by changing the button's caption making the UI design more intuitive

これは、Winforms の Backgroundworker コンポーネントでエレガントに実現できます [面倒なコードはありません]。コピーして貼り付け、F5 キーを押すだけです (ボタンとラベルを含む新しい Winforms プロジェクトを作成した後)。

ここでボタンに関連するものをチェックする必要はありません。すべては、適切なイベント ハンドラーによって処理されます。それぞれのイベントハンドラーで正しいものを実行する必要があるだけです。それを試してみてください !

using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form3 : Form
    {
        private BackgroundWorker _worker;

        public Form3()
        {
            InitializeComponent();
            InitWorker();
        }

        private void InitWorker()
        {
            if (_worker != null)
            {
                _worker.Dispose();
            }

            _worker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _worker.DoWork += DoWork;
            _worker.RunWorkerCompleted += RunWorkerCompleted;
            _worker.ProgressChanged += ProgressChanged;
        }

        /// do time consuming work here... 
        void DoWork(object sender, DoWorkEventArgs e)
        {
            int highestPercentageReached = 0;
            if (_worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                double i = 0.0d;

                for (i = 0; i <= 199990000; i++)
                {
                    // Report progress as a percentage of the total task.
                    var percentComplete = (int)(i / 199990000 * 100);
                    if (percentComplete > highestPercentageReached)
                    {
                        highestPercentageReached = percentComplete;
                        // Report UI abt the progress  
                        _worker.ReportProgress(percentComplete);
                        _worker.CancelAsync();
                    }
                }

            }
        }

        void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Enabled = true;
            if (e.Cancelled)
            {
                // Display some message to the user that task has been
                // cancelled
                label1.Text = "Cancelled the operation";
            }
            else if (e.Error != null)
            {
                // Do something with the error
            }

            button1.Text = "Start again";
        }

        void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text =  string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
        }

        private void OnStartClick(object sender, System.EventArgs e)
        {
            _worker.RunWorkerAsync();
            button1.Text = "Processing started...";
            button1.Enabled = false;
        }

    }
}
于 2012-06-21T11:24:38.097 に答える
0

他の回答で述べたように、おそらくあなたが求めているものよりも良い解決策があります。

質問に直接答えるには、IMessageFilter インターフェイスを確認してください。

不要なマウス メッセージを抑制するフィルタを作成し、必要に応じて を使用して適用しますApplication.AddMessageFilter()

これらの行に沿ったもの(これはおそらくコンパイルする必要があります...):

public class MouseButtonFilter : IMessageFilter
{

    private const int WM_LBUTTONDOWN            = 0x0201;
    private const int WM_LBUTTONUP              = 0x0202;
    private const int WM_LBUTTONDBLCLK          = 0x0203;
    private const int WM_RBUTTONDOWN            = 0x0204;
    private const int WM_RBUTTONUP              = 0x0205;
    private const int WM_RBUTTONDBLCLK          = 0x0206;
    private const int WM_MBUTTONDOWN            = 0x0207;
    private const int WM_MBUTTONUP              = 0x0208;

    bool IMessageFilter.PreFilterMessage(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_LBUTTONDOWN:
            /* case ... (list them all here; i'm being lazy) */
            case WM_MBUTTONUP:
                return true;
        }

        return false;
    }
}
于 2012-06-21T16:28:52.517 に答える