我有一个带有普通窗口的Windows窗体应用程序。现在,当我关闭应用程序并重新启动它时,我希望主窗口出现在屏幕上的相同位置,其大小与关闭时的大小相同。
在Windows窗体中是否有一种简单的方法可以记住屏幕位置和窗口大小(如果可能的话,窗口状态)或者是否必须手动完成所有操作?
答案 0 :(得分:55)
如果您将此代码添加到FormClosing
事件处理程序:
if (WindowState == FormWindowState.Maximized)
{
Properties.Settings.Default.Location = RestoreBounds.Location;
Properties.Settings.Default.Size = RestoreBounds.Size;
Properties.Settings.Default.Maximised = true;
Properties.Settings.Default.Minimised = false;
}
else if (WindowState == FormWindowState.Normal)
{
Properties.Settings.Default.Location = Location;
Properties.Settings.Default.Size = Size;
Properties.Settings.Default.Maximised = false;
Properties.Settings.Default.Minimised = false;
}
else
{
Properties.Settings.Default.Location = RestoreBounds.Location;
Properties.Settings.Default.Size = RestoreBounds.Size;
Properties.Settings.Default.Maximised = false;
Properties.Settings.Default.Minimised = true;
}
Properties.Settings.Default.Save();
它将保存当前状态。
然后将此代码添加到表单的OnLoad
处理程序:
if (Properties.Settings.Default.Maximised)
{
WindowState = FormWindowState.Maximized;
Location = Properties.Settings.Default.Location;
Size = Properties.Settings.Default.Size;
}
else if (Properties.Settings.Default.Minimised)
{
WindowState = FormWindowState.Minimized;
Location = Properties.Settings.Default.Location;
Size = Properties.Settings.Default.Size;
}
else
{
Location = Properties.Settings.Default.Location;
Size = Properties.Settings.Default.Size;
}
它将恢复最后一个状态。
它甚至会记住多监视器设置中的哪个监视器应用程序最大化为。
答案 1 :(得分:32)
您需要在应用程序设置中保存窗口位置和大小。这是一个很好的C#article来向您展示如何。
修改强>
您可以在应用程序设置中保存任何您想要的内容。在设置网格的“类型”列中,您可以浏览到任何.NET类型。 WindowState位于System.Windows.Forms中,并列为FormWindowState。 FormStartPosition还有一个属性。
答案 2 :(得分:3)
之前的解决方案对我不起作用。玩了一会儿后,我最终得到了以下代码:
如果屏幕尺寸发生变化(分离式监视器,远程连接......),在屏幕外打开应用程序时,用户将无法进入令人沮丧的状态。
private void MyForm_Load(object sender, EventArgs e)
{
if (Properties.Settings.Default.IsMaximized)
WindowState = FormWindowState.Maximized;
else if (Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(Properties.Settings.Default.WindowPosition)))
{
StartPosition = FormStartPosition.Manual;
DesktopBounds = Properties.Settings.Default.WindowPosition;
WindowState = FormWindowState.Normal;
}
}
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
Properties.Settings.Default.IsMaximized = WindowState == FormWindowState.Maximized;
Properties.Settings.Default.WindowPosition = DesktopBounds;
Properties.Settings.Default.Save();
}
用户设置:
<userSettings>
<WindowsFormsApplication2.Properties.Settings>
<setting name="WindowPosition" serializeAs="String">
<value>0, 0, -1, -1</value>
</setting>
<setting name="IsMaximized" serializeAs="String">
<value>False</value>
</setting>
</WindowsFormsApplication2.Properties.Settings>
</userSettings>
注意:WindowsPosition是故意错误的,因此在首次启动时,应用程序将使用默认位置。
答案 3 :(得分:3)
我尝试了几种不同的方法;这就是最终为我工作的东西。 (在这种情况下 - 首次启动时 - 默认值尚未保留,因此表单将使用设计器中设置的值)
将以下代码添加到表单中:
private void Form1_Load(object sender, EventArgs e)
{
this.RestoreWindowPosition();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
this.SaveWindowPosition();
}
private void RestoreWindowPosition()
{
if (Settings.Default.HasSetDefaults)
{
this.WindowState = Settings.Default.WindowState;
this.Location = Settings.Default.Location;
this.Size = Settings.Default.Size;
}
}
private void SaveWindowPosition()
{
Settings.Default.WindowState = this.WindowState;
if (this.WindowState == FormWindowState.Normal)
{
Settings.Default.Location = this.Location;
Settings.Default.Size = this.Size;
}
else
{
Settings.Default.Location = this.RestoreBounds.Location;
Settings.Default.Size = this.RestoreBounds.Size;
}
Settings.Default.HasSetDefaults = true;
Settings.Default.Save();
}
答案 4 :(得分:2)
Matt - 要将WindowState保存为用户设置,请在“设置”对话框的“类型”下拉列表中,滚动到底部并选择“浏览”。
在“选择类型”对话框中,展开System.Windows.Forms,然后选择“FormWindowState”作为类型。
(抱歉,我没有看到允许我评论评论的按钮......)
答案 5 :(得分:2)
如果你有超过1张表格,你可以使用这样的......
添加此部分所有表单加载无效
var AbbA = Program.LoadFormLocationAndSize(this);
this.Location = new Point(AbbA[0], AbbA[1]);
this.Size = new Size(AbbA[2], AbbA[3]);
this.FormClosing += new FormClosingEventHandler(Program.SaveFormLocationAndSize);
将表单位置和大小保存到app.config xml
public static void SaveFormLocationAndSize(object sender, FormClosingEventArgs e)
{
Form xForm = sender as Form;
Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
if (ConfigurationManager.AppSettings.AllKeys.Contains(xForm.Name))
config.AppSettings.Settings[xForm.Name].Value = String.Format("{0};{1};{2};{3}", xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height);
else
config.AppSettings.Settings.Add(xForm.Name, String.Format("{0};{1};{2};{3}", xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height));
config.Save(ConfigurationSaveMode.Full);
}
从app.config xml
加载表单位置和大小public static int[] LoadFormLocationAndSize(Form xForm)
{
int[] LocationAndSize = new int[] { xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height };
//---//
try
{
Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
var AbbA = config.AppSettings.Settings[xForm.Name].Value.Split(';');
//---//
LocationAndSize[0] = Convert.ToInt32(AbbA.GetValue(0));
LocationAndSize[1] = Convert.ToInt32(AbbA.GetValue(1));
LocationAndSize[2] = Convert.ToInt32(AbbA.GetValue(2));
LocationAndSize[3] = Convert.ToInt32(AbbA.GetValue(3));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
//---//
return LocationAndSize;
}
答案 6 :(得分:1)
您必须在某处手动保存信息。我建议将其作为应用程序设置,将它们存储在用户特定的独立存储中。
加载后,请阅读设置,然后调整/移动表单。
答案 7 :(得分:0)
如果您使用神话般的开源库 - Jot ,您可以忘记繁琐的.settings文件,只需执行此操作:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
还有一个Nuget包,你几乎可以配置有关数据存储方式/时间/位置的所有内容。
免责声明:我是作者,但图书馆是完全开源的(在MIT许可下)。
答案 8 :(得分:0)
我的回答改编自ChrisF♦'s answer,但我已经解决了一件我不喜欢的事情 - 如果窗口在关闭时被最小化,它将在下次启动时显示为最小化。
我的代码通过记住窗口在最小化时是最大化还是正常,并相应地设置持久状态来正确处理该案例。
不幸的是,Winforms没有直接暴露这些信息,所以我需要覆盖WndProc并自己存储。见Check if currently minimized window was in maximized or normal state at the time of minimization
partial class Form1 : Form
{
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SYSCOMMAND)
{
int wparam = m.WParam.ToInt32() & 0xfff0;
if (wparam == SC_MAXIMIZE)
LastWindowState = FormWindowState.Maximized;
else if (wparam == SC_RESTORE)
LastWindowState = FormWindowState.Normal;
}
base.WndProc(ref m);
}
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MAXIMIZE = 0xf030;
private const int SC_RESTORE = 0xf120;
private FormWindowState LastWindowState;
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (WindowState == FormWindowState.Normal)
{
Properties.Settings.Default.WindowLocation = Location;
Properties.Settings.Default.WindowSize = Size;
}
else
{
Properties.Settings.Default.WindowLocation = RestoreBounds.Location;
Properties.Settings.Default.WindowSize = RestoreBounds.Size;
}
if (WindowState == FormWindowState.Minimized)
{
Properties.Settings.Default.WindowState = LastWindowState;
}
else
{
Properties.Settings.Default.WindowState = WindowState;
}
Properties.Settings.Default.Save();
}
private void Form1_Load(object sender, EventArgs e)
{
if (Properties.Settings.Default.WindowSize != new Size(0, 0))
{
Location = Properties.Settings.Default.WindowLocation;
Size = Properties.Settings.Default.WindowSize;
WindowState = Properties.Settings.Default.WindowState;
}
}
答案 9 :(得分:0)
您还可以在关闭表单时将其保存在您的(例如)config.xml中:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
XmlDocument docConfigPath = new XmlDocument();
docConfigPath.Load(XML_Config_Path);
WriteNode(new string[] { "config", "Size", "Top", Top.ToString() }, docConfigPath);
WriteNode(new string[] { "config", "Size", "Left", Left.ToString() }, docConfigPath);
WriteNode(new string[] { "config", "Size", "Height", Height.ToString() }, docConfigPath);
WriteNode(new string[] { "config", "Size", "Width", Width.ToString() }, docConfigPath);
docConfigPath.Save(XML_Config_Path);
}
public static XmlNode WriteNode(string[] sNode, XmlDocument docConfigPath)
{
int cnt = sNode.Length;
int iNode = 0;
string sNodeNameLast = "/" + sNode[0];
string sNodeName = "";
XmlNode[] xN = new XmlNode[cnt];
for (iNode = 1; iNode < cnt - 1; iNode++)
{
sNodeName = "/" + sNode[iNode];
xN[iNode] = docConfigPath.SelectSingleNode(sNodeNameLast + sNodeName);
if (xN[iNode] == null)
{
xN[iNode] = docConfigPath.CreateNode("element", sNode[iNode], "");
xN[iNode].InnerText = "";
docConfigPath.SelectSingleNode(sNodeNameLast).AppendChild(xN[iNode]);
}
sNodeNameLast += sNodeName;
}
if (sNode[cnt - 1] != "")
xN[iNode - 1].InnerText = sNode[cnt - 1];
return xN[cnt - 2];
}
正在加载您的内容:
private void Form1_Load(object sender, EventArgs e)
{
XmlDocument docConfigPath = new XmlDocument();
docConfigPath.Load(XML_Config_Path);
XmlNodeList nodeList = docConfigPath.SelectNodes("config/Size");
Height = ReadNodeInnerTextAsNumber("config/Size/Height", docConfigPath);
Width = ReadNodeInnerTextAsNumber("config/Size/Width", docConfigPath);
Top = ReadNodeInnerTextAsNumber("config/Size/Top", docConfigPath);
Left = ReadNodeInnerTextAsNumber("config/Size/Left", docConfigPath);
}
config.xml应包含以下内容:
<?xml version="1.0" encoding="utf-8"?>
<config>
<Size>
<Height>800</Height>
<Width>1400</Width>
<Top>100</Top>
<Left>280</Left>
</Size>
</config>
答案 10 :(得分:0)
到目前为止,我一直在使用这种方法,并且效果很好。您无需摆弄应用程序设置。而是使用序列化将设置文件写入您的工作目录。我使用JSON,但是您可以使用.NET的本机XML序列化或任何与此相关的序列化。
将这些静态方法放在通用扩展类中。如果您有一个由多个项目引用的通用扩展项目,则可以得到加分:
const string WINDOW_STATE_FILE = "windowstate.json";
public static void SaveWindowState(Form form)
{
var state = new WindowStateInfo
{
WindowLocation = form.Location,
WindowState = form.WindowState
};
File.WriteAllText(WINDOW_STATE_FILE, JsonConvert.SerializeObject(state));
}
public static void LoadWindowState(Form form)
{
if (!File.Exists(WINDOW_STATE_FILE)) return;
var state = JsonConvert.DeserializeObject<WindowStateInfo>(File.ReadAllText(WINDOW_STATE_FILE));
if (state.WindowState.HasValue) form.WindowState = state.WindowState.Value;
if (state.WindowLocation.HasValue) form.Location = state.WindowLocation.Value;
}
public class WindowStateInfo
{
public FormWindowState? WindowState { get; set; }
public Point? WindowLocation { get; set; }
}
您只需要编写一次该代码,就不会再混乱了。现在开始有趣的部分:将下面的代码放入表单的Load
和FormClosing
事件中,如下所示:
private void Form1_Load(object sender, EventArgs e)
{
WinFormsGeneralExtensions.LoadWindowState(this);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
WinFormsGeneralExtensions.SaveWindowState(this);
}
这就是您需要做的。唯一的设置是将这些扩展添加到一个通用类中。之后,只需在表单的代码中添加两行代码即可。
仅当WinForm的应用程序具有单个表单时,此代码才真正起作用。如果它有多种形式要记住其位置,则需要发挥创造力并执行以下操作:
public static void SaveWindowState(Form form)
{
var state = new WindowStateInfo
{
WindowLocation = form.Location,
WindowState = form.WindowState
};
File.WriteAllText($"{form.Name} {WINDOW_STATE_FILE}", JsonConvert.SerializeObject(state));
}
我只保存位置和状态,但是您可以对其进行修改以记住表单的高度和宽度或其他任何形式。只需进行一次更改,它将对调用它的任何应用程序起作用。