从表单滑块(TrackBar)

时间:2015-07-31 00:29:48

标签: c# winforms thread-safety trackbar

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

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>个配置数据。这是因为所需的数据有所不同(一些bool,一些int,一串字符串)。创建它的代码如下:

    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部分。在此之前一切都很好。但是,只有这一点,我得到:

  

跨线程操作无效:从a访问控制'sliderX'   除了创建它的线程以外的线程。

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

谢谢!

2 个答案:

答案 0 :(得分:1)

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

除非您需要&#34;实时&#34;否则我不会将Invoke回调用于UI线程。访问控件(即更新ProgressBar值)。相反,在运行后台工作程序之前,在UI线程上收集UI内容并将其提供给worker:

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线程上创建整个配置字典,然后将其用作后台工作者的agrument,而不仅仅是这个值。

答案 1 :(得分:1)

要安全地访问任何控制线程,您应该调用该控件的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;
    });
}

警告!很遗憾,我没有机会构建该代码(我已在此处写过),因此,请使用作为示例