首页 > 解决方案 > C# WinFrom ComboBox SelectedValueChanged 事件触发延迟

问题描述

更新:

我还没有找到真正的原因,但我发现,更新任何其他数据绑定控件的属性都会引发来自文件夹组合框的“延迟”事件。到目前为止,这不是一个干净的解决方案,但我通过更新未起诉的财产来帮助自己。也就是说,直到我了解真正的原因。


原帖:

我目前正在开发一个 Windows.Forms 项目(不幸的是必须是 WinForms),并且我有三个 ComboBoxes,每个 DataSources 都绑定到一个 List。列表包含文件夹或文件名。每个 Combobox 的 SelectedItem 属性也绑定到一个字符串。SelectedValueChanged 事件已注册并实现。

它们相互依赖,所以当我更新 combobox1 的 DataSource 时,combobox2 的 DataSource 也必须更新。这是因为在 combobox1 中,您可以为随后在 combobox2 中列出的文件选择一个子目录。

现在问题来了。有时会发生,当我以编程方式更新 combobox1 中的 SelectedItem 时,SelectedValueChanged 事件不会立即触发。程序继续,直到combobox2 的DataSource 更新。仅然后,执行组合框 1 的 SelectedValueChanged 事件方法,但不幸的是,它“为时已晚”,因为组合框 2 的数据源已经使用来自组合框 1 的错误子目录进行了更新。

我想了解,哪个事件没有立即触发。下面我发布了相关代码部分的简短示例。

// Cmb1Data and Cmb2Data are the String-Lists which are bound to the DataSource property of the ComboBoxes
// TempCmb1(2)SelectedValue is a string value which contains the value which is to be set.
// Cmb1(2)SelectedValue is a string which is bound the the SelectedItem property of the ComboBoxes

List<string> TempCmb1Data = MainVM.GetCmb1Data();
// some if-statement (plausibility check) is done here before the DataSource is updated.
Cmb1Data = TempCmb1Data ;
if (Cmb1Data.Contains(TempCmb1SelectedValue)
    Cmb1SelectedValue = TempCmb1SelectedValue; // This should fire the event - but sometimes it does not...

List<string> TempCmb2Data = MainVM.GetCmb2Data();
// as before, some if-statement (plausibility check) is done here before the DataSource is updated.
Cmb2Data = TempCmb2Data; // This is the point, where the SelectedValueChangedEvent of Combobox1 suddenly is fired, followed by the SelectdValueChanged event of Combobox 2 

我已经仔细检查了所有数据绑定和事件方法注册,它们都可以。如果我手动更改 SelectedItem ,一切都运行良好 - 只是有时必须以编程方式完成。

先感谢您。阿尔


编辑:

所以我将代码总结到相关部分(如下所示)。当我测试这段代码以确保它是正确的时,问题并没有发生。在我看来,问题隐藏在其他地方并且不知道在哪里,这里发布的代码太多了。如果发现问题,我将再次深入研究并发布更新。

public partial class Form
{
    RuntimeData _RuntimeData = new RuntimeData();

    private void Form_Load(object sender, EventArgs e)
    {
        AddDataBindings();
    }
    
    private void AddDataBindings()
    {
        cmbFolders.DataBindings.Add("SelectedItem", _RuntimeData , "SelectedFolder");
        cmbFolders.DataBindings.Add("DataSource",   _RuntimeData , "Folders");
        cmbFiles.DataBindings.Add("SelectedItem",   _RuntimeData , "SelectedFile");
        cmbFiles.DataBindings.Add("DataSource",     _RuntimeData , "Files");
    }

    bool _ToggleFlag = false;
    private void btTest_Click(object sender, EventArgs e)
    {
         string TcpString = "Cmd=Execute;Dir=SubDirName1;File=FileName1.dat;";

         if (_ToggleFlag)
             TcpString = "Cmd=Execute;Dir=SubDirName2;File=FileName2.dat;";

         _ToggleFlag = !_ToggleFlag;

         // Method is usually executed in separate thread but the problem exists either way. So Threading removed for simplification
         ParseAndExecute(TcpString, _RuntimeData);
    }

    private void ParseAndExecute(string tcpString, RuntimeData runtimeData)
    {
        if (String.IsNullOrEmpty(tcpString))
            return;

        string[] Elements = tcpString.Split(new char[] { ';', '=' }, StringSplitOptions.RemoveEmptyEntries);

        // Replaced GetFolders-Method for simplification
        List<string> TempFolders = new List<string>() { "SubDirName1", "SubDirName2", "SubDirName3" };
        if (TempFolders [0] == Elements[3])
            ;//runtimeData.ProcessFolderChange = true;
        runtimeData.Folders.Clear();
        runtimeData.Folders = TempFolders;
        if (runtimeData.Folders.Contains(Elements[3]))
        {
             if (runtimeData.Folders[0] != Elements[3])
                 ;//runtimeData.ProcessFolderChange = true;
             runtimeData.SelectedFolder = Elements[3];
        }

        // Replaced GetFiles-Method for simplification
        List<string> TempFiles = new List<string>() { "FileName1.dat", "FileName2.dat", "FileName3.dat" };
        if (TempFiles [0] == Elements[5])
            ;//runtimeData.ProcessFileChange = true;
        runtimeData.Files.Clear();
        runtimeData.Files = TempFiles;
        if (runtimeData.Files.Contains(Elements[5]))
        {
             if (runtimeData.Files[0] != Elements[5])
                 ;//runtimeData.ProcessFileChange = true;
             runtimeData.SelectedFile = Elements[5];
        }
    }

    private void cmbFolders_SelectedValueChanged(object sender, EventArgs e)
    {
        //if (!_RuntimeData.ProcessFolderChange)
            //return;
        //_RuntimeData.ProcessFolderChange = false;

        ((ComboBox)sender).DataBindings["SelectedItem"].WriteValue();

        _RuntimeData.Files.Clear();
        _RuntimeData.Files = new List<string>() { "FileName1.dat", "FileName2.dat", "FileName3.dat" };
    }

    private void cmbFiles_SelectedValueChanged(object sender, EventArgs e)
    {
        //if (!_RuntimeData.ProcessFileChange)
            //return;
        //_RuntimeData.ProcessFileChange= false;

        ((ComboBox)sender).DataBindings["SelectedItem"].WriteValue();

        // do some random stuff with the file...
    }
}


// Relevant data from RuntimeData class.
public class RuntimeData : VMBase
{
    private List<string> folders = new List<string>() { "SubDirName1", "SubDirName2", "SubDirName3" };
    public List<string> Folders
    {
        get { return folders; }
        set
        {
            folders = value;            
            OnPropertyChanged(new PropertyChangedEventArgs("Folders"));
        }
    }
    
    private List<string> files = new List<string>()  { "FileName1.dat", "FileName2.dat", "FileName3.dat" };
    public List<string> Files
    {
        get { return files; }
        set
        {
            files = value;            
            OnPropertyChanged(new PropertyChangedEventArgs("Files"));
        }
    }

    string selectedFolder = String.Empty;
    public string SelectedFolder
    {
        get { return selectedFolder ; }
        set
        {
            selectedFolder = value;
            OnPropertyChanged(new PropertyChangedEventArgs("SelectedFolder"));
        }
    }

    string selectedFile = String.Empty;
    public string SelectedFile 
    {
        get { return selectedFile ; }
        set
        {
            selectedFile = value;
            OnPropertyChanged(new PropertyChangedEventArgs("SelectedFile"));
        }
    }
}

public abstract class VMBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
}

标签: c#winformsdata-bindingcombobox

解决方案


推荐阅读