Skip to content

Commit

Permalink
Added support for richer Added/Removed events on collections and cont…
Browse files Browse the repository at this point in the history
…ainers. #50
  • Loading branch information
kzu committed Oct 24, 2013
1 parent 22e04c6 commit 19e8339
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 9 deletions.
117 changes: 117 additions & 0 deletions Core.UnitTests/ComponentModelFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ public void when_creating_element_then_references_parent_product()
Assert.Same(child.Parent, product);
}

[Fact]
public void when_creating_element_then_raises_component_added()
{
var product = new Product("Foo", "IFoo");
var added = default(IComponent);

product.ComponentAdded += (sender, args) => added = args.Value;

var child = product.CreateElement("Storage", "IStorage");

Assert.NotNull(added);
Assert.Same(added, child);
}

[Fact]
public void when_element_new_name_is_duplicated_with_other_element_then_throws()
{
Expand All @@ -40,6 +54,44 @@ public void when_element_new_name_is_duplicated_with_container_property_then_thr
Assert.Throws<ArgumentException>(() => child.Name = "Element");
}

[Fact]
public void when_element_name_changed_then_raises_property_changing()
{
var product = new Product("Foo", "IFoo");
var changed = false;

product.PropertyChanging += (sender, args) =>
{
changed = true;
Assert.Equal("Name", args.PropertyName);
Assert.Equal("Foo", args.OldValue);
Assert.Equal("Bar", args.NewValue);
};

product.Name = "Bar";

Assert.True(changed);
}

[Fact]
public void when_element_name_changed_then_raises_property_changed()
{
var product = new Product("Foo", "IFoo");
var changed = false;

product.PropertyChanged += (sender, args) =>
{
changed = true;
Assert.Equal("Name", args.PropertyName);
Assert.Equal("Foo", args.OldValue);
Assert.Equal("Bar", args.NewValue);
};

product.Name = "Bar";

Assert.True(changed);
}

[Fact]
public void when_creating_collection_then_references_parent_product()
{
Expand Down Expand Up @@ -133,6 +185,21 @@ public void when_deleting_element_then_removes_from_parent_components()
Assert.Equal(0, product.Components.Count());
}

[Fact]
public void when_deleting_element_then_raises_component_removed()
{
var product = new Product("Foo", "IFoo");
var removed = default(IComponent);
var child = product.CreateElement("Storage", "IStorage");

product.ComponentRemoved += (sender, args) => removed = args.Value;

child.Delete();

Assert.NotNull(removed);
Assert.Same(removed, child);
}

[Fact]
public void when_deleting_collection_item_then_removes_from_parent_collection()
{
Expand All @@ -145,6 +212,22 @@ public void when_deleting_collection_item_then_removes_from_parent_collection()
Assert.Equal(0, collection.Items.Count());
}

[Fact]
public void when_deleting_collection_item_then_raises_item_deleted()
{
var product = new Product("Foo", "IFoo");
var collection = product.CreateCollection("Collection", "ICollection");
var child = collection.CreateItem("Item", "IItem");

var deleted = default(IElement);
collection.ItemRemoved += (sender, args) => deleted = args.Value;

child.Delete();

Assert.NotNull(deleted);
Assert.Same(child, deleted);
}

[Fact]
public void when_deleting_element_then_disposes_it()
{
Expand Down Expand Up @@ -293,6 +376,22 @@ public void when_creating_collection_item_then_can_access_it()
Assert.Same(item, collection.Items.First());
}

[Fact]
public void when_creating_collection_item_then_raises_item_added()
{
var product = new Product("Product", "IProduct");
var collection = product.CreateCollection("Collection", "ICollection");

var item = default(IElement);

collection.ItemAdded += (sender, args) => item = args.Value;

var created = collection.CreateItem("Item", "IItem");

Assert.NotNull(item);
Assert.Same(created, item);
}

[Fact]
public void when_creating_collection_item_then_can_access_product()
{
Expand Down Expand Up @@ -347,6 +446,24 @@ public void when_property_changes_then_notifies_component()
Assert.Equal("bar", changed.NewValue);
}

