2013-04-16 33 views
4

如果我有以下视图模型标记扩展结合ISubject <string>

class Foo : INotifyPropertyChanged { 

    ISubject<string> Name { ... } 

} 

和一些想象的XAML代码

<TextBox Text="{my:Subscribe Path=Name}/> 

祝双向绑定的行为是

  • Subject.onNext当文本框在UI中更新时调用
  • 文本框通过订阅Subject.Subscribe

由于WPF更新只支持直接INPC我的想法是通过标记扩展

class WPFSubjectProxy : INotifyPropertyChanged{ 

    string Value { ... } 

} 

代理在创建代理INPC对象 将连入主题为这样

subject.Subscribe(v=>proxy.Value=v); 

proxy 
    .WhenAny(p=>p.Value, p.Value) 
    .Subscribe(v=>subject.OnNext(v)) 

注WhenAny是ReactiveUI帮手订阅 INPC事件。

但是,然后我需要生成绑定并通过标记扩展返回 。

我知道我想要做什么,但无法弄清楚标记扩展魔术把它放在一起。

回答

2

很难说没有具体看到你在挣扎什么,但也许this有帮助吗?

编辑

我(bradgonesurfing)想出了是由于在 分配正确的答案指针下面的解决方案。

节点

和执行代码。它有ReactiveUI的依赖,并在私人图书馆的辅助功能的支持INPC对象

using ReactiveUI.Subjects; 
using System; 
using System.Linq; 
using System.Reactive.Subjects; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Markup; 

namespace ReactiveUI.Markup 
{ 
    [MarkupExtensionReturnType(typeof(BindingExpression))] 
    public class SubscriptionExtension : MarkupExtension 
    { 
     [ConstructorArgument("path")] 
     public PropertyPath Path { get; set; } 

     public SubscriptionExtension() { } 

     public SubscriptionExtension(PropertyPath path) 
     { 
      Path = Path; 
     } 

     class Proxy : ReactiveObject 
     { 
      string _Value; 
      public string Value 
      { 
       get { return _Value; } 
       set { this.RaiseAndSetIfChanged(value); } 
      } 
     } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      var pvt = serviceProvider as IProvideValueTarget; 
      if (pvt == null) 
      { 
       return null; 
      } 

      var frameworkElement = pvt.TargetObject as FrameworkElement; 
      if (frameworkElement == null) 
      { 
       return this; 
      } 


      object propValue = GetProperty(frameworkElement.DataContext, Path.Path); 

      var subject = propValue as ISubject<string>; 

      var proxy = new Proxy(); 
      Binding binding = new Binding() 
      { 
       Source = proxy, 
       Path = new System.Windows.PropertyPath("Value") 
      }; 

      // Bind the subject to the property via a helper (in private library) 
      var subscription = subject.ToMutableProperty(proxy, x => x.Value); 

      // Make sure we don't leak subscriptions 
      frameworkElement.Unloaded += (e,v) => subscription.Dispose(); 

      return binding.ProvideValue(serviceProvider); 
     } 

     private static object GetProperty(object context, string propPath) 
     { 
      object propValue = propPath 
       .Split('.') 
       .Aggregate(context, (value, name) 
        => value.GetType() 
         .GetProperty(name) 
         .GetValue(value, null)); 
      return propValue; 
     } 

    } 
} 
+0

我添加了一个解决方案,以显示我想出了答案上结合ISubject到一个可变的特性。它的工作到目前为止:) – bradgonesurfing

+0

嗨,我真的很喜欢你的解决方案,但我有一个问题:在运行时我总是得到一个空的DataContext,因为使用Caliburn.Micro的WindowManager首先创建视图,然后附加ViewModel,因此MarkupExt被解析在View获得它的DataContext之前。你知道任何解决方法来解决这个问题吗?谢谢你,兄弟! – Sergio

+0

是的,我有一个解决方案。我现在使用它的一个变量来监听datacontext的变化。我会在星期一去找。如果我不发布,请在这里再次ping我。 – bradgonesurfing