gpt4 book ai didi

c# - 仅在成功提交的窗口内观察更改

转载 作者:行者123 更新时间:2023-11-30 15:32:42 24 4
gpt4 key购买 nike

假设我有以下类(class):

public class Person : ReactiveObject, IEditableObject
{
private string name;
private string nameCopy;

public string Name
{
get { return this.name; }
set { this.RaiseAndSetIfChanged(ref this.name, value); }
}

public void BeginEdit()
{
this.nameCopy = this.name;
}

public void CancelEdit()
{
this.name = this.nameCopy;
}

public void EndEdit()
{
}
}

现在假设我想创建一个可观察的序列(属于 Unit ),每当对 Name 的更改提交时,它就会“滴答作响” .也就是说,我只关心 Name 的变化。在调用 BeginEdit 之间发生的以及随后对 EndEdit 的调用.调用 CancelEdit 之前的任何更改应该被忽略,序列不应该打勾。

我正在努力思考如何使用 Rx 做到这一点。看来我需要管道中某处的状态才能知道更改是否发生在 BeginEdit 的窗口期间/EndEdit电话。我想我可以为所有内容添加时间戳并比较时间戳,但这似乎是一个令人讨厌的 hack。

我非常接近使用专用的 Subject用于编辑操作以及 Observable.Merge :

public class Person : ReactiveObject, IEditableObject
{
private readonly Subject<EditAction> editActions;
private readonly IObservable<Unit> changedDuringEdit;
private string name;
private string nameCopy;

public Person()
{
this.editActions = new Subject<EditAction>();

var nameChanged = this.ObservableForProperty(x => x.Name).Select(x => x.Value);
var editBeginning = this.editActions.Where(x => x == EditAction.Begin);
var editCommitted = this.editActions.Where(x => x == EditAction.End);

this.changedDuringEdit = nameChanged
.Buffer(editBeginning, _ => editCommitted)
.Where(x => x.Count > 0)
.Select(_ => Unit.Default);
}

public IObservable<Unit> ChangedDuringEdit
{
get { return this.changedDuringEdit; }
}

public string Name
{
get { return this.name; }
set { this.RaiseAndSetIfChanged(ref this.name, value); }
}

public void BeginEdit()
{
this.editActions.OnNext(EditAction.Begin);
this.nameCopy = this.name;
}

public void CancelEdit()
{
this.editActions.OnNext(EditAction.Cancel);
this.Name = this.nameCopy;
}

public void EndEdit()
{
this.editActions.OnNext(EditAction.End);
}

private enum EditAction
{
Begin,
Cancel,
End
}
}

但是,如果取消了多个更改,然后提交了一个更改,则可观察对象会在提交时滴答多次(每次取消前一次,提交时再次滴答)。更不用说我得到一个 List<Unit> 的事实我实际上并不需要。在某种程度上,这仍然可以满足我的用例,但不能满足我的好奇心或代码美感。

我觉得 Join应该相当优雅地解决这个问题:

var nameChanged = this.ObservableForProperty(x => x.Name).Select(_ => Unit.Default);
var editBeginning = this.editActions.Where(x => x == EditAction.Begin);
var editCommitted = this.editActions.Where(x => x == EditAction.End);
var editCancelled = this.editActions.Where(x => x == EditAction.Cancel);
var editCancelledOrCommitted = editCancelled.Merge(editCommitted);

this.changedDuringEdit = editBeginning
.Join(nameChanged, _ => editCancelledOrCommitted, _ => editCancelledOrCommitted, (editAction, _) => editAction == EditAction.End)
.Where(x => x)
.Select(_ => Unit.Default);

但这也行不通。好像Join未订阅 editCancelledOrCommitted ,出于我不明白的原因。

有人知道如何彻底地解决这个问题吗?

最佳答案

这是我的做法:

IObservable<Unit> beginEditSignal = ...;
IObservable<Unit> commitSignal = ...;
IObservable<Unit> cancelEditSignal = ...;
IObservable<T> propertyChanges = ...;


// this will yield an array after each commit
// that has all of the changes for that commit.
// nothing will be yielded if the commit is canceled
// or if the changes occur before BeginEdit.
IObservable<T[]> commitedChanges = beginEditSignal
.Take(1)
.SelectMany(_ => propertyChanges
.TakeUntil(commitSignal)
.ToArray()
.Where(changeList => changeList.Length > 0)
.TakeUntil(cancelEditSignal))
.Repeat();


// if you really only want a `Unit` when something happens
IObservable<Unit> changeCommittedSignal = beginEditSignal
.Take(1)
.SelectMany(_ => propertyChanges
.TakeUntil(commitSignal)
.Count()
.Where(c => c > 0)
.Select(c => Unit.Default)
.TakeUntil(cancelEditSignal))
.Repeat();

关于c# - 仅在成功提交的窗口内观察更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18480491/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com