Настройки VB Winforms не сохраняются надежно - PullRequest
0 голосов
/ 11 апреля 2019

Мне было поручено создать пользовательский интерфейс приложения Winforms, написанный на VB, чтобы сохранить положение нескольких разделителей SplitContainer и размер окна. Я покажу код для SplitContainers ниже. Код для окна очень похож, но обращается к различным свойствам. Обратите внимание, что все значения SplitContainer сохраняются как целочисленные и присваиваются пользовательской области.

Код довольно прост. Когда форма загружается, я проверяю 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

Пока я работаю над этим, я отслеживаю файл user.config, используя Tail.exe . Это позволяет мне видеть обновления настроек по мере их сохранения. Я даже дошел до того, что настроил его так, чтобы при обновлении документа звучал звук.

Что я вижу, так это то, что, перемещая сплиттеры в SplitContainer, я могу видеть, как события запускаются, как и положено, устанавливая точки останова. Тем не менее, я также могу наблюдать, как он достигает точки останова, обновлять настройки, проходить после строки сохранения и абсолютно не обновлять документ. Это работает около 40% времени и кажется совершенно случайным. Я потратил почти целый день на то, чтобы заставить это работать, и я нахожусь в том же месте, где я был, когда писал код изначально. Я не могу найти ничего, что указывало бы на то, что кто-либо когда-либо видел такое поведение раньше, и я уверен, что мой код работает так, как должен, но по какой-то причине приложение не может выполнить запись в файл.

У меня довольно убедительные признаки того, что это правда. Когда вызывается My.Settings.Save () и значения не обновляются в Tail.exe, текст состояния в левом нижнем углу говорит: «Ожидание файла ...». Когда это работает, текст говорит: «Последнее обновление: XX: XX: XX» (отметка времени). Ожидание файла никогда не исчезнет, ​​если я просто оставлю его.

enter image description here

Итак, мне было интересно, сталкивался ли кто-нибудь еще с подобным поведением. Если так, как я могу заставить настройки заканчивать писать? Будет ли мне лучше использовать стороннее решение? Конечно, если вы обнаружите что-то, что я делаю неправильно, при сохранении этих настроек, пожалуйста, дайте мне знать.

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 12 апреля 2019

Я перешел к использованию DataBindings в настройках пользователя, как предложено @ OlivierJacot-Descombes.Теперь у меня есть только один вызов сохранения в функции Form_Closing.

Приходите, чтобы узнать, что я делал для отслеживания изменений, было недостаточно.Хвост не всегда обновлялся, чтобы отразить текущие данные в файле конфигурации, который вводил в заблуждение.Я использовал это в течение многих лет, чтобы контролировать файлы журнала и тому подобное, и никогда не видел, чтобы это делало это раньше.Кроме того, мне нужно было выполнить ручные обновления для значений, которые я должен был присутствовать, когда сохранение было сделано.Это состояло из зацикливания SpitContainers и обновления пользовательских настроек с их текущим значением SplitterDistance в обработчике ClientSize_Changed, который является общим для всех SplitContainers.ClientSize_Changed запускается многократно во время загрузки формы, поэтому мне все равно приходилось отслеживать это с помощью бита загрузки, чтобы SplitDistances не обновлялись до тех пор, пока не будут выполнены все измерения, и я перезагружаю настройки.

По-прежнему это не происходит.всегда сохраняйте настройки в режиме отладки.Тем не менее, когда я создаю релиз и использую .exe для запуска приложения (или запуска без отладки), оно сохраняет гораздо надежнее.

Мне также пришлось вызвать My.Settings.Reload в обработчике Form_Shown.Это потому, что форма много измеряет и просматривает загруженные вами значения.Перезагружая значения после завершения основного измерения, я вижу, как сохраненные значения вступают в силу.

Затем, чтобы избавиться от тонны видимых измерений, мне пришлось приостановить макет во время изменения размера формы, обратившись к Form_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

Спасибо за комментарии.Надеюсь, кто-то еще может найти это полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...