Skip to content
Permalink
Browse files

Fix: WPF producing a warning for BindCommand (#2039)

* Suppress binding warnings for BindCommand on WPF
Fixes #2037
  • Loading branch information...
mgnslndh authored and glennawatson committed May 19, 2019
1 parent ddb56c7 commit 39aca809ddb702c5309fc1780a9607b45fc6ae74
Showing with 123 additions and 41 deletions.
  1. +6 −5 src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.approved.txt
  2. +6 −5 src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net461.approved.txt
  3. +6 −5 src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp2.0.approved.txt
  4. +1 −1 src/ReactiveUI.Tests/Platforms/winforms/API/ApiApprovalTests.Winforms.net461.approved.txt
  5. +1 −1 src/ReactiveUI.Tests/Platforms/wpf/API/ApiApprovalTests.Wpf.net461.approved.txt
  6. +29 −0 src/ReactiveUI.Tests/Platforms/wpf/Mocks/FakeXamlCommandBindingView.cs
  7. +14 −0 src/ReactiveUI.Tests/Platforms/wpf/WpfCommandBindingImplementationTests.cs
  8. +19 −0 src/ReactiveUI.Tests/Resolvers/PocoObservableForPropertyTests.cs
  9. +1 −1 src/ReactiveUI.Winforms/WinformsCreatesObservableForProperty.cs
  10. +6 −2 src/ReactiveUI.Wpf/DependencyObjectObservableForProperty.cs
  11. +2 −0 src/ReactiveUI.Wpf/Registrations.cs
  12. +1 −1 src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs
  13. +2 −1 src/ReactiveUI/Interfaces/ICreatesObservableForProperty.cs
  14. +8 −6 src/ReactiveUI/Mixins/ReactiveNotifyPropertyChangedMixin.cs
  15. +1 −1 src/ReactiveUI/ObservableForProperty/INPCObservableForProperty.cs
  16. +1 −1 src/ReactiveUI/ObservableForProperty/IROObservableForProperty.cs
  17. +2 −2 src/ReactiveUI/ObservableForProperty/POCOObservableForProperty.cs
  18. +1 −1 src/ReactiveUI/Platforms/android/AndroidObservableForWidgets.cs
  19. +1 −1 src/ReactiveUI/Platforms/apple-common/KVOObservableForProperty.cs
  20. +1 −1 src/ReactiveUI/Platforms/apple-common/ObservableForPropertyBase.cs
  21. +9 −6 src/ReactiveUI/Platforms/uap/DependencyObjectObservableForProperty.cs
  22. +5 −0 src/ReactiveUI/RxApp.cs
@@ -1,4 +1,4 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("ReactiveUI.AndroidSupport")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("ReactiveUI.AndroidSupport")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("ReactiveUI.Tests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("ReactiveUI.Winforms")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("ReactiveUI.Wpf")]
@@ -171,7 +171,7 @@ namespace ReactiveUI
public interface ICreatesObservableForProperty : Splat.IEnableLogger
{
int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False);
}
public interface IHandleObservableErrors
{
@@ -198,7 +198,7 @@ namespace ReactiveUI
{
public INPCObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged, bool suppressWarnings = False) { }
}
public class Interaction<TInput, TOutput>
{
@@ -293,7 +293,7 @@ namespace ReactiveUI
{
public IROObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public interface IRoutableViewModel : ReactiveUI.INotifyPropertyChanging, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged
{
@@ -414,7 +414,7 @@ namespace ReactiveUI
{
public POCOObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public class PropertyBinderImplementation : ReactiveUI.IPropertyBinderImplementation, Splat.IEnableLogger
{
@@ -609,6 +609,7 @@ namespace ReactiveUI
public static System.IObserver<System.Exception> DefaultExceptionHandler { get; set; }
public static System.Reactive.Concurrency.IScheduler MainThreadScheduler { get; set; }
public static bool SupportsRangeNotifications { get; set; }
public static bool SuppressViewCommandBindingMessage { get; set; }
public static ReactiveUI.ISuspensionHost SuspensionHost { get; set; }
public static System.Reactive.Concurrency.IScheduler TaskpoolScheduler { get; set; }
}
@@ -171,7 +171,7 @@ namespace ReactiveUI
public interface ICreatesObservableForProperty : Splat.IEnableLogger
{
int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False);
}
public interface IHandleObservableErrors
{
@@ -198,7 +198,7 @@ namespace ReactiveUI
{
public INPCObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged, bool suppressWarnings = False) { }
}
public class Interaction<TInput, TOutput>
{
@@ -293,7 +293,7 @@ namespace ReactiveUI
{
public IROObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public interface IRoutableViewModel : ReactiveUI.INotifyPropertyChanging, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged
{
@@ -419,7 +419,7 @@ namespace ReactiveUI
{
public POCOObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public class PropertyBinderImplementation : ReactiveUI.IPropertyBinderImplementation, Splat.IEnableLogger
{
@@ -525,7 +525,7 @@ namespace ReactiveUI
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> ObservableForProperty<TSender, TValue>(this TSender @this, System.Linq.Expressions.Expression<System.Func<TSender, TValue>> property, bool beforeChange = False, bool skipInitial = True) { }
public static System.IObservable<TRet> ObservableForProperty<TSender, TValue, TRet>(this TSender @this, System.Linq.Expressions.Expression<System.Func<TSender, TValue>> property, System.Func<TValue, TRet> selector, bool beforeChange = False)
where TSender : class { }
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> SubscribeToExpressionChain<TSender, TValue>(this TSender source, System.Linq.Expressions.Expression expression, bool beforeChange = False, bool skipInitial = True) { }
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> SubscribeToExpressionChain<TSender, TValue>(this TSender source, System.Linq.Expressions.Expression expression, bool beforeChange = False, bool skipInitial = True, bool suppressWarnings = False) { }
}
[System.Runtime.Serialization.DataContractAttribute()]
public class ReactiveObject : ReactiveUI.IHandleObservableErrors, ReactiveUI.INotifyPropertyChanging, ReactiveUI.IReactiveNotifyPropertyChanged<ReactiveUI.IReactiveObject>, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged
@@ -613,6 +613,7 @@ namespace ReactiveUI
public static System.IObserver<System.Exception> DefaultExceptionHandler { get; set; }
public static System.Reactive.Concurrency.IScheduler MainThreadScheduler { get; set; }
public static bool SupportsRangeNotifications { get; set; }
public static bool SuppressViewCommandBindingMessage { get; set; }
public static ReactiveUI.ISuspensionHost SuspensionHost { get; set; }
public static System.Reactive.Concurrency.IScheduler TaskpoolScheduler { get; set; }
}
@@ -165,7 +165,7 @@ namespace ReactiveUI
public interface ICreatesObservableForProperty : Splat.IEnableLogger
{
int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False);
System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False);
}
public interface IHandleObservableErrors
{
@@ -192,7 +192,7 @@ namespace ReactiveUI
{
public INPCObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged, bool suppressWarnings = False) { }
}
public class Interaction<TInput, TOutput>
{
@@ -287,7 +287,7 @@ namespace ReactiveUI
{
public IROObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public interface IRoutableViewModel : ReactiveUI.INotifyPropertyChanging, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged
{
@@ -413,7 +413,7 @@ namespace ReactiveUI
{
public POCOObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public class PropertyBinderImplementation : ReactiveUI.IPropertyBinderImplementation, Splat.IEnableLogger
{
@@ -519,7 +519,7 @@ namespace ReactiveUI
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> ObservableForProperty<TSender, TValue>(this TSender @this, System.Linq.Expressions.Expression<System.Func<TSender, TValue>> property, bool beforeChange = False, bool skipInitial = True) { }
public static System.IObservable<TRet> ObservableForProperty<TSender, TValue, TRet>(this TSender @this, System.Linq.Expressions.Expression<System.Func<TSender, TValue>> property, System.Func<TValue, TRet> selector, bool beforeChange = False)
where TSender : class { }
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> SubscribeToExpressionChain<TSender, TValue>(this TSender source, System.Linq.Expressions.Expression expression, bool beforeChange = False, bool skipInitial = True) { }
public static System.IObservable<ReactiveUI.IObservedChange<TSender, TValue>> SubscribeToExpressionChain<TSender, TValue>(this TSender source, System.Linq.Expressions.Expression expression, bool beforeChange = False, bool skipInitial = True, bool suppressWarnings = False) { }
}
[System.Runtime.Serialization.DataContractAttribute()]
public class ReactiveObject : ReactiveUI.IHandleObservableErrors, ReactiveUI.INotifyPropertyChanging, ReactiveUI.IReactiveNotifyPropertyChanged<ReactiveUI.IReactiveObject>, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged
@@ -607,6 +607,7 @@ namespace ReactiveUI
public static System.IObserver<System.Exception> DefaultExceptionHandler { get; set; }
public static System.Reactive.Concurrency.IScheduler MainThreadScheduler { get; set; }
public static bool SupportsRangeNotifications { get; set; }
public static bool SuppressViewCommandBindingMessage { get; set; }
public static ReactiveUI.ISuspensionHost SuspensionHost { get; set; }
public static System.Reactive.Concurrency.IScheduler TaskpoolScheduler { get; set; }
}
@@ -104,7 +104,7 @@ namespace ReactiveUI.Winforms
{
public WinformsCreatesObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
}
namespace ReactiveUI.Winforms.Legacy
@@ -37,7 +37,7 @@ namespace ReactiveUI
{
public DependencyObjectObservableForProperty() { }
public int GetAffinityForObject(System.Type type, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False) { }
public System.IObservable<ReactiveUI.IObservedChange<object, object>> GetNotificationForProperty(object sender, System.Linq.Expressions.Expression expression, string propertyName, bool beforeChanged = False, bool suppressWarnings = False) { }
}
public class PlatformOperations
{
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;

namespace ReactiveUI.Tests.Wpf
{
public class FakeXamlCommandBindingView : IViewFor<CommandBindingViewModel>
{
private readonly Button _buttonDeclaredInXaml;

public FakeXamlCommandBindingView()
{
_buttonDeclaredInXaml = new Button();

this.BindCommand(ViewModel, vm => vm.Command2, v => v._buttonDeclaredInXaml);
}

public string NameOfButtonDeclaredInXaml => nameof(_buttonDeclaredInXaml);

object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (CommandBindingViewModel)value;
}

public CommandBindingViewModel ViewModel { get; set; }
}
}
@@ -11,6 +11,8 @@
using System.Windows;
using System.Windows.Input;
using ReactiveUI.Tests.Xaml;
using Shouldly;
using Splat;
using Xunit;

using FactAttribute = Xunit.WpfFactAttribute;
@@ -37,5 +39,17 @@ public void CommandBindToExplicitEventWireup()
view.Command2.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseUpEvent });
Assert.Equal(1, invokeCount);
}

[Fact]
public void BindCommandShouldNotWarnWhenBindingToFieldDeclaredInXaml()
{
var testLogger = new TestLogger();
Locator.CurrentMutable.RegisterConstant<ILogger>(testLogger);

var vm = new CommandBindingViewModel();
var view = new FakeXamlCommandBindingView { ViewModel = vm };

testLogger.Messages.ShouldNotContain(t => t.Item1.Contains(nameof(POCOObservableForProperty)) && t.Item1.Contains(view.NameOfButtonDeclaredInXaml) && t.Item3 == LogLevel.Warn);
}
}
}
@@ -10,6 +10,7 @@
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Splat;
using Xunit;

@@ -45,6 +46,24 @@ public void NotificationPocoErrorOnBind()
Assert.Equal(testLogger.LastMessages[0], $"{nameof(POCOObservableForProperty)}: The class {typeof(PocoType).FullName} property {nameof(PocoType.Property1)} is a POCO type and won't send change notifications, WhenAny will only return a single value!");
}

[Fact]
public void NotificationPocoSuppressErrorOnBind()
{
var instance = new POCOObservableForProperty();

var testLogger = new TestLogger();
Locator.CurrentMutable.RegisterConstant<ILogger>(testLogger);

var testClass = new PocoType();

Expression<Func<PocoType, string>> expr = x => x.Property1;
var exp = Reflection.Rewrite(expr.Body);

instance.GetNotificationForProperty(testClass, exp, exp.GetMemberInfo().Name, false, true).Subscribe(_ => { });

testLogger.LastMessages.ShouldNotContain(m => m.Contains(nameof(POCOObservableForProperty)));
}

private class PocoType
{
public string Property1 { get; set; }
@@ -43,7 +43,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang
}

/// <inheritdoc/>
public IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, Expression expression, string propertyName, bool beforeChanged = false)
public IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, Expression expression, string propertyName, bool beforeChanged = false, bool suppressWarnings = false)
{
var ei = eventInfoCache.Get(Tuple.Create(sender.GetType(), propertyName));

0 comments on commit 39aca80

Please sign in to comment.
You can’t perform that action at this time.