我创建了一个表可以继承的类,它处理表单位置,大小和状态.而且效果很好.除了一件事:
当您在与主要屏幕不同的屏幕上最大化应用程序时,位置和大小(在最大化之前)被正确存储,但是当它最大化时(根据其先前的状态),它在我的主监视器上最大化.当我将其恢复到正常状态时,它会转到之前的其他屏幕.当我再次最大化它时,它当然会在正确的屏幕上最大化.
所以我的问题是......我怎样才能制作一个表格,当它最大化时,记住它最大化的屏幕是什么?当表单再次打开时,如何恢复?
我接受了一个非常好的提示,如果在屏幕上如何.但这只是我问题的一部分,所以这是我的解决方案:
负载
首先得到存储Bounds
和WindowState
任何存储.
然后设置Bounds
.
确保Bounds
通过Screen.AllScreens.Any(ø => ø.Bounds.IntersectsWith(Bounds))
或可见MdiParent.Controls.OfType
.
如果没有,就这样做Location = new Point();
.
然后设置窗口状态.
关闭时
商店WindowState
.
如果WindowState
是FormWindowState.Normal
,则存储Bounds
,否则存储RestoreBounds
.
就是这样!=)
因此,正如Oliver所建议的,这里有一些代码.它需要充实,但这可以作为任何想要的人的开始:
负责在某处存储和获取数据.
public sealed class PersistentFormHandler { ///The form identifier in storage. public string Name { get; private set; } ///Gets and sets the window state. (int instead of enum so that it can be in a BI layer, and not require a reference to WinForms) public int WindowState { get; set; } ///Gets and sets the window bounds. (X, Y, Width and Height) public Rectangle WindowBounds { get; set; } ///Dictionary for other values. private readonly DictionaryotherValues; /// /// Instantiates new persistent form handler. /// /// Thewill be used as . /// Default state of the window. /// Default bounds of the window. public PersistentFormHandler(Type windowType, int defaultWindowState, Rectangle defaultWindowBounds) : this(windowType, null, defaultWindowState, defaultWindowBounds) { } /// /// Instantiates new persistent form handler. /// /// Thewill be used as base . /// Use this if you need to separate windows of same type. Will be appended to . /// Default state of the window. /// Default bounds of the window. public PersistentFormHandler(Type windowType, string id, int defaultWindowState, Rectangle defaultWindowBounds) { Name = string.IsNullOrEmpty(id) ? windowType.FullName : windowType.FullName + ":" + id; WindowState = defaultWindowState; WindowBounds = defaultWindowBounds; otherValues = new Dictionary (); } /// /// Looks for previously stored values in database. /// ///False if no previously stored values were found. public bool Load() { // See Note 1 } ////// Stores all values in database /// public void Save() { // See Note 2 } ////// Adds the given ///to the collection of values that will be /// stored in database on . /// Type of object. /// The key you want to use for this value. /// The value to store. public void Set(string key, T value) { // Create memory stream using (var s = new MemoryStream()) { // Serialize value into binary form var b = new BinaryFormatter(); b.Serialize(s, value); // Store in dictionary otherValues[key] = new Binary(s.ToArray()); } } /// /// Same as ///, but uses default( ) as fallback value. /// Type of object /// The key used on. /// The stored object, or the default( public T Get) object if something went wrong. (string key) { return Get(key, default(T)); } /// /// Gets the value identified by the given ///. /// Type of object /// The key used on. /// Value to return if the given could not be found. /// In other words, if you haven't used yet. /// The stored object, or the public T Getobject if something went wrong. (string key, T fallback) { // If we have a value with this key if (otherValues.ContainsKey(key)) { // Create memory stream and fill with binary version of value using (var s = new MemoryStream(otherValues[key].ToArray())) { try { // Deserialize, cast and return. var b = new BinaryFormatter(); return (T)b.Deserialize(s); } catch (InvalidCastException) { // T is not what it should have been // (Code changed perhaps?) } catch (SerializationException) { // Something went wrong during Deserialization } } } // Else return fallback return fallback; } }
注1:在加载方法,你必须寻找先前存储的WindowState
,WindowBounds
和其他值.我们使用SQL Server,并有一个Window
表格,表格中的列Id
,Name
,MachineName
(为Environment.MachineName
), ,UserId
,WindowState
,X
,Y
,.Height
Width
因此,对于每一个窗口,你将有一个排WindowState
,X
,Y
,Height
并Width
为每个用户和机器.另外,我们有一个WindowValues
只有一个外键的表WindowId
,一个Key
类型String
的Value
列和一个类型的列Binary
.如果有找不到的东西,我只是保留默认值并返回false.
注意2:在save方法中,您当然要执行与Load方法相反的操作.为当前用户和计算机创建行Window
以及WindowValues
它们是否已存在.
此类使用上一个类,并为其他表单形成一个方便的基类.
// Should have been abstract, but that makes the the designer crash at the moment... public class PersistentFormBase : Form { private PersistentFormHandler PersistenceHandler { get; set; } private bool handlerReady; protected PersistentFormBase() { // Prevents designer from crashing if (LicenseManager.UsageMode != LicenseUsageMode.Designtime) { Load += persistentFormLoad; FormClosing += persistentFormFormClosing; } } protected event EventHandlerValuesLoaded; protected event EventHandler StoringValues; protected void StoreValue (string key, T value) { if (!handlerReady) throw new InvalidOperationException(); PersistenceHandler.Set(key, value); } protected T GetValue (string key) { if (!handlerReady) throw new InvalidOperationException(); return PersistenceHandler.Get (key); } protected T GetValue (string key, T fallback) { if (!handlerReady) throw new InvalidOperationException(); return PersistenceHandler.Get(key, fallback); } private void persistentFormLoad(object sender, EventArgs e) { // Create PersistenceHandler and load values from it PersistenceHandler = new PersistentFormHandler(GetType(), (int) FormWindowState.Normal, Bounds); PersistenceHandler.Load(); handlerReady = true; // Set size and location Bounds = PersistenceHandler.WindowBounds; // Check if we have an MdiParent if(MdiParent == null) { // If we don't, make sure we are on screen if (!Screen.AllScreens.Any(ø => ø.Bounds.IntersectsWith(Bounds))) Location = new Point(); } else { // If we do, make sure we are visible within the MdiClient area var c = MdiParent.Controls.OfType ().FirstOrDefault(); if(c != null && !c.ClientRectangle.IntersectsWith(Bounds)) Location = new Point(); } // Set state WindowState = Enum.IsDefined(typeof (FormWindowState), PersistenceHandler.WindowState) ? (FormWindowState) PersistenceHandler.WindowState : FormWindowState.Normal; // Notify that values are loaded and ready for getting. var handler = ValuesLoaded; if (handler != null) handler(this, EventArgs.Empty); } private void persistentFormFormClosing(object sender, FormClosingEventArgs e) { // Set common things PersistenceHandler.WindowState = (int) WindowState; PersistenceHandler.WindowBounds = WindowState == FormWindowState.Normal ? Bounds : RestoreBounds; // Notify that values will be stored now, so time to store values. var handler = StoringValues; if (handler != null) handler(this, EventArgs.Empty); // Save values PersistenceHandler.Save(); } }
这就是它.要使用它,表单只会从PersistentFormBase继承.这将自动处理边界和状态.如果还应存储任何其他内容,例如分割器距离,您将监听ValuesLoaded
和StoringValues
事件,并使用GetValue
和StoreValue
方法.
希望这可以帮助别人!如果有,请告诉我.而且,如果您认为可以做得更好或其他什么,请提供一些反馈.我想学习=)