如何在WinForms中忽略用户单击?
当用户单击一个按钮时,它会启动一些任务。我不想阻止主应用程序线程,所以我在一个单独的线程中运行它。现在我需要禁止用户在我的任务完成之前单击按钮 我可以设定如何在WinForms中忽略用户单击?,winforms,multithreading,background-process,messages,Winforms,Multithreading,Background Process,Messages,当用户单击一个按钮时,它会启动一些任务。我不想阻止主应用程序线程,所以我在一个单独的线程中运行它。现在我需要禁止用户在我的任务完成之前单击按钮 我可以设定 button.Enabled = false; ,但我正在寻找一些方法来忽略对它的点击 我可以添加一些签入单击事件处理程序: if (executingThread != null) return; ,但我必须为每个处理者做这件事,这是个坏主意 我知道有一些方法可以过滤用户的消息。你能告诉我怎么做吗?我不想过滤掉所有消息,因为其他一些按钮
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
}
和往常一样,UI的呈现方式应该让用户理解应用程序在做什么,并且
应该使用UI元素与用户交谈
正如Adam Houldsworth所建议的那样,我也希望保持按钮处于禁用或启用状态,但我还建议按钮的标题应向用户传达一个信息,即新线程启动时长处理正在进行中。。因此按钮的标题应立即更改对于类似于“处理..请等待…”
(除了被禁用或即使您想保持启用),然后如果您保持按钮启用,只需检查按钮上的按钮标题(或isProcessing bool标志),单击事件返回,如果它说“处理..请等待…”或(isProcessing==true)
许多网站帮助用户上传文件/图像
将上传
按钮的标题更改为“上传..请稍候…”
通知用户等待上传完成,此外,一些网站还禁用上传按钮,以便用户无法再次单击上传按钮
当线程完成长时间处理时,您还需要将标题恢复为正常
可能还有其他先进的方法,但我们的想法是让它尽可能简单和基本
查看此示例,其中显示了在多线程时禁用按钮。+1了解到目前为止的所有建议。正如CSharpVJ
所建议的-我的想法是通过更改按钮的标题来额外通知用户,使UI设计更直观
这可以通过Winforms中的Backgroundworker组件优雅地实现[No Hassels code]。只需复制粘贴并点击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;
}
}
}
使用System.ComponentModel;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类表单3:表单
{
私人背景工人;
公共表格3()
{
初始化组件();
InitWorker();
}
私有void InitWorker()
{
如果(_worker!=null)
{
_worker.Dispose();
}
_worker=新的后台工作人员
{
WorkerReportsProgress=true,
WorkerSupportsScanCellation=真
};
_worker.DoWork+=DoWork;
_worker.RunWorkerCompleted+=RunWorkerCompleted;
_worker.ProgressChanged+=ProgressChanged;
}
///在这里做耗时的工作。。。
无效DoWork(对象发送方,DoWorkEventArgs e)
{
int highestPercentageReached=0;
如果(_worker.CancellationPending)
{
e、 取消=真;
}
其他的
{
双i=0.0d;
对于(i=0;i最高百分比)
{
highestPercentageReached=完成百分比;
//报告进度
_工人报告进度(完成百分比);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
按钮1.启用=真;
如果(如已取消)
{
//向用户显示任务已完成的消息
//取消
label1.Text=“已取消操作”;
}
否则如果(例如错误!=null)
{
//对这个错误做点什么
}
按钮1.Text=“重新开始”;
}
void ProgressChanged(对象发送方,progresschangedventargs e)
{
label1.Text=string.Format(“结果{0}:百分比{1}”,e.UserState,e.ProgressPercentage);
}
private void OnStartClick(对象发送者,System.EventArgs e)
{
_worker.RunWorkerAsync();
按钮1.Text=“处理已开始…”;
按钮1.启用=错误;
}
}
}
如其他答案所述,可能有比您所要求的更好的解决方案
要直接回答您的问题,请查看
创建筛选器以使其抑制不需要的鼠标消息,必要时使用Application.AddMessageFilter()
应用它
以下内容(这可能需要编译…):
CSharpVJ,Adam Houldsworth感谢您的回复,但我需要我所问的。告诉用户长进程运行、将游标更改为WaitCursor等等-很清楚。我可以检查正在执行的线程,而不是检查按钮的标题,这是个坏主意。
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;
}
}