Windows 表单 - 等待按钮点击 return 执行 (Application.DoEvents()?)
Windows Forms - Waiting for a button click to return to execution (Application.DoEvents()?)
这是我第一次尝试使用 Windows 表单实现 GUI。
我有一个特定于我的项目的问题,但我将使用另一个例子来强调我的挫败感:
目标: 循环遍历文件目录并提示用户是否重命名其文件夹的程序。
假设我们有一个按钮:
Start Service
一旦用户点击此按钮,程序就会执行循环访问目录的所有魔法。假设我们有一个目录:
A
- 1
- 2
B
-1
假设我们只循环遍历顶级目录,我们在循环中遇到的第一个文件夹是 'A'。
我想要的是执行流程在这里停止。
'Start Service button'上方还有两个按钮:
Rename
Ignore
我希望在选择这两个按钮之一之前停止执行,然后根据用户的选择发生某些事情。
我在处理其中的 'halting' 部分时遇到了问题。我尝试的最后一件事:
ManualResetEvent mre = new ManualResetEvent(false);
正在启动服务:
for (... some loop that goes through the directory){
var x = somethign[1] // "A";
mre.WaitOne();
}
在重命名按钮单击事件的函数中:
//do some things
mre.Set();
但是我的表单冻结并且无法正常工作。我确信这是可能的,但我似乎无法弄清楚。谁能指出我正确的方向?
您需要创建一个新线程来放入逻辑,现在您的 UI 正在阻塞,因为您正在主线程中执行此操作。
所以过程是:
- 创建 ManualResetEvent
- 创建方法来保存将迭代、读取目录结构并允许修改的逻辑。
- 运行 为您刚刚创建的方法创建一个新线程。
- 通过调用和委托建立与主线程的通信(有多种方法可以做到这一点)
入门示例代码:
Pause/Resume thread whith AutoResetEvent
完整的工作示例
Form1.cs
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace ThreadLockExample
{
public partial class Form1 : Form
{
public static ManualResetEvent mre = new ManualResetEvent(true);
public Form1()
{
InitializeComponent();
}
private void btnStartService_Click(object sender, EventArgs e)
{
btnRename.Enabled = false;
btnIgnore.Enabled = false;
Thread thread = new Thread(CheckFiles);
thread.Start();
}
public void CheckFiles()
{
var files = Directory.GetFiles("c:\"); //Demo Purposes...
foreach (var file in files)
{
Thread.Sleep(500);
mre.Reset();
//Since we are not in our main thread, we need to communicate
//with the static form variable via an invoke on that Form object.
this.Invoke((Action) delegate
{
Program.form1.lstDirectories.Items.Add(file);
Program.form1.lstDirectories.Refresh();
Program.form1.btnRename.Enabled = true;
Program.form1.btnIgnore.Enabled = true;
});
mre.WaitOne();
}
}
private void btnRename_Click(object sender, EventArgs e)
{
//Do whatever you need to do here, then resume thread.
mre.Set();
}
private void btnIgnore_Click(object sender, EventArgs e)
{
//Do whatever you need to do here, then resume thread.
mre.Set();
}
}
}
Program.cs
using System;
using System.Windows.Forms;
namespace ThreadLockExample
{
static class Program
{
public static Form1 form1 = new Form1();
[MTAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(form1);
}
}
}
这是另一个例子:
public partial class Form1 : Form
{
private bool Rename = false;
private string RenameTo = "";
private BackgroundWorker bgw;
private ManualResetEvent mre = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += Bgw_DoWork;
bgw.ProgressChanged += Bgw_ProgressChanged;
bgw.RunWorkerCompleted += Bgw_RunWorkerCompleted;
this.Load += Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
btnIgnore.Enabled = false;
btnRename.Enabled = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
btnStart.Enabled = false;
progressBar1.Value = 0;
progressBar1.Enabled = true;
bgw.RunWorkerAsync(fbd.SelectedPath);
}
}
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
string folder = (string)e.Argument;
DirectoryInfo di = new DirectoryInfo(folder);
DirectoryInfo[] folders = di.GetDirectories();
for(int i = 0; i < folders.Length; i++)
{
mre.Reset();
Rename = false;
DirectoryInfo subFolder = folders[i];
bgw.ReportProgress((int)((decimal)(i + 1) / (decimal)folders.Length * (decimal)100), subFolder.Name);
mre.WaitOne();
if (Rename)
{
Console.WriteLine("Rename `" + subFolder.Name + "` to `" + RenameTo + "`");
}
}
}
private void Bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
lblFolder.Text = (string)e.UserState;
btnIgnore.Enabled = true;
btnRename.Enabled = true;
}
private void btnIgnore_Click(object sender, EventArgs e)
{
btnIgnore.Enabled = false;
btnRename.Enabled = false;
mre.Set();
}
private void btnRename_Click(object sender, EventArgs e)
{
string newName = txtFolder.Text.Trim();
if (newName.Length > 0)
{
Rename = true;
RenameTo = newName;
btnIgnore.Enabled = false;
btnRename.Enabled = false;
mre.Set();
}
else
{
MessageBox.Show("Please enter a New Folder Name first!");
}
}
private void Bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done!");
btnStart.Enabled = true;
btnIgnore.Enabled = false;
btnRename.Enabled = false;
progressBar1.Enabled = false;
}
}
这是我第一次尝试使用 Windows 表单实现 GUI。
我有一个特定于我的项目的问题,但我将使用另一个例子来强调我的挫败感:
目标: 循环遍历文件目录并提示用户是否重命名其文件夹的程序。
假设我们有一个按钮:
Start Service
一旦用户点击此按钮,程序就会执行循环访问目录的所有魔法。假设我们有一个目录:
A
- 1
- 2
B
-1
假设我们只循环遍历顶级目录,我们在循环中遇到的第一个文件夹是 'A'。
我想要的是执行流程在这里停止。
'Start Service button'上方还有两个按钮:
Rename
Ignore
我希望在选择这两个按钮之一之前停止执行,然后根据用户的选择发生某些事情。
我在处理其中的 'halting' 部分时遇到了问题。我尝试的最后一件事:
ManualResetEvent mre = new ManualResetEvent(false);
正在启动服务:
for (... some loop that goes through the directory){
var x = somethign[1] // "A";
mre.WaitOne();
}
在重命名按钮单击事件的函数中:
//do some things
mre.Set();
但是我的表单冻结并且无法正常工作。我确信这是可能的,但我似乎无法弄清楚。谁能指出我正确的方向?
您需要创建一个新线程来放入逻辑,现在您的 UI 正在阻塞,因为您正在主线程中执行此操作。
所以过程是:
- 创建 ManualResetEvent
- 创建方法来保存将迭代、读取目录结构并允许修改的逻辑。
- 运行 为您刚刚创建的方法创建一个新线程。
- 通过调用和委托建立与主线程的通信(有多种方法可以做到这一点)
入门示例代码: Pause/Resume thread whith AutoResetEvent
完整的工作示例
Form1.cs
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace ThreadLockExample
{
public partial class Form1 : Form
{
public static ManualResetEvent mre = new ManualResetEvent(true);
public Form1()
{
InitializeComponent();
}
private void btnStartService_Click(object sender, EventArgs e)
{
btnRename.Enabled = false;
btnIgnore.Enabled = false;
Thread thread = new Thread(CheckFiles);
thread.Start();
}
public void CheckFiles()
{
var files = Directory.GetFiles("c:\"); //Demo Purposes...
foreach (var file in files)
{
Thread.Sleep(500);
mre.Reset();
//Since we are not in our main thread, we need to communicate
//with the static form variable via an invoke on that Form object.
this.Invoke((Action) delegate
{
Program.form1.lstDirectories.Items.Add(file);
Program.form1.lstDirectories.Refresh();
Program.form1.btnRename.Enabled = true;
Program.form1.btnIgnore.Enabled = true;
});
mre.WaitOne();
}
}
private void btnRename_Click(object sender, EventArgs e)
{
//Do whatever you need to do here, then resume thread.
mre.Set();
}
private void btnIgnore_Click(object sender, EventArgs e)
{
//Do whatever you need to do here, then resume thread.
mre.Set();
}
}
}
Program.cs
using System;
using System.Windows.Forms;
namespace ThreadLockExample
{
static class Program
{
public static Form1 form1 = new Form1();
[MTAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(form1);
}
}
}
这是另一个例子:
public partial class Form1 : Form
{
private bool Rename = false;
private string RenameTo = "";
private BackgroundWorker bgw;
private ManualResetEvent mre = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += Bgw_DoWork;
bgw.ProgressChanged += Bgw_ProgressChanged;
bgw.RunWorkerCompleted += Bgw_RunWorkerCompleted;
this.Load += Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
btnIgnore.Enabled = false;
btnRename.Enabled = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
btnStart.Enabled = false;
progressBar1.Value = 0;
progressBar1.Enabled = true;
bgw.RunWorkerAsync(fbd.SelectedPath);
}
}
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
string folder = (string)e.Argument;
DirectoryInfo di = new DirectoryInfo(folder);
DirectoryInfo[] folders = di.GetDirectories();
for(int i = 0; i < folders.Length; i++)
{
mre.Reset();
Rename = false;
DirectoryInfo subFolder = folders[i];
bgw.ReportProgress((int)((decimal)(i + 1) / (decimal)folders.Length * (decimal)100), subFolder.Name);
mre.WaitOne();
if (Rename)
{
Console.WriteLine("Rename `" + subFolder.Name + "` to `" + RenameTo + "`");
}
}
}
private void Bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
lblFolder.Text = (string)e.UserState;
btnIgnore.Enabled = true;
btnRename.Enabled = true;
}
private void btnIgnore_Click(object sender, EventArgs e)
{
btnIgnore.Enabled = false;
btnRename.Enabled = false;
mre.Set();
}
private void btnRename_Click(object sender, EventArgs e)
{
string newName = txtFolder.Text.Trim();
if (newName.Length > 0)
{
Rename = true;
RenameTo = newName;
btnIgnore.Enabled = false;
btnRename.Enabled = false;
mre.Set();
}
else
{
MessageBox.Show("Please enter a New Folder Name first!");
}
}
private void Bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done!");
btnStart.Enabled = true;
btnIgnore.Enabled = false;
btnRename.Enabled = false;
progressBar1.Enabled = false;
}
}