2015-08-17 4 views
2

У меня есть класс Foo с событием, которое публикует перечисление FooState. Я хочу превратить это событие в наблюдаемое, которое повторяет последнее значение для новых подписчиков.Опубликовать последнее значение события для новых подписчиков

Даже если подписчиков нет, любой новый абонент должен получить последнее значение.

public enum FooState 
{ 
    Stopped = 0, 
    Starting = 1, 
    Running = 2,   
} 

public delegate void FooEventHandler(object sender, FooEventArgs e); 

public class FooEventArgs : EventArgs 
{ 
    public FooEventArgs(FooState fooState) 
    { 
     this.State = fooState; 
    } 

    public FooState State {get; private set;} 
} 

public class Foo 
{ 
    public event FooEventHandler FooEvent; 

    public void OnFooEvent(FooState state) 
    { 
     var fooEvent = FooEvent; 

     if(fooEvent != null) 
     { 
      fooEvent(this, new FooEventArgs(state)); 
     } 
    } 
} 

Мои попытки до сих пор вращались вокруг использования Publish, RefCount и Replay. Но ни одна из комбинаций, которые я пробовала работать, если я подписываюсь на наблюдаемый после того, как я запустил это событие.

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

var foo = new Foo(); 

    var obs = Observable.FromEventPattern<FooEventHandler, FooEventArgs>(
             h => foo.FooEvent += h, 
             h => foo.FooEvent -= h) 
            .DistinctUntilChanged() 
            .Replay(1) 
            .RefCount(); 

    // Works if this line is uncomented. 
    //obs.Subscribe(x => Console.WriteLine("Early Subscriber = " + x.EventArgs.State)); 

    foo.OnFooEvent(FooState.Running); 

    obs.Subscribe(x => Console.WriteLine("Late Subscriber = " + x.EventArgs.State)); 

Кто-нибудь знает, как это сделать с помощью Rx?

ответ

3

RefCount подключается только после первой подписки. Если вы хотите иметь мелкозернистый контроль при подключении, вы должны использовать Replay + Connect.

Так что вместо того, чтобы:

var publishedSource = eventSource.DistinctUntilChanged().Replay(1); 

var connection = publishedSource.Connect(); 

//Subscribe to publishedSource to receive events and dispose of 
connection when you are done. 

Сообщение от моего телефона, чтобы извинения за любые ошибки синтаксиса заранее.

+0

Есть ли способ автоматически «Подключиться» при создании наблюдаемого? т. е. мне не нужно управлять подпиской 'Connect' отдельно? –

+0

@NedStoyanov Как вы собираетесь определить, когда пришло время очистить ваш поток? В основном, как вы знаете, когда поток сделан? – paulpdaniels

+1

@NedStoyanov - Вам либо нужно подключить все через вызов '.Connect()' или через '.Subscribe (...)'. Но поскольку вы хотите делиться ценностями между подписками, у вас мало выбора, кроме как использовать '.Connect()'. – Enigmativity

1

Rx делает правильную вещь, преобразуя ваши уведомления о событиях в ваш поток и воспроизводя их, но то, что вы просите, это: «Почему, когда я подписываюсь на мероприятие, не получаю начальное состояние».

События не работают. Если я делаю + = на foo.FooEvent, я не получаю немедленный триггер с текущим значением. Я получаю уведомление только после его изменения. Как вы заметили, «Повтор» будет воспроизводить последующие события, но не предоставлять состояние во время подписки.

Чтобы решить вашу проблему, вам необходимо убедиться, что текущее значение помещено в поток, прежде чем подключать поток для уведомлений об изменениях. Проверьте Observable.StartWith().

i.e. «.StartWith (foo.State)» перед вызовом DistinctUntilChanged() (сразу после .FromEventPattern).

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