[Fact]
public void when_property_changing_then_notifies_component()
{
var product = new Product("Product", "IProduct");
product.CreateProperty("key").SetValue("foo");

var changing = default(PropertyChangeEventArgs);

product.PropertyChanging += (sender, args) => changing = args;

product.Set("key", "bar");

Assert.NotNull(changing);
Assert.Equal("key", changing.PropertyName);
Assert.Equal("foo", changing.OldValue);
Assert.Equal("bar", changing.NewValue);
}

[Fact]
public void when_property_set_to_same_existing_value_then_does_not_raise_propertychanged()
{
Expand Down
11 changes: 10 additions & 1 deletion Core/Collection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ internal class Collection : Container, ICollection
{
private List<Element> items = new List<Element>();

public event ValueEventHandler<IElement> ItemAdded = (sender, args) => { };
public event ValueEventHandler<IElement> ItemRemoved = (sender, args) => { };

public Collection(string name, string schemaId, Component parent)
: base(name, schemaId, parent)
{
Expand Down Expand Up @@ -46,6 +49,9 @@ public Element CreateItem(string name, string schemaId)
element.PropertyChanged += OnItemChanged;
element.Disposed += OnItemDisposed;
items.Add(element);

ItemAdded(this, element);

return element;
}

Expand Down Expand Up @@ -78,7 +84,10 @@ internal void DeleteItem(Component component)
// After the delete, the component is disposed, which will
// call our OnComponentDisposed, at which point we unsubscribe
// the property changed event.
items.Remove((Element)component);
var element = (Element)component;

items.Remove(element);
ItemRemoved(this, element);
}

private void OnItemChanged(object sender, EventArgs args)
Expand Down
14 changes: 11 additions & 3 deletions Core/Component.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ internal abstract class Component : IComponent, IDisposable, ILineInfo

public event EventHandler<PropertyChangeEventArgs> PropertyChanged = (sender, args) => { };

public event EventHandler<PropertyChangeEventArgs> PropertyChanging = (sender, args) => { };

public Component(string name, string schemaId, Component parent)
{
this.Name = name;
Expand All @@ -43,8 +45,11 @@ public string Name
{
if (value != name)
{
OnRenaming(name, value);
var oldValue = name;
OnRenaming(oldValue, value);
RaisePropertyChanging("Name", oldValue, value);
name = value;
RaisePropertyChanged("Name", oldValue, value);
}
}
}
Expand Down Expand Up @@ -208,15 +213,18 @@ protected virtual void OnRenaming(string oldName, string newName)
var container = Parent as Container;
if (container != null)
container.ThrowIfDuplicateRename(oldName, newName);

RaisePropertyChanged("Name", oldName, newName);
}

internal void DeleteProperty(Property property)
{
properties.Remove(property.Name);
}

internal void RaisePropertyChanging(string propertyName, object oldValue, object newValue)
{
PropertyChanging(this, new PropertyChangeEventArgs(propertyName, oldValue, newValue));
}

internal void RaisePropertyChanged(string propertyName, object oldValue, object newValue)
{
PropertyChanged(this, new PropertyChangeEventArgs(propertyName, oldValue, newValue));
Expand Down
8 changes: 8 additions & 0 deletions Core/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ internal abstract class Container : Component, IContainer
{
private List<Component> components = new List<Component>();

public event ValueEventHandler<IComponent> ComponentAdded = (sender, args) => { };
public event ValueEventHandler<IComponent> ComponentRemoved = (sender, args) => { };

public Container(string name, string schemaId, Component parent)
: base(name, schemaId, parent)
{
Expand Down Expand Up @@ -43,6 +46,8 @@ public Collection CreateCollection(string name, string schemaId)
collection.PropertyChanged += OnComponentChanged;
collection.Disposed += OnComponentDisposed;
components.Add(collection);
ComponentAdded(this, collection);

return collection;
}

Expand All @@ -63,6 +68,8 @@ public Element CreateElement(string name, string schemaId)
element.PropertyChanged += OnComponentChanged;
element.Disposed += OnComponentDisposed;
components.Add(element);
ComponentAdded(this, element);

return element;
}

Expand All @@ -72,6 +79,7 @@ internal void DeleteComponent(Component component)
// call our OnComponentDisposed, at which point we unsubscribe
// the property changed event.
components.Remove(component);
ComponentRemoved(this, component);
}

