C# Windows窗体桌面应用程序栏没有响应
我会在标题中给出一些关于实际问题的指示,但我不知道它是什么。我所能说的是,在实现appbar时,表单在我尝试为变量赋值后不再响应,从而导致我必须停止调试并重新启动计算机以恢复桌面工作区。下面的代码中记录了错误的位置,我只列出了错误点的代码。这里有什么我看不到的明显的东西吗C# Windows窗体桌面应用程序栏没有响应,c#,winforms,desktop-application,C#,Winforms,Desktop Application,我会在标题中给出一些关于实际问题的指示,但我不知道它是什么。我所能说的是,在实现appbar时,表单在我尝试为变量赋值后不再响应,从而导致我必须停止调试并重新启动计算机以恢复桌面工作区。下面的代码中记录了错误的位置,我只列出了错误点的代码。这里有什么我看不到的明显的东西吗 static class Program { [STAThread] static void Main() { Application.EnableVisualStyles();
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public partial class Form1 : AppBar
{
public Form1() : base()
{
InitializeComponent();
}
//This is a button on the test form.
//When clicked, the form should become a desktop application bar
//docked to the top of the desktop.
private void t_Click(object sender, EventArgs e)
{
base.SET_APPBAR();
}
}
public class AppBar : Form
{
protected internal Size appbarSize;
protected internal Point appbarLocation;
protected internal bool appbarMode;
private EDGES appbarEdge;
private RECT appbarRect;
private uint ID { get; private set; }
private IntPtr HANDLE { get; private set; }
//constructor
public AppBar() : base () //no issues here
{
appbarEdge = EDGES.ABE_TOP;
appbarRect = new RECT();
ID = 0;
HANDLE = this.Handle;
appbarMode = false;
}
protected internal void SET_APPBAR()
{
if (IS_NEW())
{
QUERY_AND_SET_POSITION(ref appbarRect); //Never get to here
}
}
private bool IS_NEW()
{
if (appbarMode) //so far, so good
{
return false;
}
while (ID == 0)
{
CREATE_ID(); //ID is created, I have verified this.
}
this.FormBorderStyle = FormBorderStyle.FixedToolWindow; //BorderStyle does change
appbarSize = this.Size; //Size is correct
appbarLocation = this.Location; //still no issues
NEW(); //this is where the error begins (see code further down)
return appbarMode; //Never get here
}
private void CREATE_ID()
{
ID = Hooks.RegisterWindowMessage(Guid.NewGuid().ToString());
}
private void QUERY_AND_SET_POSITION(ref RECT appbarRect)
{
SET_APPBAR_SIZE(ref appbarRect);
QUERY_POS(ref appbarRect);
APPBAR_RESIZE(ref appbarRect);
SET_POS(ref appbarRect);
this.Location = new Point(appbarRect.left, appbarRect.top);
appbarSize = new Size(appbarRect.right - appbarRect.left, appbarRect.bottom - appbarRect.top);
this.Size = appbarSize;
}
private void SET_APPBAR_SIZE(ref RECT appbarRect)
{
switch (appbarEdge)
{
case (EDGES.ABE_BOTTOM):
appbarRect.left = 0;
appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
appbarRect.top = SystemInformation.PrimaryMonitorSize.Height - appbarSize.Height;
appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
break;
case (EDGES.ABE_LEFT):
appbarRect.left = 0;
appbarRect.right = appbarSize.Width;
appbarRect.top = 0;
appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
break;
case (EDGES.ABE_RIGHT):
appbarRect.left = SystemInformation.PrimaryMonitorSize.Width - appbarSize.Width;
appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
appbarRect.top = 0;
appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
break;
default:
appbarRect.left = 0;
appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
appbarRect.top = SystemInformation.WorkingArea.Top;
appbarRect.bottom = appbarSize.Height;
break;
}
}
private void APPBAR_RESIZE(ref RECT appbarRect)
{
switch (appbarEdge)
{
case (EDGES.ABE_TOP):
appbarRect.bottom = appbarRect.top + appbarSize.Height;
break;
case (EDGES.ABE_BOTTOM):
appbarRect.top = appbarRect.bottom - appbarSize.Height;
break;
case (EDGES.ABE_LEFT):
appbarRect.right = appbarRect.left + appbarSize.Width;
break;
case (EDGES.ABE_RIGHT):
appbarRect.left = appbarRect.right - appbarSize.Width;
break;
}
}
private void APPBAR_CALLBACK(ref Message apiMessage)
{
switch ((NOTIFICATIONS)(uint)apiMessage.WParam)//? on int vs uint here
{
case (NOTIFICATIONS.ABN_STATECHANGE):
STATE_CHANGE();
break;
case (NOTIFICATIONS.ABN_POSCHANGED):
QUERY_AND_SET_POSITION(ref appbarRect);
break;
case (NOTIFICATIONS.ABN_FULLSCREENAPP):
if ((int)apiMessage.LParam != 0)
{
this.SendToBack();
this.TopMost = false;
}
else
{
STATE_CHANGE();
}
break;
case (NOTIFICATIONS.ABN_WINDOWARRANGE):
//first call
if ((int)apiMessage.LParam != 0)
{
this.Visible = false;
}
//second call
else
{
this.Visible = true;
}
break;
}
}
protected override void WndProc(ref Message apiMessage)
{
if (appbarMode)
{
if (HANDLE == apiMessage.HWnd)
{
APPBAR_CALLBACK(ref apiMessage);
}
else if (apiMessage.Msg == (int)API_MESSAGES.WM_ACTIVATE)
{
ACTIVATE();
}
else if (apiMessage.Msg == (int)API_MESSAGES.WM_WINDOWPOSCHANGED)
{
WINDOW_POS_CHANGED();
}
}
base.WndProc(ref apiMessage);
}
private void NEW()
{
APPBARDATA data = new APPBARDATA(); //no apparent issue
data.cbSize = (uint)Marshal.SizeOf(data); //no apparent issue
data.hWnd = HANDLE; //no apparent issue
data.uCallbackMessage = ID; //no apparent issue
if (Hooks.SHAppBarMessage((uint)DWORD.ABM_NEW, ref data) != 0) //SHAppBar returns 1 (true)
{
//no issue if I were to place a MessageBox here
appbarMode = true; // why in the world is this causing an issue?????
//can't do anything from this point
}
}
}
public static class Hooks
{
[DllImport("shell32.dll", EntryPoint = "SHAppBarMessage")]
public static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);
[DllImport("user32.dll", EntryPoint = "RegisterWindowMessage")]
public static extern uint RegisterWindowMessage(
[MarshalAs(UnmanagedType.LPTStr)]
string lpString);
}
无论发生什么问题,我都无法单击任何按钮或关闭表单。桌面工作区总是适当调整大小。希望所有这些对某人来说都是有意义的。感谢您提前查看。问题在于您正在UI线程中执行长时间运行的操作。这将阻止UI线程并阻止它执行任何其他操作(绘制更改、响应按钮单击或鼠标移动事件等) 您需要在后台线程中执行长时间运行的操作。虽然您可以手动执行此操作,但最好使用
BackgroundWorker
,因为它正是为此应用程序而设计的。它不仅可以为您创建/配置后台线程,还提供了简单易用的机制,用于在后台任务完成时更新UI、在任务运行时随进度更新UI等
请注意,在后台线程中,您无法访问UI元素;需要从UI线程访问它们。在开始后台任务之前,您应该将从UI获取信息的所有代码移动到(将其保存在局部变量或字段中以备以后使用),并且应该将所有代码移动到最后,以便根据结果更新UI(如果使用
BackgroundWorker
,则在RunWorkerCompleted
事件中)。除了BackgroundWorker
的DoWork
之外的所有事件都在UI线程中执行,因此可以访问UI控件。问题在于您正在UI线程中执行长时间运行的操作。这将阻止UI线程并阻止它执行任何其他操作(绘制更改、响应按钮单击或鼠标移动事件等)
您需要在后台线程中执行长时间运行的操作。虽然您可以手动执行此操作,但最好使用BackgroundWorker
,因为它正是为此应用程序而设计的。它不仅可以为您创建/配置后台线程,还提供了简单易用的机制,用于在后台任务完成时更新UI、在任务运行时随进度更新UI等
请注意,在后台线程中,您无法访问UI元素;需要从UI线程访问它们。在开始后台任务之前,您应该将从UI获取信息的所有代码移动到(将其保存在局部变量或字段中以备以后使用),并且应该将所有代码移动到最后,以便根据结果更新UI(如果使用
BackgroundWorker
,则在RunWorkerCompleted
事件中)。除了BackgroundWorker
的DoWork
之外的所有事件都在UI线程中执行,因此可以访问您的UI控件。hehehehe。我想我未来发布的关于“实现多线程”的预发布说明只是排在了前面。谢谢你的洞察力。如果有人关注这一点,你也可能对这条老线索感兴趣:呵呵。我想我未来发布的关于“实现多线程”的预发布说明只是排在了前面。感谢您提供的见解。如果有人关注此内容,您可能也会对此旧线程感兴趣: