2013-04-16 62 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