我有一个具有各种配置的初始表单的应用程序(复选框,文本框,滑块/轨道栏)。当我启动使用这些配置的操作时,会有一个名为的工作进程:
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' 除了创建它的线程以外的线程。
首先,为什么读取该值不是线程安全的,但阅读复选框和文本是?其次,我已经开始讨论如何使线程安全,但这似乎都需要另一个函数来异步调用该值。我已经采取措施确保在工作程序运行时禁用滑块,因此无法从表单进行更改。
谢谢!
答案 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;
});
}
警告!很遗憾,我没有机会构建该代码(我已在此处写过),因此,请使用作为示例。