Commit 512d9d7
Changed files (9)
product
desktop.ui
bootstrappers
presenters
views
controls
dialogs
specs
unit
ui
presenters
utility
product/desktop.ui/bootstrappers/Bootstrapper.cs
@@ -108,6 +108,7 @@ namespace solidware.financials.windows.ui.bootstrappers
builder.RegisterType<AddNewStockSymbolPresenter>();
builder.RegisterType<AddNewStockSymbolPresenter.AddCommand>();
+ builder.RegisterType<AddNewStockSymbolPresenter.IsValid>();
builder.RegisterType<StockViewModel.MoreCommand>();
product/desktop.ui/presenters/AddNewStockSymbolPresenter.cs
@@ -1,47 +1,33 @@
using System;
-using System.Linq.Expressions;
using gorilla.utility;
using solidware.financials.infrastructure;
using solidware.financials.messages;
using solidware.financials.windows.ui.presenters.validation;
+using solidware.financials.windows.ui.views.controls;
+using utility;
namespace solidware.financials.windows.ui.presenters
{
- public class AddNewStockSymbolPresenter : DialogPresenter, INotification<AddNewStockSymbolPresenter>
+ public class AddNewStockSymbolPresenter : DialogPresenter
{
public AddNewStockSymbolPresenter(UICommandBuilder builder)
{
this.builder = builder;
- Notification = new Notification<AddNewStockSymbolPresenter>();
+ Symbol = new ObservableProperty<string>();
}
public ObservableCommand Add { get; set; }
public ObservableCommand Cancel { get; set; }
- public virtual string Symbol { get; set; }
+ public virtual Observable<string> Symbol { get; set; }
public virtual Action close { get; set; }
- public Notification<AddNewStockSymbolPresenter> Notification { get; set; }
public void present()
{
- Add = builder.build<AddCommand>(this);
+ Add = builder.build<AddCommand, IsValid>(this);
Cancel = builder.build<CancelCommand>(this);
- Notification.Register<Error>(x => x.Symbol, () => Symbol.is_blank(), () => "Please specify a symbol.");
- }
-
- public string this[string property]
- {
- get { return Notification[property]; }
- }
-
- public string this[Expression<Func<AddNewStockSymbolPresenter, object>> property]
- {
- get { return Notification[property]; }
- }
-
- public string Error
- {
- get { return Notification.Error; }
+ Symbol.Notify(Add);
+ Symbol.Register<Error>(x => x.is_blank(), () => "Please specify a symbol.");
}
UICommandBuilder builder;
@@ -57,9 +43,17 @@ namespace solidware.financials.windows.ui.presenters
public override void run(AddNewStockSymbolPresenter presenter)
{
- bus.publish(new StartWatchingSymbol {Symbol = presenter.Symbol.ToUpperInvariant()});
+ bus.publish(new StartWatchingSymbol {Symbol = presenter.Symbol.Value.ToUpperInvariant()});
presenter.close();
}
}
+
+ public class IsValid : UISpecification<AddNewStockSymbolPresenter>
+ {
+ public override bool is_satisfied_by(AddNewStockSymbolPresenter presenter)
+ {
+ return presenter.Symbol.not(x => x.Value.is_blank());
+ }
+ }
}
}
\ No newline at end of file
product/desktop.ui/views/controls/Observable.cs
@@ -3,14 +3,23 @@ using System.ComponentModel;
namespace solidware.financials.windows.ui.views.controls
{
- public interface Observable<T> : Observable
+ public interface Observable<T> : Observable, IDataErrorInfo
{
new T Value { get; set; }
void WhenChanged(Action observer);
+ void Register<Severity>(Func<T, bool> failCondition, Func<string> errorMessage) where Severity : presenters.validation.Severity, new();
}
public interface Observable : INotifyPropertyChanged
{
object Value { get; }
}
+
+ static public class ObservableExtensions
+ {
+ static public void Notify<T>(this Observable<T> observable, ObservableCommand command)
+ {
+ observable.WhenChanged(() => command.notify_observers());
+ }
+ }
}
\ No newline at end of file
product/desktop.ui/views/controls/ObservableProperty.cs
@@ -1,9 +1,10 @@
using System;
using System.ComponentModel;
+using solidware.financials.windows.ui.presenters.validation;
namespace solidware.financials.windows.ui.views.controls
{
- public class ObservableProperty<T> : Observable<T>
+ public class ObservableProperty<T> : Observable<T>, IDataErrorInfo
{
T value;
@@ -12,8 +13,11 @@ namespace solidware.financials.windows.ui.views.controls
public ObservableProperty(T value)
{
this.value = value;
+ Notification = new Notification<Observable<T>>();
}
+ public Notification<Observable<T>> Notification { get; private set; }
+
public T Value
{
get { return value; }
@@ -29,6 +33,11 @@ namespace solidware.financials.windows.ui.views.controls
PropertyChanged += (o, e) => observer();
}
+ public void Register<TSeverity>(Func<T, bool> failCondition, Func<string> errorMessage) where TSeverity : Severity, new()
+ {
+ Notification.Register<TSeverity>(x => x.Value, () => failCondition(Value), errorMessage);
+ }
+
object Observable.Value
{
get { return value; }
@@ -45,5 +54,15 @@ namespace solidware.financials.windows.ui.views.controls
{
return value.ToString();
}
+
+ public string this[string property]
+ {
+ get { return Notification[property]; }
+ }
+
+ public string Error
+ {
+ get { throw new NotImplementedException(); }
+ }
}
}
\ No newline at end of file
product/desktop.ui/views/dialogs/AddNewStockSymbolDialog.xaml
@@ -13,7 +13,7 @@
</StackPanel.Resources>
<DockPanel>
<Label Width="120px">Symbol:</Label>
- <TextBox Text="{Binding Path=Symbol, UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" Style="{StaticResource Error}"></TextBox>
+ <TextBox Text="{Binding Path=Symbol.Value, UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}" Style="{StaticResource Error}"></TextBox>
</DockPanel>
<DockPanel LastChildFill="False" HorizontalAlignment="Right">
<Button IsDefault="True" Command="{Binding Path=Add}">_Add</Button>
product/desktop.ui/UISpecification.cs
@@ -7,8 +7,7 @@ namespace solidware.financials.windows.ui
bool is_satisfied_by<T>(T presenter) where T : Presenter;
}
- public abstract class UISpecification<TPresenter> : UISpecification, Specification<TPresenter>
- where TPresenter : Presenter
+ public abstract class UISpecification<TPresenter> : UISpecification, Specification<TPresenter> where TPresenter : Presenter
{
bool UISpecification.is_satisfied_by<T>(T presenter)
{
product/specs/unit/ui/presenters/AddNewStockSymbolPresenterSpecs.cs
@@ -27,7 +27,7 @@ namespace specs.unit.ui.presenters
{
add_command = Create.an<ObservableCommand>();
cancel_command = Create.an<ObservableCommand>();
- builder.is_told_to(x => x.build<AddNewStockSymbolPresenter.AddCommand>(sut)).it_will_return(add_command);
+ builder.is_told_to(x => x.build<AddNewStockSymbolPresenter.AddCommand, AddNewStockSymbolPresenter.IsValid>(sut)).it_will_return(add_command);
builder.is_told_to(x => x.build<CancelCommand>(sut)).it_will_return(cancel_command);
};
@@ -55,7 +55,7 @@ namespace specs.unit.ui.presenters
Because of = () =>
{
sut.present();
- result = sut[x => x.Symbol];
+ result = sut.Symbol["Value"];
};
It should_display_an_error = () =>
@@ -85,7 +85,7 @@ namespace specs.unit.ui.presenters
Establish context = () =>
{
presenter = Create.an<AddNewStockSymbolPresenter>();
- presenter.is_told_to(x => x.Symbol).it_will_return("TD.TO");
+ presenter.is_told_to(x => x.Symbol).it_will_return("TD.TO".ToObservable());
presenter.Stub(x => x.close).Return(() =>
{
closed = true;
@@ -111,5 +111,62 @@ namespace specs.unit.ui.presenters
static bool closed;
}
}
+
+ public class IsValidSpecs
+ {
+ public class concern
+ {
+ Establish context = () =>
+ {
+ sut = new AddNewStockSymbolPresenter.IsValid();
+ };
+
+ static protected AddNewStockSymbolPresenter.IsValid sut;
+ }
+
+ public class when_a_valid_symbol_is_entered : concern
+ {
+ Establish context = () =>
+ {
+ presenter = Create.an<AddNewStockSymbolPresenter>();
+ presenter.is_told_to(x => x.Symbol).it_will_return("ARX.TO".ToObservable());
+ };
+
+ Because of = () =>
+ {
+ result = sut.is_satisfied_by(presenter);
+ };
+
+ It should_be_valid = () =>
+ {
+ result.should_be_true();
+ };
+
+ static bool result;
+ static AddNewStockSymbolPresenter presenter;
+ }
+
+ public class when_a_invalid_symbol_is_entered : concern
+ {
+ Establish context = () =>
+ {
+ presenter = Create.an<AddNewStockSymbolPresenter>();
+ presenter.is_told_to(x => x.Symbol).it_will_return("".ToObservable());
+ };
+
+ Because of = () =>
+ {
+ result = sut.is_satisfied_by(presenter);
+ };
+
+ It should_be_invalid = () =>
+ {
+ result.should_be_false();
+ };
+
+ static bool result;
+ static AddNewStockSymbolPresenter presenter;
+ }
+ }
}
}
\ No newline at end of file
product/utility/BooleanLogic.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace utility
+{
+ static public class BooleanLogic
+ {
+ static public bool not<T>(this T item, Func<T, bool> condition)
+ {
+ return !condition(item);
+ }
+ }
+}
\ No newline at end of file
product/utility/utility.csproj
@@ -43,6 +43,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BooleanLogic.cs" />
<Compile Include="MapKey.cs" />
<Compile Include="MapperRegistery.cs" />
<Compile Include="Mathematics.cs" />