最佳反应式框架扩展






4.98/5 (15投票s)
由于反应式框架,对重复的意大利面条代码进行了一些很好的代码重写
介绍
你们中的一些人可能还记得我对 Rx Framework 的喜爱始于一个宠物项目 我写过的文章。
现在,我几乎每天都在使用 Rx Framework,但这要归功于一个小小的个人框架,它让我的生活更轻松了。
所以,今天没有长篇大论,毕竟是星期五,只是列举了我最好的反应式框架扩展方法。本文可以被认为是 这篇旧文章 的补充,其中分组了一些我的实用程序类。
最佳
我使用的所有方法,例如 .Subscribe,都将返回一个 IDisposable,如果您想取消订阅,可以将其释放。
如何订阅 PropertyChanged
当您对某些视图模型上发生更改的属性感兴趣时,您通常需要编写以下意大利面条代码
public void UpdateUser(User user)
{
user.PropertyChanged += user_PropertyChanged;
NameChanged();
}
void user_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Name")
NameChanged();
}
private void NameChanged()
{
//Do wonderfull stuff
}
我用
user
.ItemPropertyChanged(u=>u.Name,true)
.Subscribe((args) =>
{
//Do wonderfull stuff with args.NewValue and args.OldValue
});
布尔值在您订阅时直接第一次触发订阅操作。 请注意,您可以使用 args 参数获取属性的 NewValue 和 OldValue,并且不再具有魔术字符串。
如何订阅 CollectionChanged
替换旧的对添加到可观察集合中的每个项目执行某些操作的方法
public void SubscribeToCollection(ObservableCollection<User> users)
{
users.CollectionChanged += users_CollectionChanged;
foreach(var user in users)
{
NewUser(user);
}
}
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.NewItems != null)
foreach(User user in e.NewItems)
{
NewUser(user);
}
}
private void NewUser(User user)
{
//Do something
}
进入反应式方式
users
.ForeachItem()
.Subscribe(user =>
{
//Do something
});
如何订阅 ObservableCollection 中的项目
基本上是将前两种旧方法结合在一起的意大利面条代码。 我用以下意大利面条代替了。
public void SubscribeToCollection(ObservableCollection<User> users)
{
users.CollectionChanged += users_CollectionChanged;
foreach(var user in users)
{
NewUser(user);
}
}
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.NewItems != null)
foreach(User user in e.NewItems)
{
NewUser(user);
}
if(e.OldItems != null)
{
foreach(User user in e.OldItems)
{
user.PropertyChanged -= UserChanged;
}
}
}
private void NewUser(User user)
{
user.PropertyChanged += UserChanged;
}
void UserChanged(object sender, PropertyChangedEventArgs e)
{
//Do wonderfull stuff when one user changes
}
进入干净的版本
users
.ObserveEachItem(u => u.ItemPropertyChanged())
.Subscribe(args =>
{
User user = args.Sender;
//Do wonderfull stuff when one user changes
});
弱事件监听器
您是否尝试过弱订阅一个对象,以便垃圾收集器正确地收集不再在任何地方引用的监听器? 好吧,一个解决方案是阅读此 msdn 页面 并使用 WeakEventManager。 抱歉,我懒得为您阅读。
另一个解决方案是使用我的 ObserveWeakly 方法
var subscription = user.ItemPropertyChanged()
.ObserveWeakly()
.Subscribe(args =>
{
User u = args.Sender;
//User changed do what you want...
});
subscription = null; //OMG forgot to Dispose the subscription !!! memory leak !1!
GC.Collect();
user.AssertSubscribers(0); //Just kidding
订阅依赖属性更改
订阅依赖属性的代码并不简单,正如您在以下代码片段中看到的那样。
TextBox box = new TextBox();
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TextBox.BackgroundProperty, typeof(TextBox));
if(dpd != null)
{
dpd.AddValueChanged(box, (sender, args) =>
{
//Do wonderfull stuff when the background changed
});
}
但不用担心,现在您可以这样做了。
TextBox box = new TextBox();
box.DependencyPropertyChanged<Brush>(TextBox.BackgroundProperty)
.Subscribe(args =>
{
Brush brush = args.NewValue;
});
同步两个 ObservableCollection
我敢肯定您不止一次遇到过这种情况,例如,您需要一个 ObservableCollection<String> ,该集合动态列出您 ObservableCollection<User> 的所有女孩的名字。 这是旧方法
ObservableCollection<String> GirlsNames = new ObservableCollection<String>();
public void SubscribeToCollection(ObservableCollection<User> users)
{
users.CollectionChanged += users_CollectionChanged;
foreach(var user in users)
{
NewUser(user);
}
}
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.NewItems != null)
foreach(User user in e.NewItems)
{
NewUser(user);
}
if(e.OldItems != null)
{
foreach(User user in e.OldItems)
{
GirlsNames.Remove(user.Name);
}
}
}
private void NewUser(User user)
{
if(user.Gender = Gender.Girl)
GirlsNames.Add(user.Name);
}
现在您可以将此意大利面条变成一行: (如果您想停止映射,则始终返回 IDisposable)
users.MapToCollection(GirlsNames, u=>u.Name, u=> u.Gender == Gender.Girl);
结论
我将源代码和二进制文件放在本文中,我还有一个私人的 GIT 存储库和内部 Nuget 提要,用于在我的项目中使用我的框架。 如果您恳求我,我打算切换到公共 GIT 存储库和公共 nuget 提要。 ;)
无论如何,该解决方案附带了所有内容的完整单元测试,请随意使用它,如果还有更多您需要的东西,如果您不需要所有东西,请随意复制/粘贴我的代码。