winforms 我试图创建我自己的助手类来保存和加载设置,但是加载部分的列表是空的,为什么列表是空的?

0wi1tuuw  于 2023-11-21  发布在  其他
关注(0)|答案(2)|浏览(127)

我知道有点长但都是有联系的。
在form1 top中,我创建了这个类:

public class SettingControlPair
{
    public string Key { get; set; }
    public object Value { get; set; }
    public Control Control { get; set; }
}

字符串
然后为configurationhelper类创建了这个列表变量和一个变量:

private List<SettingControlPair> settingControlPairs = new List<SettingControlPair>();
private ConfigurationHelper configurationHelper;


在form1构造函数中,我初始化了configurationhelper并调用了configurationLoading方法:

public Form1()
{
    InitializeComponent();

    // Initialize your module classes here
    selectedImagePath = string.Empty;
    imageProcessor = new ImageProcessor(selectedImagePath);
    fileHandler = new FileHandler();

    configurationHelper = new ConfigurationHelper(settingControlPairs);

    if (textBoxLensSize.Text == string.Empty)
    {
        LensCropRectWidth = 10;
    }

    InitializeUI();
    configurationHelper.LoadConfiguration();
}


我如何使用它来保存的示例:

private void textBoxLensSize_TextChanged(object sender, EventArgs e)
{
    // Perform real-time input validation
    if (int.TryParse(textBoxLensSize.Text, out int width))
    {
        // Valid integer input
        if (width >= 10)
        {
            LensCropRectWidth = width; // Update the property
            labelCroppedImagesCount.Focus();

            configurationHelper.SaveConfiguration("LensSize", width, textBoxLensSize);
        }
        else
        {
            // Show a message if the value is less than 10
            MessageBox.Show("Please enter a value greater than or equal to 10.");
            textBoxLensSize.Text = 10.ToString(); // Revert to the previous value
            labelCroppedImagesCount.Focus();
        }
    }
}


这是储蓄线:

configurationHelper.SaveConfiguration("LensSize", width, textBoxLensSize);


最后是ExclusionHelper类代码:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using static Images_Cropping.Form1;

namespace Images_Cropping
{
    public class ConfigurationHelper
    {
        private List<SettingControlPair> settingControlPairs;

        public ConfigurationHelper(List<SettingControlPair> settingControlPairs)
        {
            this.settingControlPairs = settingControlPairs;
        }

        public void LoadConfiguration()
        {
            foreach (var pair in settingControlPairs)
            {
                var value = Properties.Settings.Default[pair.Key];
                if (value != null)
                {
                    pair.Value = value;

                    if (pair.Control is TextBox textBox)
                    {
                        textBox.Text = value.ToString();
                    }
                    else if (pair.Control is CheckBox checkBox)
                    {
                        if (bool.TryParse(value.ToString(), out bool isChecked))
                        {
                            checkBox.Checked = isChecked;
                        }
                    }
                    else if (pair.Control is NumericUpDown numericUpDown)
                    {
                        if (decimal.TryParse(value.ToString(), out decimal numericValue))
                        {
                            numericUpDown.Value = numericValue;
                        }
                    }
                    else if (pair.Control is ComboBox comboBox)
                    {
                        comboBox.SelectedItem = value;
                    }
                    else if (pair.Control is TrackBar trackBar)
                    {
                        if (int.TryParse(value.ToString(), out int trackBarValue))
                        {
                            trackBar.Value = trackBarValue;
                        }
                    }
                }
            }
        }

        public bool SaveConfiguration(string key, object value, Control control)
        {
            try
            {
                // Save the configuration setting
                Properties.Settings.Default[key] = value;

                // Add the key, object value, and control to the list
                settingControlPairs.Add(new SettingControlPair
                {
                    Key = key,
                    Value = value,
                    Control = control
                });

                Properties.Settings.Default.Save();
                return true; // Save operation succeeded
            }
            catch (Exception ex)
            {
                // Handle any exceptions related to saving the configuration
                Console.WriteLine("Error saving configuration: " + ex.Message);
                return false; // Save operation failed
            }
        }
    }
}


问题是List settingControlPairs是空的。然后当试图在LoadConfiguration方法中循环列表时,ir什么也不做,因为List是空的。
列表为空的原因是因为我用列表初始化了form1构造函数中的configurationHelper,但列表为空:

configurationHelper = new ConfigurationHelper(settingControlPairs);


列表settingControlPairs为空,因此在LoadingConfiguration方法中也为空。
我怎样才能解决这个逻辑问题,列表不会是空的?

pobjuy32

pobjuy321#

当从配置中读取字符串时,它可能只是空的而不是null。因此,为了解决这个问题,在if块(位于load方法的foreach循环中)中进行以下检查之一应该会有所帮助:

if(!string.IsNullOrEmpty(value))

字符串
或者,您可以使用:用途:

if(value?.Length > 0)


例如:

