VB Winforms设置不能可靠保存

时间:2019-04-11 20:08:24

标签: vb.net winforms

我的任务是制作用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”(时间戳)。如果我离开文件,等待文件将永远不会消失。

enter image description here

因此,我想知道是否还有其他人遇到过类似的行为。如果是这样,如何使设置完成写入?使用第三方解决方案会更好吗?当然,如果您在保存这些设置时发现任何我做错的事情,请告诉我。

感谢您的帮助!

1 个答案:

答案 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 SplitContainer with a SplitContainer in both the right and left panels

用户设置 User Settings

感谢您的评论。希望其他人可以找到有用的东西。