当用户点击按钮时,它会启动一些任务。我不想阻止主应用程序线程,所以我在一个单独的线程中运行它。现在我需要禁止用户单击按钮,直到我的任务完成。
我可以设置
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
}
答案 0 :(得分:1)
与往常一样,UI应该以这样的方式呈现:用户了解应用程序正在执行的操作以及使用UI元素should talk to the user
。
正如Adam Houldsworth建议我也希望保持button
被禁用或启用但我还建议按钮的标题应该向用户传达这样的信息:新的处理正在进行中线程开始..所以button
的标题应立即更改为"Processing..Please wait..."
(除了被禁用或甚至你想保持启用),然后如果你保持启用按钮只是检查其click
事件上的按钮标题(或isProcessing bool标志),如果它显示“Processing..Please wait ...”或(isProcessing == true)则返回。
许多帮助用户上传files/images
的网站会将Upload
按钮的标题更改为"Uploading..Please wait..."
,以通知用户等到上传完成,此外还有一些网站{{1}上传按钮,以便用户无法再次点击上传按钮。
当线程完成长时间处理时,您还需要将标题恢复为正常。
可能还有其他先进的方法,但想法是尽可能保持简单和基本。
在Threading in Windows Forms上查看此示例,该示例显示在多线程时禁用按钮。
答案 1 :(得分: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组件优雅地实现[无麻烦代码]。只需复制粘贴和HIT 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;
}
}
}
答案 2 :(得分:0)
正如其他答案中所提到的,可能有一个比你要求的更好的解决方案。
要直接回答您的问题,请查看IMessageFilter interface
创建过滤器以禁止显示您不需要的鼠标消息,并在必要时使用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;
}
}