65.9K
CodeProject 正在变化。 阅读更多。
Home

最佳反应式框架扩展

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (15投票s)

2014年2月20日

LGPL3

2分钟阅读

viewsIcon

48838

downloadIcon

543

由于反应式框架,对重复的意大利面条代码进行了一些很好的代码重写

介绍  

你们中的一些人可能还记得我对 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 提要。 ;)

无论如何,该解决方案附带了所有内容的完整单元测试,请随意使用它,如果还有更多您需要的东西,如果您不需要所有东西,请随意复制/粘贴我的代码。

© . All rights reserved.