gpt4 book ai didi

C#:如何使窗体记住其边界和 WindowState(考虑双显示器设置)

转载 作者:太空狗 更新时间:2023-10-29 17:51:26 38 4
gpt4 key购买 nike

我创建了一个表单可以继承的类,它处理表单的位置、大小和状态。而且效果很好。除了一件事:

当您在与主屏幕不同的屏幕上最大化应用程序时,位置和大小(在您最大化之前)会正确存储,但当它最大化时(根据其先前的状态)它会在我的主显示器上最大化。当我将它恢复到正常状态时,它会转到之前的另一个屏幕。当我再次最大化它时,它当然会在正确的屏幕上最大化。

所以我的问题是......我如何制作一个表单,当它最大化时,记住它在哪个屏幕上最大化?当表单再次打开时如何恢复它?


问题的完整解决方案

我接受了答案,该答案提供了关于如何在屏幕上显示的非常好的提示。但这只是我问题的一部分,所以这是我的解决方案:

加载中

  1. 首先存储BoundsWindowState来自任何存储。
  2. 然后设置Bounds .
  3. 确保BoundsScreen.AllScreens.Any(ø => ø.Bounds.IntersectsWith(Bounds)) 可见或 MdiParent.Controls.OfType<MdiClient>().First().ClientRectangle.IntersectsWith(Bounds) .
    • 如果没有,就执行Location = new Point(); .
  4. 然后设置窗口状态。

关闭时

  1. 商店 WindowState .
  2. 如果WindowStateFormWindowState.Normal ,然后存储 Bounds , 否则存储 RestoreBounds .

就是这样! =)

一些示例代码

因此,正如 Oliver 所建议的那样, 这是一些代码。它需要充实一些,但这可以作为任何想要的人的开始:

持久化处理程序

负责在某处存储和获取数据。

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 , WindowBounds和其他值。我们使用 SQL Server,并且有一个 Window包含 Id 列的表格, Name , MachineName (对于 Environment.MachineName ),UserId , WindowState , X , Y , Height , Width .所以对于每个窗口,你都会有一行 WindowState , X , Y , HeightWidth对于每个用户和机器。此外我们还有一个 WindowValues只有一个外键到 WindowId 的表, 一个 Key String 类型的列和一个 Value Binary 类型的列.如果没有找到东西,我会保留默认值并返回 false。

注意 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。这将自动处理边界和状态。如果还应存储任何其他内容,例如分离器距离,您将收听 ValuesLoadedStoringValues事件和那些使用 GetValueStoreValue方法。

希望这可以帮助别人!如果有,请告诉我。另外,如果您认为可以做得更好,请提供一些反馈。我想学习 =)

最佳答案

没有内置的方法来执行此操作 - 您必须自己编写逻辑。这样做的一个原因是您必须决定如何处理上次显示窗口的监视器不再可用的情况。例如,这在笔记本电脑和投影仪中很常见。 Screen类有一些有用的功能可以帮助解决这个问题,尽管可能很难唯一且一致地标识显示器。

关于C#:如何使窗体记住其边界和 WindowState(考虑双显示器设置),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/495380/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com