我的任务是制作用VB编写的Winforms应用程序的UI,以保存几个SplitContainer拆分器的位置和窗口大小。我将在下面显示SplitContainers的代码。窗口的代码非常相似,但是具有不同的属性。请注意,所有SplitContainer值都被保存为Integer并分配给User范围。
代码非常简单。加载表单时,我检查My.Settings.SettingsLoaded,默认为False。如果为False,我将获取当前的默认位置并将其保存保存。
Private Sub InitSettings()
If My.Settings.SettingsLoaded <> True Then
UpdateWindowSettingsData()
UpdateSplitContainerSettingsData()
My.Settings.SettingsLoaded = True
My.Settings.Save()
End If
isLoading = False
ScaleWindow()
ScaleUIElements()
End Sub
第二部分在每次表单加载和定位有问题的元素时运行
Private Sub ScaleUIElements()
isLoading = True
SuspendLayout()
SplitContainer3.SplitterDistance = My.Settings.SplitContainer3
SplitContainer8.SplitterDistance = My.Settings.SplitContainer8
SplitContainer10.SplitterDistance = My.Settings.SplitContainer10
SplitContainer20.SplitterDistance = My.Settings.SplitContainer20
SplitContainer21.SplitterDistance = My.Settings.SplitContainer21
ResumeLayout()
isLoading = False
End Sub
然后,我附加了几个处理程序以捕获用户操作
Private Sub SplitterMoved(ByVal sender As System.Object, ByVal e As System.Windows.Forms.SplitterEventArgs) Handles SplitContainer3.SplitterMoved, SplitContainer8.SplitterMoved, SplitContainer20.SplitterMoved, SplitContainer21.SplitterMoved, SplitContainer10.SplitterMoved
If isLoading Then
Return
End If
UpdateSplitContainerSettingsData()
End Sub
数据更新也很简单
Private Sub UpdateSplitContainerSettingsData()
My.Settings.SplitContainer3 = SplitContainer3.SplitterDistance
My.Settings.SplitContainer8 = SplitContainer8.SplitterDistance
My.Settings.SplitContainer10 = SplitContainer10.SplitterDistance
My.Settings.SplitContainer20 = SplitContainer20.SplitterDistance
My.Settings.SplitContainer21 = SplitContainer21.SplitterDistance
My.Settings.Save()
End Sub
在此过程中,我一直在使用Tail.exe监视user.config文件。这使我可以看到设置保存后的更新。我什至竭尽所能进行设置,以便在文档更新时播放声音。
我看到的是,当我在SplitContainers中四处移动拆分器时,通过设置断点,我可以看到事件如预期那样触发。但是,我也可以看到它到达断点,更新设置,运行到保存行之后,并且绝对不更新文档。它大约有40%的时间有效,而且似乎是完全随机的。我花了整整一整天的时间试图使它正常工作,并且与我最初编写代码时的位置完全相同。我找不到任何迹象表明有人曾经见过此行为,并且我有信心代码可以正常工作,但是由于某种原因,该应用程序无法对文件进行写入。
我有一个很明确的指示,那就是事实。当调用My.Settings.Save()且Tail.exe中的值不更新时,左下角状态文本将显示“正在等待文件...”。当它起作用时,文本将显示“上次更新时间:XX:XX:XX”(时间戳)。如果我离开文件,等待文件将永远不会消失。
因此,我想知道是否还有其他人遇到过类似的行为。如果是这样,如何使设置完成写入?使用第三方解决方案会更好吗?当然,如果您在保存这些设置时发现任何我做错的事情,请告诉我。
感谢您的帮助!
答案 0 :(得分:0)
我已经按照@ OlivierJacot-Descombes的建议,将数据绑定用于用户设置。现在,在Form_Closing函数中只有一个保存调用。
来找出我在跟踪变更中所做的工作是不够的。尾部并非总是更新以反映配置文件中的当前数据,这会产生误导。多年来,我一直在使用它来监视日志文件,但从未见过这样做。 另外,我需要对保存完成后需要显示的值进行手动更新。这包括循环SpitContainers并在所有SplitContainers共有的ClientSize_Changed处理程序中使用其当前的SplitterDistance值更新用户设置。在加载表单时,ClientSize_Changed会重复触发,因此我仍然必须使用加载位来跟踪它,以便在完成所有测量并重新加载设置之前,不会更新SplitDistances。
它仍然不总是以调试模式保存设置。但是,当我构建发行版并使用.exe启动应用程序(或在不调试的情况下运行)时,它可以更可靠地进行保存。
我还必须在Form_Shown处理程序中调用My.Settings.Reload。这是因为表单会进行大量测量,并且会遍历您已加载的值。通过在主要测量完成后重新加载值,我可以看到保存的值生效。
然后,为了摆脱大量可见的度量,我不得不在寻址ResizeBegin和Form_ResizeEnd的过程中,在重新调整尺寸时暂停布局。这样可以使用户在调整大小时看到的内容变得平滑,但是仍然存在对堆栈面板进行难看的重新测量的问题。
在C#中的工作端项目中:
public partial class Form1 : Form
{
private bool loading = true;
public Form1()
{
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Properties.Settings.Default.Save();
}
private void SplitContainerClientSizeChanged(object sender, EventArgs e)
{
if (!loading)
{
UpdateAllSplitterDistance();
Properties.Settings.Default.Save();
}
}
private void UpdateAllSplitterDistance()
{
foreach (var i in this.Controls)
{
if (i is SplitContainer)
{
UpdateSplitterDistance(i as SplitContainer);
}
}
}
private void UpdateSplitterDistance(SplitContainer sc)
{
Properties.Settings.Default[string.Format("{0}_Dist", sc.Name)] = sc.SplitterDistance;
}
private void Form1_Shown(object sender, EventArgs e)
{
loading = false;
scMain.Visible = false;
scMain.SuspendLayout();
Properties.Settings.Default.Reload();
scMain.ResumeLayout();
scMain.Visible = true;
}
private void Form1_ResizeBegin(object sender, EventArgs e)
{
scMain.Visible = false;
scMain.SuspendLayout();
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
scMain.Visible = true;
scMain.ResumeLayout();
}
}
SplitContainer,左右两侧都有一个SplitContainer
感谢您的评论。希望其他人可以找到有用的东西。