XAML中用于绑定issubject 的标记扩展
本文关键字:扩展 string 用于 绑定 issubject XAML | 更新日期: 2023-09-27 18:09:29
如果我有以下视图模型
class Foo : INotifyPropertyChanged {
ISubject<string> Name { ... }
}
和一些想象中的XAML代码
<TextBox Text="{my:Subscribe Path=Name}/>
我希望双向绑定的行为
- 主题。在UI 中更新文本框时调用onNext。
- 文本框通过订阅主题更新。订阅
由于WPF只直接支持INPC,我的想法是创建一个代理INPC对象通过一个标记扩展名
class WPFSubjectProxy : INotifyPropertyChanged{
string Value { ... }
}
代理将连接到主题,如下
subject.Subscribe(v=>proxy.Value=v);
proxy
.WhenAny(p=>p.Value, p.Value)
.Subscribe(v=>subject.OnNext(v))
注意WhenAny是用于订阅的ReactiveUI
helperINPC事件。
但是我需要生成一个绑定并返回通过标记扩展名
我知道我想做什么,但不知道该怎么做
如果没有看到你在挣扎什么,很难说,但也许这有帮助?
编辑
我(bradgonesurfing)想出的解决方案是下面感谢指针在正确答案
节点
和实现代码。它依赖于ReactiveUI和私有库中的辅助函数,用于将issubject绑定到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;
}
}
}