Browse Source

Defer style changes when changing classes.

Because we don't know which style to apply until all selectors have
received notification of a class change.
pull/4/head
grokys 12 years ago
parent
commit
52bf8b0b1f
  1. 4
      Perspex.UnitTests/Styling/SubscribeCheck.cs
  2. 172
      Perspex/Classes.cs
  3. 7
      Perspex/Controls/Control.cs
  4. 1
      Perspex/Perspex.csproj
  5. 35
      Perspex/PerspexObject.cs
  6. 41
      Perspex/PriorityValue.cs
  7. 2
      Perspex/Styling/IStyleable.cs

4
Perspex.UnitTests/Styling/SubscribeCheck.cs

@ -27,11 +27,11 @@ namespace Perspex.UnitTests.Styling
{
public SubscribeCheck()
{
this.Classes = new PerspexList<string>();
this.Classes = Classes;
this.SubscribeCheckObservable = new TestObservable();
}
public PerspexList<string> Classes
public Classes Classes
{
get;
private set;

172
Perspex/Classes.cs

@ -0,0 +1,172 @@
// -----------------------------------------------------------------------
// <copyright file="Classes.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive;
using System.Reactive.Subjects;
public class Classes : ICollection<string>, INotifyCollectionChanged
{
private List<string> inner;
private Subject<NotifyCollectionChangedEventArgs> beforeChanged
= new Subject<NotifyCollectionChangedEventArgs>();
private Subject<NotifyCollectionChangedEventArgs> changed
= new Subject<NotifyCollectionChangedEventArgs>();
private Subject<NotifyCollectionChangedEventArgs> afterChanged
= new Subject<NotifyCollectionChangedEventArgs>();
public Classes()
{
this.inner = new List<string>();
}
public Classes(params string[] classes)
{
this.inner = new List<string>(classes);
}
public Classes(IEnumerable<string> classes)
{
this.inner = new List<string>(classes);
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public int Count
{
get { return this.inner.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public IObservable<NotifyCollectionChangedEventArgs> BeforeChanged
{
get { return this.beforeChanged; }
}
public IObservable<NotifyCollectionChangedEventArgs> Changed
{
get { return this.changed; }
}
public IObservable<NotifyCollectionChangedEventArgs> AfterChanged
{
get { return this.afterChanged; }
}
public void Add(string item)
{
this.Add(Enumerable.Repeat(item, 1));
}
public void Add(params string[] items)
{
this.Add((IEnumerable<string>)items);
}
public void Add(IEnumerable<string> items)
{
items = items.Except(this.inner);
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
items);
this.beforeChanged.OnNext(e);
this.inner.AddRange(items);
this.RaiseChanged(e);
}
private void RaiseChanged(NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
{
this.CollectionChanged(this, e);
}
this.changed.OnNext(e);
this.afterChanged.OnNext(e);
}
public void Clear()
{
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset);
this.beforeChanged.OnNext(e);
this.inner.Clear();
this.RaiseChanged(e);
}
public bool Contains(string item)
{
return this.inner.Contains(item);
}
public void CopyTo(string[] array, int arrayIndex)
{
this.inner.CopyTo(array, arrayIndex);
}
public IEnumerator<string> GetEnumerator()
{
return inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return inner.GetEnumerator();
}
public bool Remove(string item)
{
return this.Remove(Enumerable.Repeat(item, 1));
}
public bool Remove(params string[] items)
{
return this.Remove((IEnumerable<string>)items);
}
public bool Remove(IEnumerable<string> items)
{
items = items.Intersect(this.inner);
if (items.Any())
{
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
items);
this.beforeChanged.OnNext(e);
foreach (string item in items)
{
this.inner.Remove(item);
}
this.RaiseChanged(e);
return true;
}
else
{
return false;
}
}
}
}

7
Perspex/Controls/Control.cs

@ -74,7 +74,10 @@ namespace Perspex.Controls
public Control()
{
this.Classes = new PerspexList<string>();
this.Classes = new Classes();
this.Classes.BeforeChanged.Subscribe(x => this.BeginDeferStyleChanges());
this.Classes.AfterChanged.Subscribe(x => this.EndDeferStyleChanges());
this.GetObservableWithHistory(ParentPropertyRW).Subscribe(this.ParentChanged);
this.GetObservable(IsMouseOverProperty).Subscribe(x =>
@ -140,7 +143,7 @@ namespace Perspex.Controls
set { this.SetValue(BorderThicknessProperty, value); }
}
public PerspexList<string> Classes
public Classes Classes
{
get;
private set;

1
Perspex/Perspex.csproj

@ -69,6 +69,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Application.cs" />
<Compile Include="Classes.cs" />
<Compile Include="Controls\Border.cs" />
<Compile Include="Controls\Button.cs" />
<Compile Include="Controls\ContentPresenter.cs" />

35
Perspex/PerspexObject.cs

@ -12,6 +12,7 @@ namespace Perspex
using System.Linq;
using System.Linq.Expressions;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reflection;
using Splat;
@ -94,6 +95,40 @@ namespace Perspex
}
}
/// <summary>
/// Defers property updates due to style changes until <see cref="EndDeferStyleChanges"/>
/// is called.
/// </summary>
public void BeginDeferStyleChanges()
{
foreach (PriorityValue v in this.values.Values)
{
v.BeginDeferStyleChanges();
}
this.Log().Debug(string.Format(
"Defer style changes on {0} (#{1:x8})",
this.GetType().Name,
this.GetHashCode()));
}
/// <summary>
/// Ends the defer of property updates due to style changes initiated by a previous call
/// to <see cref="BeginDeferStyleChanges"/>.
/// </summary>
public void EndDeferStyleChanges()
{
foreach (PriorityValue v in this.values.Values)
{
v.EndDeferStyleChanges();
}
this.Log().Debug(string.Format(
"End defer style changes on {0} (#{1:x8})",
this.GetType().Name,
this.GetHashCode()));
}
/// <summary>
/// Gets all <see cref="PerspexProperty"/>s registered on a type.
/// </summary>

41
Perspex/PriorityValue.cs

@ -25,6 +25,10 @@ namespace Perspex
private List<IObserver<Tuple<object, object>>> observers =
new List<IObserver<Tuple<object, object>>>();
private int defer;
private bool dirty;
public object LocalValue
{
get
@ -113,18 +117,41 @@ namespace Perspex
return Disposable.Create(() => this.observers.Remove(observer));
}
private void Push()
public void BeginDeferStyleChanges()
{
object value = this.GetEffectiveValue();
if (this.defer++ == 0)
{
this.dirty = false;
}
}
if (!object.Equals(this.lastValue, value))
public void EndDeferStyleChanges()
{
if (this.defer > 0 && --this.defer == 0 && dirty)
{
foreach (IObserver<Tuple<object, object>> observer in this.observers)
this.Push();
}
}
private void Push()
{
if (defer == 0)
{
object value = this.GetEffectiveValue();
if (!object.Equals(this.lastValue, value))
{
observer.OnNext(Tuple.Create(this.lastValue, value));
}
foreach (IObserver<Tuple<object, object>> observer in this.observers)
{
observer.OnNext(Tuple.Create(this.lastValue, value));
}
this.lastValue = value;
this.lastValue = value;
}
}
else
{
dirty = true;
}
}

2
Perspex/Styling/IStyleable.cs

@ -17,7 +17,7 @@ namespace Perspex.Styling
/// <summary>
/// Gets the list of classes for the control.
/// </summary>
PerspexList<string> Classes { get; }
Classes Classes { get; }
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to a style.

Loading…
Cancel
Save