Настройка приложения не сохраняется

Я хочу сохранить StringDictionary в настройках приложения, чтобы заполнить мой список lbc_lastCustomersVisited сохраненными значениями при запуске приложения.

Вот мои настройки приложения (формат XML):

<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Wibe_EFI.Properties" GeneratedClassName="Settings">
    <Profiles />
    <Settings>
        <Setting Name="ApplicationSkinName" Type="System.String" Scope="User">
            <Value Profile="(Default)" />
        </Setting>
        <Setting Name="LastTimeWibeDataObtained" Type="System.String" Scope="User">
            <Value Profile="(Default)" />
        </Setting>
        <Setting Name="LastVisitedCustomer" Type="System.Collections.Specialized.StringDictionary" Scope="User">
            <Value Profile="(Default)" />
        </Setting>
  </Settings>


In my form, I got a StringDictionary local variable :

public partial class MainForm : XtraForm
{
    private StringDictionary lastVisitedCustomers = new StringDictionary();
    [...]
}


Вот как я заполняю свою локальную переменную StringDictionary:

private void btn_selectCustomer_Click(object sender, EventArgs e)
{
    DataRowView selectedRow = GetCustomersGridSelectedRow();
    lastVisitedCustomers.Add(GetCustomerID(selectedRow), String.Format("{0} - {1}", GetCustomerName(selectedRow), GetCustomerCity(selectedRow)));
}

(StringDictionary успешно заполнено)

В FormClosing я сохраняю свои настройки:

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
        Settings.Default["ApplicationSkinName"] = UserLookAndFeel.Default.SkinName;
        Settings.Default.LastVisitedCustomer = lastVisitedCustomers;
        Settings.Default.Save();
}

Настройка ApplicationSkinName успешно сохранена, но не lastVisitedCustomer StringDictionary. Потому что, когда я загружаю свои настройки во время запуска приложения, Settings.Default.LastVisitedCustomer равно null.


Вот как я загружаю свои настройки скина приложения (это работает):

public MainForm()
{
        InitializeComponent();
        InitSkinGallery();
        UserLookAndFeel.Default.SkinName = Settings.Default["ApplicationSkinName"].ToString();
}

Но я не могу загрузить свой StringDictionnary прямо здесь из-за файла NullReferenceException.
Поэтому я загружаю его здесь:

private void MainForm_Load(object sender, EventArgs e)
{
    _mySqlCeEngine = new MySqlCeEngine(this);
    ShowHomePanel();
    LoadLastVisitedCustomers();
}

private void LoadLastVisitedCustomers()
{
    if (Settings.Default.LastVisitedCustomer.Count > 0)
    {
        lastVisitedCustomers = Settings.Default.LastVisitedCustomer;
    }
    lbc_lastCustomersVisited.DataSource = new BindingSource(lastVisitedCustomers, null);
    lbc_lastCustomersVisited.DisplayMember = "Value";
    lbc_lastCustomersVisited.ValueMember = "Key";
}

Но на данный момент Settings.Default.LastVisitedCustomer равно нулю, и я не понимаю, почему. Я пробовал некоторые вещи, например не использовать локальную переменную и читать/записывать напрямую из Settings.Default.LastVisitedCustomer, но у меня возникла та же проблема.

Спасибо,

Адский кот.

EDIT: добавлен полный файл Settings.settings (представление XML).


person Hellcat8    schedule 07.08.2015    source источник
comment
Можете ли вы отредактировать свой пост и включить весь файл XML? Я думаю, что вы обращаетесь не к тем узлам в вашем Settings.   -  person Leon Bohmann    schedule 07.08.2015
comment
Я отредактировал свой пост. Благодарю вас !   -  person Hellcat8    schedule 07.08.2015
comment
Попробуйте использовать this.LastVisitedCustomers = (StringDictionary)Settings.Default["LastVisitedCustomer"] в конструкторе MainForm().   -  person Leon Bohmann    schedule 07.08.2015
comment
Спасибо за помощь, но это все то же самое: во время запуска оно равно нулю :(   -  person Hellcat8    schedule 10.08.2015


Ответы (2)


Если вы хотите попробовать, я попытался создать ошибку, которую вы получили, создав новую форму приложения:

namespace WindowsFormsApplication2
{
  public partial class Form1 : Form
  {

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        test.Text = (string)Settings.Default["lastCustomers"];
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        Settings.Default["lastCustomers"] = test.Text;
        Settings.Default.Save();
    }
  }
}

