System.Windows.Forms.Control与其他不安全的属性相比,为什么从另一个线程更新 的部分属性是安全的,并且程序员必须使用Delegate?
例如,ForeColor比较Text.
有人可以从设计的角度解释这一点吗?
要回答你的问题,为什么一些属性访问引发非法跨线程错误和其他不这样做,你可以参考源代码System.Windows.Forms.Control。它需要进行一些挖掘,但它确实看起来好像建议某些访问是线程安全的,例如获取Text属性但设置它不是。
实际上,将所有控制访问视为非线程安全的传统智慧是最佳实践。
public virtual string Text {
get {
if (CacheTextInternal) {
return(text == null) ? "" : text;
}
else {
return WindowText;
}
}
set {
if (value == null) {
value = "";
}
if (value == Text) {
return;
}
if (CacheTextInternal) {
text = value;
}
WindowText = value;
OnTextChanged(EventArgs.Empty);
if( this.IsMnemonicsListenerAxSourced ){
for( Control ctl = this; ctl != null; ctl = ctl.ParentInternal ) {
ActiveXImpl activeXImpl = (ActiveXImpl)ctl.Properties.GetObject(PropActiveXImpl);
if( activeXImpl != null ) {
activeXImpl.UpdateAccelTable();
break;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意上面代码中内部 WindowText 属性的使用。
/// <devdoc>
/// The current text of the Window; if the window has not yet been created, stores it in the control.
/// If the window has been created, stores the text in the underlying win32 control.
/// This property should be used whenever you want to get at the win32 control's text. For all other cases,
/// use the Text property - but note that this is overridable, and any of your code that uses it will use
/// the overridden version in controls that subclass your own.
/// </devdoc>
internal virtual string WindowText {
get {
if (!IsHandleCreated) {
if (text == null) {
return "";
}
else {
return text;
}
}
using (new MultithreadSafeCallScope()) {
// it's okay to call GetWindowText cross-thread.
//
int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(window, Handle));
// Check to see if the system supports DBCS character
// if so, double the length of the buffer.
if (SystemInformation.DbcsEnabled) {
textLen = (textLen * 2) + 1;
}
StringBuilder sb = new StringBuilder(textLen + 1);
UnsafeNativeMethods.GetWindowText(new HandleRef(window, Handle), sb, sb.Capacity);
return sb.ToString();
}
}
set {
if (value == null) value = "";
if (!WindowText.Equals(value)) {
if (IsHandleCreated) {
UnsafeNativeMethods.SetWindowText(new HandleRef(window, Handle), value);
}
else {
if (value.Length == 0) {
text = null;
}
else {
text = value;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意使用MultithreadSafeCallScope的get代码。还要注意Handle会抛出跨线程错误的属性的使用;我相信Handle财产充当守门员支票跨线程访问。
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
Run Code Online (Sandbox Code Playgroud)