пятница, 4 ноября 2011 г.

C#: Пишем в Control из Thread

Решений немало.

Простое, как грабли, через делегат:
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
    someLabel.Text = newText; // runs on UI thread
});

То же самое, вынесено в отдельную функцию и выверено по MSDN:

delegate void UpdateLabelDelegate (string message);

void UpdateLabel (string message)
{
    if (InvokeRequired)
    {
         Invoke (new UpdateLabelDelegate (UpdateLabel), new object[] { message });
         return;
    }
    MyLabelControl.Text = message;
}

Там же - замечательные LINQ-оподобные конструкции, которые не так просто вставить в Blogger - там есть Template-овы конструкции вроде < Func <, а Blogger принимает их за теги. Поэтому не забываем ставить пробелы: Очаровательное LINQ-оподобное решение:

private delegate void SetPropertyThreadSafeDelegate(Control @this, Expression< Func > property, TResult value);

public static void SetPropertyThreadSafe(this Control @this, Expression< Func > property, TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;

if (propertyInfo == null ||
!@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
@this.GetType().GetProperty(propertyInfo.Name, propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}

if (@this.InvokeRequired)
{
@this.Invoke(new SetPropertyThreadSafeDelegate(SetPropertyThreadSafe), new object[] { @this, property, value });
}
else
{
@this.GetType().InvokeMember(propertyInfo.Name, BindingFlags.SetProperty, null, @this, new object[] { value });
}
}

Улучшенные вариант с проверкой на null и более жёсткой типизацией:

public static void SetPropertyInGuiThread< C, V >(this C control, Expression< Func < C, V >> property, V value) where C : Control
{
    var memberExpression = property.Body as MemberExpression;
    if (memberExpression == null)
        throw new ArgumentException("The 'property' expression must specify a property on the control.");

    var propertyInfo = memberExpression.Member as PropertyInfo;
    if (propertyInfo == null)
        throw new ArgumentException("The 'member' expression must specify a property on the control.");

    if (control.InvokeRequired)
        control.Invoke(
            (Action< C, Expression< Func < C, V >>, V>)SetPropertyInGuiThread,
            new object[] { control, property, value }
        );
    else
        propertyInfo.SetValue(control, value, null);
}

Комментариев нет:

Отправить комментарий