В этом примере код работает. Просто создайте новую форму-приложение и добавьте в нее текстовое поле с именем test. Каждый раз, когда вы закрываете программу и перезапускаете ее, строка, которую вы написали в текстовое поле, будет сохранена и перезагружена в test.Text.

Конкретно в вашем случае ваш конструктор должен выглядеть так: (Возможное решение)

public MainForm()
{
    InitializeComponent();
    InitSkinGallery();
    UserLookAndFeel.Default.SkinName = Settings.Default["ApplicationSkinName"].ToString();
    lastVisitedCustomers = (StringDictionary)Settings.Default["LastVisitedCustomer"];
}

После этого вы сохраняете настройки так же, как вы их загрузили:

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    Settings.Default["ApplicationSkinName"] = UserLookAndFeel.Default.SkinName;
    Settings.Default["LastVisitedCustomer"] = lastVisitedCustomers;
    Settings.Default.Save();
}

Это должно решить вашу проблему!

РЕДАКТИРОВАТЬ Ну и, конечно же, ваши функции загрузки выглядят по-другому:

private void MainForm_Load(object sender, EventArgs e)
{
    _mySqlCeEngine = new MySqlCeEngine(this);
    ShowHomePanel();
    LoadLastVisitedCustomers();
}


private void LoadLastVisitedCustomers()
{
    lbc_lastCustomersVisited.DataSource = new BindingSource(lastVisitedCustomers, null);
    lbc_lastCustomersVisited.DisplayMember = "Value";
    lbc_lastCustomersVisited.ValueMember = "Key";
}
person Leon Bohmann    schedule 07.08.2015
comment
Большое спасибо за вашу помощь, но это не решает мою проблему :(. Я попробовал ваше решение, я также пытался использовать OrderedDictionary вместо String. Но это то же самое: Settings.Default["LastVisitedCustomer"] имеет значение null во время запуска. - person Hellcat8; 10.08.2015

Я не смог найти решения для хранения Dictionary в настройках приложения, поэтому решил разобраться с string и разделить его:

public partial class MainForm : XtraForm
{
    private Dictionary<string, string> lastVisitedCustomers;

    public MainForm()
    {
        InitializeComponent();
        InitSkinGallery();
        UserLookAndFeel.Default.SkinName = Settings.Default["ApplicationSkinName"].ToString();
        lastVisitedCustomers = StringToDictionary(Settings.Default["LastVisitedCustomer"].ToString());
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        Settings.Default["ApplicationSkinName"] = UserLookAndFeel.Default.SkinName;
        Settings.Default["LastVisitedCustomer"] = DictionaryToString(lastVisitedCustomers);
        Settings.Default.Save();
    }

    #region Dictionary management

    private string DictionaryToString(Dictionary<string, string> dic)
    {
        if (dic.Count == 0)
        {
            return string.Empty;
        }
        else
        {
            string dicString = string.Empty;
            int i = 0;
            foreach (KeyValuePair<string, string> entry in dic)
            {
                if (i == 0)
                {
                    dicString = String.Format("{0} ## {1}", entry.Key, entry.Value);
                    i++;
                }
                else
                {
                    dicString += String.Format(" -- {0} ## {1}", entry.Key, entry.Value);
                }
            }
            return dicString;
        }
    }

    private Dictionary<string, string> StringToDictionary(string str)
    {
        Dictionary<string, string> dic = new Dictionary<string,string>();
        if (String.IsNullOrEmpty(str))
        {
            return dic;
        }
        else
        {
            string[] entries = Regex.Split(str, " -- ");

            foreach (string entry in entries)
            {
                string[] kvp = Regex.Split(entry, " ## ");
                dic.Add(kvp[0], kvp[1]);
            }

            return dic;
        }
    }
}
    #endregion

На данный момент это работает.
Я надеюсь, что это поможет любому в моей ситуации.

Примечание. Возможно, вам придется изменить методы моего словаря, чтобы обрабатывать все случаи для исключений. Но я думаю, что сейчас это нормально.

Приносим извинения за любые английские ошибки

person Hellcat8    schedule 10.08.2015