フォームが継承できるクラスを作成し、フォームの場所、サイズ、および状態を処理します。そして、それはうまく機能します。1つのことを除いて:
メイン画面とは異なる画面でアプリケーションを最大化すると、(最大化する前の) 場所とサイズは正しく保存されますが、(以前の状態に従って) 最大化すると、メイン モニターで最大化されます。その後、通常の状態に戻すと、以前の別の画面に移動します。もう一度最大化すると、もちろん正しい画面で最大化されました。
だから私の質問は...どうすればフォームを作成できますか?最大化されたときに、どの画面で最大化されたかを覚えていますか? また、フォームが再び開いたときにそれを復元するにはどうすればよいですか?
問題に対する完全な解決策の種類
画面に表示されている場合の方法について非常に良いヒントが含まれている回答を受け入れました。しかし、それは私の問題の一部に過ぎなかったので、ここに私の解決策があります:
ロード中
- 最初に保存され
Bounds
、WindowState
任意のストレージから取得します。 - を設定し
Bounds
ます。 - または
Bounds
のいずれかで表示されていることを確認してください。Screen.AllScreens.Any(ø => ø.Bounds.IntersectsWith(Bounds))
MdiParent.Controls.OfType<MdiClient>().First().ClientRectangle.IntersectsWith(Bounds)
- そうでない場合は、実行してください
Location = new Point();
。
- そうでない場合は、実行してください
- 次に、ウィンドウの状態を設定します。
閉店時
- 保存し
WindowState
ます。 - である場合
WindowState
はFormWindowState.Normal
保存Bounds
し、そうでない場合は保存しRestoreBounds
ます。
以上です!=)
いくつかのサンプルコード
したがって、 Oliverが示唆するように、ここにいくつかのコードがあります。肉付けする必要がありますが、これは、次のことを望む人のための出発点として使用できます。
PersistentFormHandler
データをどこかに保存して取得します。
public sealed class PersistentFormHandler
{
/// <summary>The form identifier in storage.</summary>
public string Name { get; private set; }
/// <summary>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)</summary>
public int WindowState { get; set; }
/// <summary>Gets and sets the window bounds. (X, Y, Width and Height)</summary>
public Rectangle WindowBounds { get; set; }
/// <summary>Dictionary for other values.</summary>
private readonly Dictionary<string, Binary> otherValues;
/// <summary>
/// Instantiates new persistent form handler.
/// </summary>
/// <param name="windowType">The <see cref="Type.FullName"/> will be used as <see cref="Name"/>.</param>
/// <param name="defaultWindowState">Default state of the window.</param>
/// <param name="defaultWindowBounds">Default bounds of the window.</param>
public PersistentFormHandler(Type windowType, int defaultWindowState, Rectangle defaultWindowBounds)
: this(windowType, null, defaultWindowState, defaultWindowBounds) { }
/// <summary>
/// Instantiates new persistent form handler.
/// </summary>
/// <param name="windowType">The <see cref="Type.FullName"/> will be used as base <see cref="Name"/>.</param>
/// <param name="id">Use this if you need to separate windows of same type. Will be appended to <see cref="Name"/>.</param>
/// <param name="defaultWindowState">Default state of the window.</param>
/// <param name="defaultWindowBounds">Default bounds of the window.</param>
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<string, Binary>();
}
/// <summary>
/// Looks for previously stored values in database.
/// </summary>
/// <returns>False if no previously stored values were found.</returns>
public bool Load()
{
// See Note 1
}
/// <summary>
/// Stores all values in database
/// </summary>
public void Save()
{
// See Note 2
}
/// <summary>
/// Adds the given <paramref key="value"/> to the collection of values that will be
/// stored in database on <see cref="Save"/>.
/// </summary>
/// <typeparam key="T">Type of object.</typeparam>
/// <param name="key">The key you want to use for this value.</param>
/// <param name="value">The value to store.</param>
public void Set<T>(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());
}
}
/// <summary>
/// Same as <see cref="Get{T}(string,T)"/>, but uses default(<typeparamref name="T"/>) as fallback value.
/// </summary>
/// <typeparam name="T">Type of object</typeparam>
/// <param name="key">The key used on <see cref="Set{T}"/>.</param>
/// <returns>The stored object, or the default(<typeparamref name="T"/>) object if something went wrong.</returns>
public T Get<T>(string key)
{
return Get(key, default(T));
}
/// <summary>
/// Gets the value identified by the given <paramref name="key"/>.
/// </summary>
/// <typeparam name="T">Type of object</typeparam>
/// <param name="key">The key used on <see cref="Set{T}"/>.</param>
/// <param name="fallback">Value to return if the given <paramref name="key"/> could not be found.
/// In other words, if you haven't used <see cref="Set{T}"/> yet.</param>
/// <returns>The stored object, or the <paramref name="fallback"/> object if something went wrong.</returns>
public T Get<T>(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
load メソッドでは、以前に保存されたWindowBounds
およびその他の値を探す必要があります。SQL Server を使用し、 、、( の場合)、、、、、のWindow
列を持つテーブルがあります。したがって、ウィンドウごとに、ユーザーとマシンごとに 、、、を含む 1 つの行が作成されます。さらに、 への外部キー、タイプの列、およびタイプの列を持つテーブルがあります。見つからないものがある場合は、デフォルトのままにして false を返します。Id
Name
MachineName
Environment.MachineName
UserId
WindowState
X
Y
Height
Width
WindowState
X
Y
Height
Width
WindowValues
WindowId
Key
String
Value
Binary
注 2: save メソッドでは、もちろん、Load メソッドで行うこととは逆のことを行います。の行を作成しWindow
、WindowValues
それらが現在のユーザーとマシンにまだ存在しない場合。
PersistentFormBase
このクラスは前のクラスを使用し、他のフォームの便利な基本クラスを形成します。
// 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 EventHandler<EventArgs> ValuesLoaded;
protected event EventHandler<EventArgs> StoringValues;
protected void StoreValue<T>(string key, T value)
{
if (!handlerReady)
throw new InvalidOperationException();
PersistenceHandler.Set(key, value);
}
protected T GetValue<T>(string key)
{
if (!handlerReady)
throw new InvalidOperationException();
return PersistenceHandler.Get<T>(key);
}
protected T GetValue<T>(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<MdiClient>().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
メソッドを使用します。
これが誰かを助けることを願っています! その場合はお知らせください。また、改善すべき点や改善点があればフィードバックをお寄せください。学びたいです=)