2016-08-08 3 views
2

Почему безопасно обновлять часть свойств System.Windows.Forms.Control из другой темы по сравнению с другими свойствами, которые небезопасны, и программист должен использовать Delegate?Почему безопасно обновлять некоторые свойства элемента управления из другого потока?

Например, ForeColor по сравнению с Text.

Не могли бы вы объяснить это с точки зрения дизайна?

+4

Где документировано, что 'ForeColor' является потокобезопасным? – Blorgbeard

+3

Просто потому, что он не генерирует исключение, каждый раз не означает, что это безопасно. – Plutonix

+1

Пожалуйста, будьте более конкретными. С какими свойствами вы обладаете уверенностью, вы можете безопасно получить доступ к перекрестным потокам? –

ответ

4

Чтобы ответить на вопрос о том, почему некоторые права доступа к ресурсам поднимают незаконную ошибку поперечного потока, а другие нет, вы можете обратиться к source code for 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; 
       } 
      } 
     } 

    } 
} 

Обратите внимание на использование внутреннего свойства 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; 
        } 
       } 
      } 
     } 
    } 

Обратите внимание на использование 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; 
    } 
} 
+0

Большое вам спасибо за подробный ответ, именно тот ответ, который я надеялся получить. – jonathana

Смежные вопросы