来自表单滑块 (TrackBar) 的线程安全 'get'

Threadsafe 'get' from form slider (TrackBar)

我有一个应用程序,其初始表单具有各种配置(复选框、文本框、sliders/trackbars)。当我启动使用这些配置的操作时,有一个名为的工作进程:

private void btnx_Click(object sender, EventArgs e)
{
  bgWorkerX.RunWorkerAsync();
}

private void bgWorkerX_DoWork(object sender, DoWorkEventArgs e)
{
    Dictionary<string, object> dictCfgOut = GenerateConfigDict();
    XGen.CreateX.aReadFile(inputPathXRAW.Text,  outputPathX.Text, dictCfgOut);
}

GenerateConfigDict 函数创建 Dictionary<string, object> 配置数据。这是因为所需的数据各不相同(一些布尔值、一些整数、一个字符串数组)。创建它的代码如下:

    private Dictionary<string, object> GenerateConfigDict()
    {
        Dictionary<string, object> ConfigDict = new Dictionary<string, object>();

        if (cbXAddOnus.Checked)
        {
            if (!MiscTools.ValidateX(txtInstX.Text, true))
                return null;
        }

        ConfigDict.Add("Available Images", GenerateConfigImageArray());
        ConfigDict.Add("X SCSC Hot", (cbXAddSCSC.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Req Adj", (cbXAddAdjustment.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Items", (cbXAddX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Use Something", (cbXAddX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Somedata", (string)txtX.Text);
        ConfigDict.Add("X Use SAN", (cbX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X % Y", (int)sliderX.Value);

        return ConfigDict;
    }

sliderX.Value 部分是今天刚刚添加的。在此之前,一切都很好。然而,只有那一点,我得到:

Cross-thread operation not valid: Control 'sliderX' accessed from a thread other than the thread it was created on.

首先,为什么读取该值不是线程安全的,但读取复选框和文本是线程安全的?其次,我一直在研究使该线程安全的问题,但这似乎都需要另一个函数来异步调用该值。我已经采取措施确保在工作人员 运行 时禁用滑块,因此无法从表单进行更改。

谢谢!

控件的线程行为与 .NET 包装的非托管代码有关。我不确切知道哪个 属性 可以 and/or 应该 从任何线程访问以及为什么。

我不会使用 Invoke 回调 UI 线程,除非您需要 "real time" 访问控件(即更新 ProgressBar 值) .相反,在 运行 后台工作者之前,在 UI 线程上收集 UI 东西并将它们提供给工作者:

bgWorkerX.RunWorkerAsync((int)sliderX.Value);
...
private void bgWorkerX_DoWork(object sender, DoWorkEventArgs e)
{
    Dictionary<string, object> dictCfgOut = GenerateConfigDict((int)e.Argument);
    ...
}

private Dictionary<string, object> GenerateConfigDict(int sliderValue)
{
    ...
    ConfigDict.Add("X % Y", sliderValue);
    ...
}

除了这个值,您甚至可以选择在 UI 线程上创建整个配置字典,然后将其用作后台工作程序的支持。

要线程安全地访问任何控件,您应该调用该控件的 Invoke() 方法 (MSDN tutorial)。

因此,您的代码将如下所示:

delegate int GetSliderValueCallback();

private int GetValue()
{
    int sliderValue;
    if (sliderX.InvokeRequired)
    {
        GetSliderValueCallback cb = new GetSliderValueCallback(GetValue);
        return (int)sliderX.Invoke(cb);
    }
    else
    {
        return (int)sliderX.Value;
    }
}

并在读取值时调用它:

ConfigDict.Add("X % Y", GetValue());

我也建议您使用 async methods

private async void btnx_Click(object sender, EventArgs e)
{
  await bgWorkerX_DoWorkAsync();
}

private async void bgWorkerX_DoWorkAsync()
{
    Dictionary<string, object> dictCfgOut = await GenerateConfigDictAsync();
    XGen.CreateX.aReadFile(inputPathXRAW.Text,  outputPathX.Text, dictCfgOut);
}

private Task<Dictionary<string, object>> GenerateConfigDictAsync()
    {
        return Task.Run(() => {
        Dictionary<string, object> ConfigDict = new Dictionary<string, object>();

        if (cbXAddOnus.Checked)
        {
            if (!MiscTools.ValidateX(txtInstX.Text, true))
                return null;
        }

        ConfigDict.Add("Available Images", GenerateConfigImageArray());
        ConfigDict.Add("X SCSC Hot", (cbXAddSCSC.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Req Adj", (cbXAddAdjustment.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Items", (cbXAddX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Use Something", (cbXAddX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X Somedata", (string)txtX.Text);
        ConfigDict.Add("X Use SAN", (cbX.Checked) ? (bool)true : (bool)false);
        ConfigDict.Add("X % Y", (int)sliderX.Value);

        return ConfigDict;
    });
}

警告! 不幸的是我没有机会构建该代码(我只是在这里写的),所以,请使用它 作为示例.