在WinForms 2.0 C#应用程序中,用于在应用程序中保存和恢复表单位置和大小的典型方法是什么?
相关,是否可以在RUNTIME中添加新的用户范围应用程序设置?我完全看到如何在设计时添加设置,这不是问题。但是如果我想在运行时创建一个呢?
更多详情:
我的应用程序是现有Visual FoxPro应用程序的转换。我一直在尝试尽可能多地阅读有关应用程序设置,用户设置等的内容,并明确了解.Net的做事方式,但仍有一些我感到困惑的事情。
在Fox应用程序中,保存的设置存储在注册表中。我的表单是子类,我有基类代码,自动保存表单位置和大小在表单名称的注册表中。每当我创建一个新表单时,我都不需要做任何特殊的事情来获得这种行为;它内置于基类中。我的.Net表格也是子类,这部分运作良好。
在.Net中,我得到的印象是我应该使用用户范围设置来处理用户首选项等内容。表单的大小和位置绝对看起来像用户首选项。但是,我看不到任何方法可以自动将这些设置添加到项目中。换句话说,每次我向项目添加一个新表单(并且它们是100个表单)时,我必须记住添加一个用户范围的应用程序设置,并确保给它与表单相同的名称,即“ FormMySpecialSizePosition“保持大小和位置。我宁愿不记得那样做。这只是运气吗?或者我是否通过尝试使用用户范围设置完全咆哮错误的树?我是否需要创建自己的XML文件来保存设置,以便我可以做任何我想做的事情(即在运行时添加新设置)?或其他什么?
当然这是非常普遍的,有人可以说出“正确”的方式。提前谢谢!
答案 0 :(得分:8)
private void Form1_Load( object sender, EventArgs e )
{
// restore location and size of the form on the desktop
this.DesktopBounds =
new Rectangle(Properties.Settings.Default.Location,
Properties.Settings.Default.Size);
// restore form's window state
this.WindowState = ( FormWindowState )Enum.Parse(
typeof(FormWindowState),
Properties.Settings.Default.WindowState);
}
private void Form1_FormClosing( object sender, FormClosingEventArgs e )
{
System.Drawing.Rectangle bounds = this.WindowState != FormWindowState.Normal ? this.RestoreBounds : this.DesktopBounds;
Properties.Settings.Default.Location = bounds.Location;
Properties.Settings.Default.Size = bounds.Size;
Properties.Settings.Default.WindowState =
Enum.GetName(typeof(FormWindowState), this.WindowState);
// persist location ,size and window state of the form on the desktop
Properties.Settings.Default.Save();
}
答案 1 :(得分:2)
我从某个地方获得了这个代码,但不幸的是当时(很久以前)没有评论我从哪里得到它。
这会将表单信息保存到用户的HKCU注册表中:
using System;
using System.Windows.Forms;
using Microsoft.Win32;
/// <summary>Summary description for FormPlacement.</summary>
public class PersistentForm : System.Windows.Forms.Form
{
private const string DIALOGKEY = "Dialogs";
/// <summary></summary>
protected override void OnCreateControl()
{
LoadSettings();
base.OnCreateControl ();
}
/// <summary></summary>
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
SaveSettings();
base.OnClosing(e);
}
/// <summary>Saves the form's settings.</summary>
public void SaveSettings()
{
RegistryKey dialogKey = Application.UserAppDataRegistry.CreateSubKey(DIALOGKEY);
if (dialogKey != null)
{
RegistryKey formKey = dialogKey.CreateSubKey(this.GetType().ToString());
if (formKey != null)
{
formKey.SetValue("Left", this.Left);
formKey.SetValue("Top", this.Top);
formKey.Close();
}
dialogKey.Close();
}
}
/// <summary></summary>
public void LoadSettings()
{
RegistryKey dialogKey = Application.UserAppDataRegistry.OpenSubKey(DIALOGKEY);
if (dialogKey != null)
{
RegistryKey formKey = dialogKey.OpenSubKey(this.GetType().ToString());
if (formKey != null)
{
this.Left = (int)formKey.GetValue("Left");
this.Top = (int)formKey.GetValue("Top");
formKey.Close();
}
dialogKey.Close();
}
}
}
答案 2 :(得分:2)
在互联网上的任何地方实际上都缺乏单一的,“正常工作”的解决方案,所以这是我自己的创作:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Win32;
using System.ComponentModel;
using System.Security.Cryptography;
namespace nedprod
{
abstract public class WindowSettings
{
private Form form;
public FormWindowState state;
public Point location;
public Size size;
public WindowSettings(Form _form)
{
this.form = _form;
}
internal class MD5Sum
{
static MD5CryptoServiceProvider engine = new MD5CryptoServiceProvider();
private byte[] sum = engine.ComputeHash(BitConverter.GetBytes(0));
public MD5Sum() { }
public MD5Sum(string s)
{
for (var i = 0; i < sum.Length; i++)
sum[i] = byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}
public void Add(byte[] data)
{
byte[] temp = new byte[sum.Length + data.Length];
var i=0;
for (; i < sum.Length; i++)
temp[i] = sum[i];
for (; i < temp.Length; i++)
temp[i] = data[i - sum.Length];
sum=engine.ComputeHash(temp);
}
public void Add(int data)
{
Add(BitConverter.GetBytes(data));
}
public void Add(string data)
{
Add(Encoding.UTF8.GetBytes(data));
}
public static bool operator ==(MD5Sum a, MD5Sum b)
{
if (a.sum == b.sum) return true;
if (a.sum.Length != b.sum.Length) return false;
for (var i = 0; i < a.sum.Length; i++)
if (a.sum[i] != b.sum[i]) return false;
return true;
}
public static bool operator !=(MD5Sum a, MD5Sum b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
try
{
return (bool)(this == (MD5Sum)obj);
}
catch
{
return false;
}
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
for (var i = 0; i < sum.Length; i++)
sb.Append(sum[i].ToString("x2"));
return sb.ToString();
}
}
private MD5Sum screenconfig()
{
MD5Sum md5=new MD5Sum();
md5.Add(Screen.AllScreens.Length); // Hash the number of screens
for(var i=0; i<Screen.AllScreens.Length; i++)
{
md5.Add(Screen.AllScreens[i].Bounds.ToString()); // Hash the dimensions of this screen
}
return md5;
}
public void load()
{
using (RegistryKey r = Registry.CurrentUser.OpenSubKey(@"Software\" + CompanyId() + @"\" + AppId() + @"\Window State\" + form.Name))
{
if (r != null)
{
try
{
string _location = (string)r.GetValue("location"), _size = (string)r.GetValue("size");
state = (FormWindowState)r.GetValue("state");
location = (Point)TypeDescriptor.GetConverter(typeof(Point)).ConvertFromInvariantString(_location);
size = (Size)TypeDescriptor.GetConverter(typeof(Size)).ConvertFromInvariantString(_size);
// Don't do anything if the screen config has since changed (otherwise windows vanish off the side)
if (screenconfig() == new MD5Sum((string) r.GetValue("screenconfig")))
{
form.Location = location;
form.Size = size;
// Don't restore if miminised (it's unhelpful as the user misses the fact it's opened)
if (state != FormWindowState.Minimized)
form.WindowState = state;
}
}
catch (Exception)
{
}
}
}
}
public void save()
{
state = form.WindowState;
if (form.WindowState == FormWindowState.Normal)
{
size = form.Size;
location = form.Location;
}
else
{
size = form.RestoreBounds.Size;
location = form.RestoreBounds.Location;
}
using (RegistryKey r = Registry.CurrentUser.CreateSubKey(@"Software\" + CompanyId()+@"\"+AppId() + @"\Window State\" + form.Name, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
r.SetValue("state", (int) state, RegistryValueKind.DWord);
r.SetValue("location", location.X.ToString() + "," + location.Y.ToString(), RegistryValueKind.String);
r.SetValue("size", size.Width.ToString()+","+size.Height.ToString(), RegistryValueKind.String);
r.SetValue("screenconfig", screenconfig().ToString(), RegistryValueKind.String);
}
}
abstract protected string CompanyId();
abstract protected string AppId();
}
}
此实现将表单的位置和大小存储在HKCU / Software /&lt; CompanyId()&gt; /&lt; AppId()&gt; / Window State /&lt; form name&gt;中。如果监视器配置发生变化,它将不会恢复设置,以防止窗口从屏幕恢复。
显然,这不能处理同一表单的多个实例。我还特别禁用了最小化恢复,但这是一个简单的源代码修复。
以上内容旨在放入自己的.cs文件中,永远不会再次触及。你必须像这样实例化一个本地命名空间副本(在Program.cs或你的插件主.cs文件或任何地方):
namespace <your app/plugin namespace name>
{
public class WindowSettings : nedprod.WindowSettings
{
public WindowSettings(Form form) : base(form) { }
protected override string CompanyId() { return "<your company name>"; }
protected override string AppId() { return "<your app name>"; }
}
....
现在,您在主命名空间中有一个非抽象实例化。因此,要使用,请将其添加到要保存和还原的表单中:
private void IssuesForm_FormClosing(object sender, FormClosingEventArgs e)
{
new WindowSettings(this).save();
}
private void IssuesForm_Load(object sender, EventArgs e)
{
new WindowSettings(this).load();
}
显然可以根据自己的目的自定义。不作任何明示或暗示的保证。使用风险由我自行承担 - 我不承担任何版权。
尼尔
答案 3 :(得分:0)
您可以创建一个具有常用功能的基本表单类,例如记住位置和大小以及从该基类继承。
public class myForm : Form {
protected override void OnLoad(){
//load the settings and apply them
base.OnLoad();
}
protected override void OnClose(){
//save the settings
base.OnClose();
}
}
then for the other forms:
public class frmMainScreen : myForm {
// you get the settings for free ;)
}
嗯,这样的事情;)
答案 4 :(得分:0)
我和你在同一条船上,因为我有多种形式(MDI儿童,在我的情况下),我想保留每个用户的位置和大小。根据我的研究,不支持在运行时创建应用程序设置。 (见this blog entry) 但是,您不必将所有内容都粘贴在主设置文件中。您可以将设置文件添加到项目(explained here in the MSDN)并通过Properties.Settings对象使用它。这不会减轻必须记住为每个表单创建新settig的痛苦,但至少它会将它们保持在一起,而不会使主应用程序设置混乱。
至于使用基类来检索设置......我不知道你是否可以在那里做到。我想(也可能会)做的是命名每个属性,然后使用Me.GetType()。ToString()(我在VB中工作)来组合我想要在Load()事件中检索的属性的名称每种形式。
答案 5 :(得分:0)
我只是将它流式传输到一个单独的XML
文件 - 快速而肮脏,可能不是你所追求的:
Dim winRect As String() = util.ConfigFile.GetUserConfigInstance().GetValue("appWindow.rect").Split(",")
Dim winState As String = util.ConfigFile.GetUserConfigInstance().GetValue("appWindow.state")
Me.WindowState = FormWindowState.Normal
Me.Left = CType(winRect(0), Integer)
Me.Top = CType(winRect(1), Integer)
Me.Width = CType(winRect(2), Integer)
Me.Height = CType(winRect(3), Integer)
If winState = "maximised" Then
Me.WindowState = FormWindowState.Maximized
End If
和
Dim winState As String = "normal"
If Me.WindowState = FormWindowState.Maximized Then
winState = "maximised"
ElseIf Me.WindowState = FormWindowState.Minimized Then
winState = "minimised"
End If
If Me.WindowState = FormWindowState.Normal Then
Dim winRect As String = CType(Me.Left, String) & "," & CType(Me.Top, String) & "," & CType(Me.Width, String) & "," & CType(Me.Height, String)
' only save window rectangle if its not maximised/minimised
util.ConfigFile.GetUserConfigInstance().SetValue("appWindow.rect", winRect)
End If
util.ConfigFile.GetUserConfigInstance().SetValue("appWindow.state", winState)
答案 6 :(得分:0)
以下是一些相关链接:
Saving out a Form's Size and Location using the Application Settings feature
答案 7 :(得分:0)
这是我使用的代码。
private void SaveWindowPosition()
{
Rectangle rect = (WindowState == FormWindowState.Normal) ?
new Rectangle(DesktopBounds.Left, DesktopBounds.Top, DesktopBounds.Width, DesktopBounds.Height) :
new Rectangle(RestoreBounds.Left, RestoreBounds.Top, RestoreBounds.Width, RestoreBounds.Height);
RegistrySettings.SetSetting("WindowPosition", String.Format("{0},{1},{2},{3},{4}",
(int)this.WindowState,
rect.Left, rect.Top, rect.Width, rect.Height));
}
private void RestoreWindowPosition()
{
try
{
string s = RegistrySettings.GetSetting("WindowPosition", String.Empty) as string;
if (s != null)
{
List<int> settings = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(v => int.Parse(v)).ToList();
if (settings.Count == 5)
{
this.SetBounds(
settings[1],
settings[2],
settings[3],
settings[4]);
this.WindowState = (FormWindowState)settings[0];
}
}
}
catch { /* Just leave current position if error */ }
}
我还在文章Saving and Restoring a Form's Window Position中提供了此代码。