1

我正在尝试在某些 GUI 场景中使用 RxJS。我遇到了一个有趣的案例。我有一个可以查看、编辑和创建实体的小部件。

当您单击“AddNewEntity”按钮时。编辑小部件创建一个空实体,加载它并更改为编辑模式。但是,如果您已经处于编辑模式,它会询问您是否想先恢复更改,一旦您单击“是”,就会发生与前面所述相同的情况。

所以我认为 Rx 可能会帮助我。这是代码。

        Rx.Observable.Merge([

            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isNotInEditMode),
            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isInEditMode)
                      .Select(function (id) {
                          return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
                            .Where(function (answer) { return answer === true; });
                      })
                      .Switch()
        ])
        .Subscribe(self, function () {
            var entity = createNewEntity();
            editWidget.loadEntity(currentEntity);
            editWidget.setEditMode();
        });

基本上我正在合并两个流。按钮的一个点击流,该按钮由状态为“NotInEditMode”的小部件的状态过滤。另一个被过滤到相反状态的按钮的点击流被投射到对话框的返回值流中。请注意,对话框的返回值是 bool 的 AsyncSubject,它表示给定的答案。

现在是棘手的部分!它不能这样工作!为什么?因为当状态为“NotInEditMode”时,第一个流匹配,它将小部件设置为编辑模式,现在第二个流(由于合并内部的顺序而随后运行)也将匹配,这基本上导致完全不一致的状态(解锁编辑模式加上打开对话框)。

我找到了两种解决方法。第一个,更改合并中的顺序,使其看起来像这样:

        Rx.Observable.Merge([
            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isInEditMode)
                      .Select(function (id) {
                          return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
                            .Where(function (answer) { return answer === true; });
                      })
                      .Switch(),
            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isNotInEditMode)                
        ])
        .Subscribe(self, function () {
            var entity = createNewEntity();
            editWidget.loadEntity(currentEntity);
            editWidget.setEditMode();
        });

但是,我不喜欢这个解决方案。这对读者来说并不明显。

幸运的是,我找到了另一个解决方案:

        Rx.Observable.Merge([

            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isNotInEditMode),
            editWidget.getObservable('AddNewEntityButtonClicked')
                      .Where(isInEditMode)
                      .Select(function (id) {
                          return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
                            .Where(function (answer) { return answer === true; });
                      })
                      .Switch()
        ])
        .Take(1)
        .Repeat()
        .Subscribe(self, function () {
            var entity = createNewEntity();
            editWidget.loadEntity(currentEntity);
            editWidget.setEditMode();
        });

背后的想法是只有一条路可以走,所以第一个匹配场景应该中止所有其他场景。

但是,我想知道是否有更清洁的解决方案,或者我是否正在尝试将 Rx 用于它不是为它设计的东西;-)

4

1 回答 1

1

我想我找到了一个干净的解决方案:

                  editWidget.getObservable('NewButtonClicked')
                            .Select(function () {
                                return isInEditMode() ? dialogWidget.question("Reject Changes", "You are in edit mode. Reject Changes?)
                                                               .Where(function (answer) { return answer === true; }) : Rx.Observable.Return(true);
                            })
                            .Switch()
                            .Subscribe(function(){
                                currentEntity = options.createNewEntity();
                                editWidgetLoadEntity(currentEntity);
                                editWidget.enable();
                            });
于 2011-05-14T18:29:13.693 回答