使用 ReactiveUI 的 BindTo() 更新 XAML 属性会生成警告

rei*_*erh 5 c# wpf mvvm system.reactive reactiveui

我正在尝试更新视图的 XAML 中元素的属性:

this.WhenAnyValue(x => x.ViewModel.IsEnabled).BindTo(this, x => x.MyButton.IsEnabled);
Run Code Online (Sandbox Code Playgroud)

这按预期工作,但是,它在运行时生成警告:

POCOObservableForProperty: rx_bindto_test.MainWindow 是 POCO 类型,不会发送更改通知,WhenAny 只会返回一个值!

我可以通过将表达式更改为:

this.WhenAnyValue(x => x.ViewModel.IsEnabled).Subscribe(b => MyButton.IsEnabled = b);
Run Code Online (Sandbox Code Playgroud)

但我仍然想知道为什么它不能与 BindTo() 一起正常工作。

编辑:它甚至出现常规BindOneWayBind生成此警告。

  1. 我在这里做错了什么?
  2. 并且真的有必要ViewModel在 View 上定义一个依赖属性才能观察到它吗?(当我将它声明为视图上的常规属性时,ReactiveUI 会生成相同的 POCO 警告)我不能简单地使其从 ReactiveObject 继承,因为 C# 不支持多重继承。

主窗口.xaml.cs

public partial class MainWindow : Window, IViewFor<MyViewModel>, IEnableLogger {
    public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel",
        typeof(MyViewModel), typeof(MainWindow));

    public MyViewModel ViewModel {
        get { return (MyViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }

    object IViewFor.ViewModel {
        get { return ViewModel; }
        set { ViewModel = (MyViewModel)value; }
    }

    public MainWindow() {
        InitializeComponent();

        this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext);

        this.WhenAnyValue(x => x.ViewModel.IsEnabled).BindTo(this, x => x.MyButton.IsEnabled);

        ViewModel = new MyViewModel();
        ViewModel.IsEnabled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

主窗口.xaml

<Window x:Class="rx_bindto_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button x:Name="MyButton">My Button</Button>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

视图模型.cs

public class MyViewModel : ReactiveObject, IEnableLogger {
    private bool isEnabled;

    public bool IsEnabled {
        get { return isEnabled; }
        set { this.RaiseAndSetIfChanged(ref isEnabled, value); }
    }
}
Run Code Online (Sandbox Code Playgroud)

Glu*_*uck 5

我认为混淆来自这样一个事实,即您收到关于“MyButton”解析的警告,而不是在 ViewModel 上。

MyButton 是一个“常量”对象,没有任何生命周期(既不是 INPC 也不是 DependencyObject),因此您可以放心地忽略此警告。

或者,您可以注册以下额外的属性解析器,它的行为类似于 FrameworkElement 的每个内部字段的 POCO(减去警告),它非常接近 XAML 中的每个控件(我相信):

Locator.CurrentMutable.Register(() => new CustomPropertyResolver(), typeof(ICreatesObservableForProperty));

public class CustomPropertyResolver : ICreatesObservableForProperty
{
    public int GetAffinityForObject(Type type, string propertyName, bool beforeChanged = false)
    {
        if (!typeof(FrameworkElement).IsAssignableFrom(type))
            return 0;
        var fi = type.GetTypeInfo().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
          .FirstOrDefault(x => x.Name == propertyName);

        return fi != null ? 2 /* POCO affinity+1 */ : 0;
    }

    public IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, bool beforeChanged = false)
    {
        var foo = (FrameworkElement)sender;
        return Observable.Return(new ObservedChange<object, object>(sender, expression), new DispatcherScheduler(foo.Dispatcher))
            .Concat(Observable.Never<IObservedChange<object, object>>());
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好的谢谢各位。对于像我这样的最终用户来说,这只是令人困惑,因为从概念上讲,我并不是真正 _observing_ 目标变量,对我来说,它只是一个值接收器。我忽略了一个事实,即它可能想要监视目标变量,以防它所针对的对象在运行时被替换。 (3认同)