2013-03-06 2 views
10

У меня есть проблема с методом на C#. Я сделал метод, который вызывает функцию из dll, которую он назвал Phone.GetLampMode(); Теперь Phone.GetLampMode ничего не возвращает. Данные возвращаются в событии 'onGetLampModeResponse'. Есть ли способ, которым я могу подождать в моем методе, пока не получу данные из события onGetLampModeResponse?Метод ожидания до тех пор, пока не будет зафиксировано событие

public bool checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 
    Phone.GetLampMode(btn, null); 

    return true; 
} 

private void Phone_OnGetLampModeResponse(object sender, Phone.GetLampModeResponseArgs e) 
{ 
    var test = e.getLampModeList[0].getLampMode.ToString();  
} 
+1

Что является вторым параметром GetLampMode? Позвольте мне угадать: объект, который вы можете определить сами? И этот объект является «отправителем» в обработчике событий или внутри 'e'? EDIT: Да, это называется userState. Вы можете получить этот пользовательский элемент внутри переменной 'e' в функции обратного вызова. – sinni800

+0

Я могу думать об одном уродливом решении, определяя глобальный 'bool', который установлен в' true', 'OnGetLampModeResponse' и проверяется в цикле' checkLamp'. –

+0

@JohnWillemse это довольно уродливо и не нужно делать, поскольку существует концепция передачи переменных состояния событиям. – sinni800

ответ

9

Одним из решений является использование AutoResetEvent:

public bool checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 

    AutoResetEvent waitHandle = new AutoResetEvent(false); 

    // Pass waitHandle as user state 
    Phone.GetLampMode(btn, waitHandle); 

    // Wait for event completion 
    waitHandle.WaitOne(); 

    return true; 
} 

private void Phone_OnGetLampModeResponse(object sender, Phone.GetLampModeResponseArgs e) 
{ 
    var test = e.getLampModeList[0].getLampMode.ToString(); 

    // Event handler completed 
    // I guess there is some UserState property in the GetLampModeResponseArgs class 
    ((AutoResetEvent)e.UserState).Set(); 
} 

Примечание: объявления вы используете Phone как статический класс/переменной, можно подумать, что вы разрабатываете на Windows Phone ... Если это так, обратите внимание, что вся концепция WP и асинхронного программирования равна , не блокируя поток пользовательского интерфейса таким образом.

+2

Вы просто положили waitHandle в глобальный контекст? Что делать, если вы выполняете его несколько раз и заставляете ваше ожидание полностью застревать? Как этот ответ может быть даже поднят? – sinni800

+0

@ sinni800 Хороший комментарий, но ОП ничего не сказал о многопоточности. Я думаю, он просто хочет сделать что-то синхронно с асинхронным. Если он фактически многопоточен, дескриптор ожидания должен передаваться как параметр метода. – ken2k

+0

он обязательно должен быть передан как userState, в любом случае. Вы рискуете получить нить застряли бесконечно из-за таких ничтожных вещей, как «условия гонки». – sinni800

0

Похоже, что существующая модель близка к асинхронному шаблону на основе событий (EAP). Возможно, вам стоит взглянуть на статью Interop with Other Asynchronous Patterns and Types, которая описывает, как преобразовать такой шаблон в новый шаблон Async на основе задач (TAP).

После того, как у вас есть Task (или Task<T>, вы можете просто Wait для него

+0

Да, ключевые слова Async были бы идеальными .. – sinni800

2

Вы можете обернуть обработчик в асинхронном методе, который должен выглядеть примерно так (непроверенный):.

public async Task<bool> checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 

    var tcs = new TaskCompletionSource<bool>(); 
    var handler = (sender, e) => { 
     Phone.OnGetLampModeResponse -= handler; 
     var test = e.getLampModeList[0].getLampMode.ToString(); 
     tcs.SetResult(true); 
    }; 
    Phone.OnGetLampModeResponse += handler; 

    Phone.GetLampMode(btn, null); 

    return tcs.Task; 
} 

В вашем вызывающем методе, можно было бы написать:

Это имеет то преимущество, что ваш пользовательский интерфейс лань s не блокируется, пока процесс ожидает ответа.

Вот запись в блоге по этой проблеме. Обратите внимание, что Framework 4.5 требуется.

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