Skip to content

Commit

Permalink
breaking change: Make Bind use non-generic IViewFor (#3677)
Browse files Browse the repository at this point in the history
<!-- Please be sure to read the
[Contribute](https://github.com/reactiveui/reactiveui#contribute)
section of the README -->

What kind of change does this PR introduce?

Fix for #3644

What is the current behavior?

BindCommand requires a view inherited from `IViewFor<TViewModel>`
`ReactiveUserControl` inherits `IViewFor<TViewModel>` which requires
Generics which WinForms does not work well with.

What is the new behavior?

Alter `BindCommand` where clause relaxing to `IViewFor`.

NOTE: Bind only requires `IViewFor` and `IViewFor<TViewModel>` inherits
`IViewFor` therefore `BindCommand` is now relaxed to `IViewFor` in the
same way as Bind.

add `ReactiveUserControlNonGeneric` for WinForms inherits `IViewFor`

What might this PR break?

API Change

Please check if the PR fulfills these requirements

 Tests for the changes have been added (for bug fixes / features)
 Docs have been added / updated (for bug fixes / features)
Other information:
  • Loading branch information
ChrisPulman committed Nov 23, 2023
1 parent f3e21de commit 23334c1
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 64 deletions.
Expand Up @@ -81,27 +81,27 @@ namespace ReactiveUI
public static class CommandBinder
{
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
public class CommandBinderImplementation : Splat.IEnableLogger
{
public CommandBinderImplementation() { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
Expand Down
Expand Up @@ -81,27 +81,27 @@ namespace ReactiveUI
public static class CommandBinder
{
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
public class CommandBinderImplementation : Splat.IEnableLogger
{
public CommandBinderImplementation() { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
Expand Down
Expand Up @@ -81,27 +81,27 @@ namespace ReactiveUI
public static class CommandBinder
{
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
public class CommandBinderImplementation : Splat.IEnableLogger
{
public CommandBinderImplementation() { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
Expand Down
Expand Up @@ -79,27 +79,27 @@ namespace ReactiveUI
public static class CommandBinder
{
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public static ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(this TView view, TViewModel? viewModel, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> propertyName, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlName, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
public class CommandBinderImplementation : Splat.IEnableLogger
{
public CommandBinderImplementation() { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.IObservable<TParam?> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
public ReactiveUI.IReactiveBinding<TView, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(TViewModel? viewModel, TView view, System.Linq.Expressions.Expression<System.Func<TViewModel, TProp?>> vmProperty, System.Linq.Expressions.Expression<System.Func<TView, TControl>> controlProperty, System.Linq.Expressions.Expression<System.Func<TViewModel, TParam?>> withParameter, string? toEvent = null)
where TView : class, ReactiveUI.IViewFor<TViewModel>
where TView : class, ReactiveUI.IViewFor
where TViewModel : class
where TProp : System.Windows.Input.ICommand { }
}
Expand Down
Expand Up @@ -32,6 +32,11 @@ namespace ReactiveUI.Winforms
public PlatformOperations() { }
public string? GetOrientation() { }
}
public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor
{
public ReactiveUserControlNonGeneric() { }
protected override void Dispose(bool disposing) { }
}
public class ReactiveUserControl<TViewModel> : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor, ReactiveUI.IViewFor<TViewModel>
where TViewModel : class
{
Expand Down
Expand Up @@ -32,6 +32,11 @@ namespace ReactiveUI.Winforms
public PlatformOperations() { }
public string? GetOrientation() { }
}
public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor
{
public ReactiveUserControlNonGeneric() { }
protected override void Dispose(bool disposing) { }
}
public class ReactiveUserControl<TViewModel> : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor, ReactiveUI.IViewFor<TViewModel>
where TViewModel : class
{
Expand Down
Expand Up @@ -32,6 +32,11 @@ namespace ReactiveUI.Winforms
public PlatformOperations() { }
public string? GetOrientation() { }
}
public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor
{
public ReactiveUserControlNonGeneric() { }
protected override void Dispose(bool disposing) { }
}
public class ReactiveUserControl<TViewModel> : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor, ReactiveUI.IViewFor<TViewModel>
where TViewModel : class
{
Expand Down
Expand Up @@ -30,6 +30,11 @@ namespace ReactiveUI.Winforms
public PlatformOperations() { }
public string? GetOrientation() { }
}
public class ReactiveUserControlNonGeneric : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor
{
public ReactiveUserControlNonGeneric() { }
protected override void Dispose(bool disposing) { }
}
public class ReactiveUserControl<TViewModel> : System.Windows.Forms.UserControl, ReactiveUI.IActivatableView, ReactiveUI.IViewFor, ReactiveUI.IViewFor<TViewModel>
where TViewModel : class
{
Expand Down
23 changes: 23 additions & 0 deletions src/ReactiveUI.Winforms/ReactiveUserControlNonGeneric.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions src/ReactiveUI.Winforms/ReactiveUserControlNonGeneric.cs
@@ -0,0 +1,39 @@
// Copyright (c) 2023 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Windows.Forms;

namespace ReactiveUI.Winforms;

/// <summary>
/// This is an UserControl that is both and UserControl and has a ReactiveObject powers
/// (i.e. you can call RaiseAndSetIfChanged).
/// </summary>
/// <seealso cref="System.Windows.Forms.UserControl" />
/// <seealso cref="ReactiveUI.IViewFor" />
public partial class ReactiveUserControlNonGeneric : UserControl, IViewFor
{
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveUserControlNonGeneric"/> class.
/// </summary>
public ReactiveUserControlNonGeneric() => InitializeComponent();

/// <inheritdoc/>
object? IViewFor.ViewModel { get; set; }

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
components?.Dispose();
}

base.Dispose(disposing);
}
}
6 changes: 3 additions & 3 deletions src/ReactiveUI/Bindings/Command/CommandBinder.cs
Expand Up @@ -50,7 +50,7 @@ static CommandBinder()
Expression<Func<TView, TControl>> controlName,
IObservable<TParam?> withParameter,
string? toEvent = null)
where TView : class, IViewFor<TViewModel>
where TView : class, IViewFor
where TViewModel : class
where TProp : ICommand =>
_binderImplementation.BindCommand(viewModel, view, propertyName, controlName, withParameter, toEvent);
Expand Down Expand Up @@ -79,7 +79,7 @@ static CommandBinder()
Expression<Func<TViewModel, TProp?>> propertyName,
Expression<Func<TView, TControl>> controlName,
string? toEvent = null)
where TView : class, IViewFor<TViewModel>
where TView : class, IViewFor
where TViewModel : class
where TProp : ICommand =>
_binderImplementation.BindCommand(viewModel, view, propertyName, controlName, toEvent);
Expand Down Expand Up @@ -112,7 +112,7 @@ static CommandBinder()
Expression<Func<TView, TControl>> controlName,
Expression<Func<TViewModel, TParam?>> withParameter,
string? toEvent = null)
where TView : class, IViewFor<TViewModel>
where TView : class, IViewFor
where TViewModel : class
where TProp : ICommand
{
Expand Down
Expand Up @@ -45,7 +45,7 @@ public class CommandBinderImplementation : ICommandBinderImplementation
Expression<Func<TView, TControl>> controlProperty,
Expression<Func<TViewModel, TParam?>> withParameter,
string? toEvent = null)
where TView : class, IViewFor<TViewModel>
where TView : class, IViewFor
where TViewModel : class
where TProp : ICommand
{
Expand Down Expand Up @@ -102,7 +102,7 @@ public class CommandBinderImplementation : ICommandBinderImplementation
Expression<Func<TView, TControl>> controlProperty,
IObservable<TParam?> withParameter,
string? toEvent = null)
where TView : class, IViewFor<TViewModel>
where TView : class, IViewFor
where TViewModel : class
where TProp : ICommand
{
Expand Down

0 comments on commit 23334c1

Please sign in to comment.