[英]Markup extension in XAML for binding to ISubject<string>
If I have the following view model如果我有以下视图模型
class Foo : INotifyPropertyChanged {
ISubject<string> Name { ... }
}
and some imagined XAML code和一些想象的 XAML 代码
<TextBox Text="{my:Subscribe Path=Name}/>
I wish the two way binding to behave that我希望这两种方式绑定的行为
As WPF only supports INPC directly my idea is to create a proxy INPC object in via a markup extension由于 WPF 仅直接支持 INPC,我的想法是通过标记扩展创建一个代理 INPC 对象
class WPFSubjectProxy : INotifyPropertyChanged{
string Value { ... }
}
The proxy would be wired up to the subject as so代理将如此连接到主题
subject.Subscribe(v=>proxy.Value=v);
proxy
.WhenAny(p=>p.Value, p.Value)
.Subscribe(v=>subject.OnNext(v))
Note WhenAny is a ReactiveUI
helper for subscribing to INPC events.注意 WhenAny 是用于订阅 INPC 事件的ReactiveUI
助手。
But then I would need to generate a binding and return that via the markup extension.但是我需要生成一个绑定并通过标记扩展返回它。
I know what I want to do but can't figure out the Markup extension magic to put it all together.我知道我想做什么,但无法弄清楚将它们组合在一起的标记扩展魔法。
It's hard to say without seeing specifically what you're struggling with, but perhaps this helps?很难没有看到具体情况,你正在与挣扎说什么,但或许这可以帮助?
EDIT编辑
The solution I (bradgonesurfing) came up with is below thanks to the pointer in the assigned correct answer.由于指定的正确答案中的指针,我(bradgonesurfing)提出的解决方案如下。
Nodes节点
and the implementing code.和实现代码。 It has a dependency on ReactiveUI and a helper function in a private library for binding ISubject to a mutable property on an INPC supporting object它依赖于 ReactiveUI 和私有库中的辅助函数,用于将 ISubject 绑定到 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;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.