protected override void Dispose(bool disposing)
Expand Down
1 change: 1 addition & 0 deletions Core/ValueHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static void Set(Property property, object value)
// TODO: do nothing if property name starts with "$" or "_"?
if (!Object.Equals(oldValue, value))
{
property.Owner.RaisePropertyChanging(property.Name, oldValue, value);
property.SetValue(value);
property.Owner.RaisePropertyChanged(property.Name, oldValue, value);
}
Expand Down
3 changes: 3 additions & 0 deletions Source/ICollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

public interface ICollection : IContainer
{
event ValueEventHandler<IElement> ItemAdded;
event ValueEventHandler<IElement> ItemRemoved;

IEnumerable<IElement> Items { get; }
new ICollectionInfo Schema { get; }

Expand Down
1 change: 1 addition & 0 deletions Source/IComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public interface IComponent : IInstance, IVisitableInstance, IAnnotated
{
event EventHandler<PropertyChangeEventArgs> PropertyChanged;
event EventHandler<PropertyChangeEventArgs> PropertyChanging;

IComponentContext Context { get; }

Expand Down
3 changes: 3 additions & 0 deletions Source/IContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

public interface IContainer : IComponent
{
event ValueEventHandler<IComponent> ComponentAdded;
event ValueEventHandler<IComponent> ComponentRemoved;

IEnumerable<IComponent> Components { get; }

ICollection CreateCollection(string name, string schemaId);
Expand Down
9 changes: 4 additions & 5 deletions Source/IProductStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ public interface IProductStore
{
string Name { get; }

// event Closed;
// event Disposed; == Closed
// Close();

IEnumerable<IProduct> Products { get; }

IProduct CreateProduct(string name, string toolkitId, string schemaId);

void Load(IProgress<int> progress);
void Save(IProgress<int> progress);

///// <summary>
///// Resolves a component at the store scope level.
///// </summary>
//T Resolve<T>();
}
}
42 changes: 42 additions & 0 deletions Source/IWarehouse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NuPattern
{
// ISolutionViewModel
// event ElementActivated;
// event CollectionChanged (index, added/removed, etc.)

public interface IWarehouse
{
// event ElementCreated; -> Traverse(tree) -> nodo.Remove();
// event ElementDeleted;
// event ElementDeleting;
// event ElementInstantiated;
// event ElementLoaded;
// event ElementPropertyChanged;
// Collection.Items prop?
// Container.Elements ?
// event CollectionChanged ?

// ctor(IElement) => propertychanged (port) -> IIS configure
// IElement.PropertyChanged.
// IWebService
// PropertyChanged("Storage")
// Changed("Items") -> Changed("Buckets")
// IStorage Storage
// PropertyChanged("Name")
// Name { get; set; }
// IBuckets Buckets -> Changed("Items")
// IBucket[0].Port -> Changed("Port")

// Open(storeFile);
// SaveAll();
// CloseAll();


IEnumerable<IProductStore> Stores { get; }
}
}
2 changes: 2 additions & 0 deletions Source/NuPattern.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<Compile Include="IComponentContextBuilder.cs" />
<Compile Include="IComponentContextExtensions.cs" />
<Compile Include="IValueProvider.cs" />
<Compile Include="IWarehouse.cs" />
<Compile Include="netfx\System\Reflection\Reflect.cs" />
<Compile Include="netfx\System\Reflection\Reflect.Overloads.cs">
<AutoGen>True</AutoGen>
Expand Down Expand Up @@ -134,6 +135,7 @@
<Compile Include="Configuration\ToolkitBuilder.cs" />
<Compile Include="SemanticVersion.cs" />
<Compile Include="SemanticVersionTypeConverter.cs" />
<Compile Include="ValueEvent.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\Solution Items\NuPattern.snk">
Expand Down
Loading

0 comments on commit 19e8339

Please sign in to comment.