Skip to content

Commit 46ff853

Browse files
author
Paul Betts
committed
Merge pull request #720 from vanderkleij/component-command-binding
Support for the Enabled property of Components in the WinForms command binder
2 parents aeb75b0 + 1043ebf commit 46ff853

File tree

2 files changed

+85
-29
lines changed

2 files changed

+85
-29
lines changed

ReactiveUI.Tests/Winforms/CommandBindingTests.cs

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Windows.Forms;
55
using ReactiveUI.Winforms;
66
using Xunit;
7+
using System.ComponentModel;
78

89
namespace ReactiveUI.Tests.Winforms
910
{
@@ -25,14 +26,12 @@ public void CommandBinderBindsToButton()
2526
commandExecuted = true;
2627
});
2728

28-
var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5));
29-
30-
input.PerformClick();
31-
32-
Assert.True(commandExecuted);
33-
Assert.NotNull(ea);
34-
disp.Dispose();
29+
using (var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) {
30+
input.PerformClick();
3531

32+
Assert.True(commandExecuted);
33+
Assert.NotNull(ea);
34+
}
3635
}
3736

3837
[Fact]
@@ -51,14 +50,36 @@ public void CommandBinderBindsToCustomControl()
5150
commandExecuted = true;
5251
});
5352

54-
var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5));
53+
using (var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) {
54+
input.PerformClick();
5555

56-
input.PerformClick();
56+
Assert.True(commandExecuted);
57+
Assert.NotNull(ea);
58+
}
59+
}
5760

58-
Assert.True(commandExecuted);
59-
Assert.NotNull(ea);
60-
disp.Dispose();
61+
[Fact]
62+
public void CommandBinderBindsToCustomComponent()
63+
{
64+
var fixture = new CreatesWinformsCommandBinding();
65+
var cmd = ReactiveCommand.Create();
66+
var input = new CustomClickableComponent { };
6167

68+
Assert.True(fixture.GetAffinityForObject(input.GetType(), true) > 0);
69+
Assert.True(fixture.GetAffinityForObject(input.GetType(), false) > 0);
70+
bool commandExecuted = false;
71+
object ea = null;
72+
cmd.Subscribe(o => {
73+
ea = o;
74+
commandExecuted = true;
75+
});
76+
77+
using (var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) {
78+
input.PerformClick();
79+
80+
Assert.True(commandExecuted);
81+
Assert.NotNull(ea);
82+
}
6283
}
6384

6485
[Fact]
@@ -73,16 +94,44 @@ public void CommandBinderAffectsEnabledState()
7394

7495
using (var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) {
7596
canExecute.OnNext(true);
76-
7797
Assert.True(input.Enabled);
7898

7999
canExecute.OnNext(false);
100+
Assert.False(input.Enabled);
101+
}
102+
}
80103

104+
[Fact]
105+
public void CommandBinderAffectsEnabledStateForComponents()
106+
{
107+
var fixture = new CreatesWinformsCommandBinding();
108+
var canExecute = new Subject<bool>();
109+
canExecute.OnNext(true);
110+
111+
var cmd = ReactiveCommand.Create(canExecute);
112+
var input = new ToolStripButton { }; // ToolStripButton is a Component, not a Control
113+
114+
using (var disp = fixture.BindCommandToObject(cmd, input, Observable.Return((object)5))) {
115+
canExecute.OnNext(true);
116+
Assert.True(input.Enabled);
117+
118+
canExecute.OnNext(false);
81119
Assert.False(input.Enabled);
82120
}
83121
}
84122
}
85123

124+
public class CustomClickableComponent : Component
125+
{
126+
public event EventHandler Click;
127+
128+
public void PerformClick()
129+
{
130+
if (Click != null)
131+
Click(this, EventArgs.Empty);
132+
}
133+
}
134+
86135
public class CustomClickableControl : Control
87136
{
88137
public void PerformClick()
@@ -99,7 +148,6 @@ public void RaiseMouseUpEvent(System.Windows.Forms.MouseEventArgs args)
99148
{
100149
this.OnMouseUp(args);
101150
}
102-
103151
}
104152

105153
public class CommandBindingImplementationTests

ReactiveUI.Winforms/Winforms/CreatesCommandBinding.cs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Windows.Input;
99
using ReactiveUI;
1010
using System.Reflection;
11+
using System.ComponentModel;
1112

1213
namespace ReactiveUI.Winforms
1314
{
@@ -23,8 +24,6 @@ public class CreatesWinformsCommandBinding : ICreatesCommandBinding
2324
Tuple.Create("MouseUp", typeof (MouseEventArgs)),
2425
};
2526

26-
static readonly PropertyInfo enabledProperty = typeof(Control).GetRuntimeProperty("Enabled");
27-
2827
public int GetAffinityForObject(Type type, bool hasEventTarget)
2928
{
3029
bool isWinformControl = typeof(Control).IsAssignableFrom(type);
@@ -33,7 +32,7 @@ public int GetAffinityForObject(Type type, bool hasEventTarget)
3332

3433
if (hasEventTarget) return 6;
3534

36-
return defaultEventsToBind.Any(x =>{
35+
return defaultEventsToBind.Any(x => {
3736
var ei = type.GetEvent(x.Item1, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
3837
return ei != null;
3938
}) ? 4 : 0;
@@ -76,18 +75,27 @@ public IDisposable BindCommandToObject<TEventArgs>(ICommand command, object targ
7675
command.Execute(useEventArgsInstead ? ea : latestParameter);
7776
}
7877
}));
79-
80-
//only controls have Enabled
81-
if (typeof(Control).IsAssignableFrom(target.GetType())) {
82-
object latestParam = null;
83-
commandParameter.Subscribe(x => latestParam = x);
84-
85-
ret.Add(Observable.FromEventPattern<EventHandler, EventArgs>(x => command.CanExecuteChanged += x, x => command.CanExecuteChanged -= x)
86-
.Select(_ => command.CanExecute(latestParam))
87-
.StartWith(command.CanExecute(latestParam))
88-
.Subscribe(x => {
89-
enabledProperty.SetValue(target, x, null);
90-
}));
78+
79+
Type targetType = target.GetType();
80+
81+
// We initially only accepted Controls here, but this is too restrictive:
82+
// there are a number of Components that can trigger Commands and also
83+
// have an Enabled property, just like Controls.
84+
// For example: System.Windows.Forms.ToolStripButton.
85+
if (typeof(Component).IsAssignableFrom(targetType)) {
86+
PropertyInfo enabledProperty = targetType.GetRuntimeProperty("Enabled");
87+
88+
if (enabledProperty != null) {
89+
object latestParam = null;
90+
commandParameter.Subscribe(x => latestParam = x);
91+
92+
ret.Add(Observable.FromEventPattern<EventHandler, EventArgs>(x => command.CanExecuteChanged += x, x => command.CanExecuteChanged -= x)
93+
.Select(_ => command.CanExecute(latestParam))
94+
.StartWith(command.CanExecute(latestParam))
95+
.Subscribe(x => {
96+
enabledProperty.SetValue(target, x, null);
97+
}));
98+
}
9199
}
92100

93101
return ret;

0 commit comments

Comments
 (0)