public void LoadConfiguration()
{
    foreach (var pair in settingControlPairs)
    {
        var value = Properties.Settings.Default[pair.Key];
        if (value?.Length > 0)
        {
            pair.Value = value;

            if (pair.Control is TextBox textBox)
            {
                textBox.Text = value.ToString()
[...]

k5ifujac

k5ifujac2#

查看您的代码,可以解释此行为的一件事是,在InitializeComponent中,如果在设置控件的 initial 值之前订阅了像TextBox.TextChanged这样的事件,因为这些初始(空白)值可能会保存到配置中,然后当您加载配置时,您将什么也得不到。
因此,例如,如果您有一个包含这些控件的表单,并希望在下次应用程序启动时使用相同的值填充它,那么您可以使用一种方法来解决您遇到的所有问题。


的数据
我认为你写一个JSON文件的想法(到用户的AppData文件夹)是一个很好的想法。为了安全起见,试着按照这个顺序做:

public partial class MainForm : Form
{
    string configPath { get; } =
        Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            Assembly.GetEntryAssembly().GetName().Name,
            "config.json"
    );
    public MainForm()
    {
        InitializeComponent();
        // Restore values BEFORE subscribing to events
        LoadConfiguration();
        // NOW you can safely subscribe.
        SubscribeToEvents();
    }
    Dictionary<string, object> ConfigurationHelper { get; set; }
    .
    .
    .
}

字符串

从Json文件加载配置

private void LoadConfiguration()
{
    if (File.Exists(configPath))
    {
        ConfigurationHelper =
            JsonConvert
            .DeserializeObject<Dictionary<string, object>>(File.ReadAllText(configPath));
        foreach (var key in ConfigurationHelper.Keys)
        {
            if (Controls[key] is Control control)
            {
                if (control is TextBox textBox)
                {
                    if (ConfigurationHelper.TryGetValue(key, out var value))
                    {
                        textBox.Text = value.ToString();
                    }
                }
                else if (control is NumericUpDown numeric)
                {
                    if (ConfigurationHelper.TryGetValue(key, out var o) && int.TryParse($"{o}", out int value))
                    {
                        numeric.Value = value;
                    }
                }
                else if (control is ComboBox comboBox)
                {
                    if (ConfigurationHelper.TryGetValue(key, out var o) && int.TryParse($"{o}", out int value))
                    {
                        comboBox.SelectedIndex = value;
                    }
                }
                else if (control is TrackBar trackBar)
                {
                    if (ConfigurationHelper.TryGetValue(key, out var o) && int.TryParse($"{o}", out int value))
                    {
                        trackBar.Value = value;
                    }
                }
                else if (control is CheckBox checkBox)
                {
                    if (ConfigurationHelper.TryGetValue(key, out var o) && bool.TryParse($"{o}", out bool value))
                    {
                        checkBox.Checked = value;
                    }
                }
            }
        }
    }
    else
    {
        Directory.CreateDirectory(Path.GetDirectoryName(configPath));
        ConfigurationHelper = new Dictionary<string, object>();
    }
}

订阅更改事件

确保浏览Designer.cs文件。要么完全删除TextChangedSelectionIndexChanged等控制更改事件的现有处理程序,* 或者 * 至少浏览这些处理程序,确保它们不会对配置文件进行任何写入。这些处理程序有真实的可能导致竞争条件,从而导致您看到的问题。* 需要明确的是,将一个事件多次订阅到多个处理程序是完全可以的。如果你选择保留现有的处理程序,不要让它们写入你的SaveConfiguration方法。*
在配置已经加载之后,改为以这种方式订阅事件:

private void SubscribeToEvents()
    {
        foreach (var control in IterateControls(Controls))
        {
            if (control is TextBox textBox)
            {
                // You're still free to subscribe to these events
                // in other places for different purposes.
                textBox.TextChanged += (sender, e) => 
                    SaveConfiguration(textBox, textBox.Text);
            }
            else if (control is NumericUpDown numeric)
            {
                numeric.ValueChanged += (sender, e) => 
                    SaveConfiguration(numeric, numeric.Value);
            }
            else if (control is ComboBox comboBox)
            {
                comboBox.SelectionChangeCommitted += (sender, e) => 
                    SaveConfiguration(comboBox, comboBox.SelectedIndex);
            }
            else if (control is TrackBar trackBar)
            {
                trackBar.ValueChanged += (sender, e) =>
                    SaveConfiguration(trackBar, trackBar.Value);
            }
            else if (control is CheckBox checkBox)
            {
                checkBox.CheckedChanged += (sender, e) => 
                    SaveConfiguration(checkBox, checkBox.Checked);
            }
        }
    }

保存单个控件更改

当发生更改时,只需序列化字典。就像写的那样,它不是非常有效。任何文本框中的每个字符串都会写入整个文件。因此,通过等待更改解决,异步写入配置文件,甚至在应用程序关闭时执行配置文件来优化。

private void SaveConfiguration(Control control, object value)
    {
        ConfigurationHelper[control.Name] = value.ToString();
        // Save every change OR: - Save on app close? - Save after time delay (consolidate rapid changes)?
        File.WriteAllText(configPath, JsonConvert.SerializeObject(ConfigurationHelper));
    }

相关问题