Browse Source

Started adding MergedDictionaries.

pull/1136/head
Steven Kirk 9 years ago
parent
commit
ac8cc99f16
  1. 13
      src/Avalonia.Controls/Control.cs
  2. 10
      src/Avalonia.Styling/Controls/IResourceDictionary.cs
  3. 2
      src/Avalonia.Styling/Controls/IResourceProvider.cs
  4. 77
      src/Avalonia.Styling/Controls/ResourceDictionary.cs
  5. 175
      tests/Avalonia.Styling.UnitTests/ResourceDictionaryTests.cs

13
src/Avalonia.Controls/Control.cs

@ -284,7 +284,7 @@ namespace Avalonia.Controls
if (_styles != null)
{
(_styles as ISetStyleParent)?.SetParent(null);
_styles.ResourcesChanged -= StyleResourcesChanged;
_styles.ResourcesChanged -= ThisResourcesChanged;
}
_styles = value;
@ -294,7 +294,7 @@ namespace Avalonia.Controls
setParent.SetParent(this);
}
_styles.ResourcesChanged += StyleResourcesChanged;
_styles.ResourcesChanged += ThisResourcesChanged;
}
}
}
@ -323,7 +323,7 @@ namespace Avalonia.Controls
if (_resources == null)
{
_resources = new ResourceDictionary();
_resources.CollectionChanged += ResourceDictionaryChanged;
_resources.ResourcesChanged += ThisResourcesChanged;
}
return _resources;
@ -914,12 +914,7 @@ namespace Avalonia.Controls
}
}
private void ResourceDictionaryChanged(object sender, NotifyCollectionChangedEventArgs e)
{
((ILogical)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
private void StyleResourcesChanged(object sender, ResourcesChangedEventArgs e)
private void ThisResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
((ILogical)this).NotifyResourcesChanged(e);
}

10
src/Avalonia.Styling/Controls/IResourceDictionary.cs

@ -11,6 +11,16 @@ namespace Avalonia.Controls
/// </summary>
public interface IResourceDictionary : IDictionary<string, object>
{
/// <summary>
/// Raised when resources in the dictionary are changed.
/// </summary>
event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary>
/// Gets a collection of child resource dictionaries.
/// </summary>
IList<IResourceDictionary> MergedDictionaries { get; }
/// <summary>
/// Tries to find a resource within the dictionary.
/// </summary>

2
src/Avalonia.Styling/Controls/IResourceProvider.cs

@ -8,7 +8,7 @@ namespace Avalonia.Controls
public interface IResourceProvider
{
/// <summary>
/// Raised when the resources in the element are changed.
/// Raised when resources in the element are changed.
/// </summary>
event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;

77
src/Avalonia.Styling/Controls/ResourceDictionary.cs

@ -2,7 +2,8 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Collections;
namespace Avalonia.Controls
@ -10,9 +11,79 @@ namespace Avalonia.Controls
/// <summary>
/// An indexed dictionary of resources.
/// </summary>
public class ResourceDictionary : AvaloniaDictionary<string, object>, IResourceDictionary, IDictionary
public class ResourceDictionary : AvaloniaDictionary<string, object>, IResourceDictionary
{
private AvaloniaList<IResourceDictionary> _mergedDictionaries;
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
public ResourceDictionary()
{
CollectionChanged += OnCollectionChanged;
}
public IList<IResourceDictionary> MergedDictionaries
{
get
{
if (_mergedDictionaries == null)
{
_mergedDictionaries = new AvaloniaList<IResourceDictionary>();
_mergedDictionaries.ResetBehavior = ResetBehavior.Remove;
_mergedDictionaries.ForEachItem(
x =>
{
if (x.Count > 0)
{
OnResourcesChanged();
}
x.ResourcesChanged += MergedDictionaryResourcesChanged;
},
x =>
{
if (x.Count > 0)
{
OnResourcesChanged();
}
x.ResourcesChanged -= MergedDictionaryResourcesChanged;
},
() => { });
}
return _mergedDictionaries;
}
}
/// <inheritdoc/>
public bool TryGetResource(string key, out object value) => TryGetValue(key, out value);
public bool TryGetResource(string key, out object value)
{
if (TryGetValue(key, out value))
{
return true;
}
if (_mergedDictionaries != null)
{
for (var i = _mergedDictionaries.Count - 1; i >= 0; --i)
{
if (_mergedDictionaries[i].TryGetResource(key, out value))
{
return true;
}
}
}
return false;
}
private void OnResourcesChanged()
{
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => OnResourcesChanged();
private void MergedDictionaryResourcesChanged(object sender, ResourcesChangedEventArgs e) => OnResourcesChanged();
}
}

175
tests/Avalonia.Styling.UnitTests/ResourceDictionaryTests.cs

@ -0,0 +1,175 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Controls;
using Xunit;
namespace Avalonia.Styling.UnitTests
{
public class ResourceDictionaryTests
{
[Fact]
public void TryGetResource_Should_Find_Resource()
{
var target = new ResourceDictionary
{
{ "foo", "bar" },
};
Assert.True(target.TryGetResource("foo", out var result));
Assert.Equal("bar", result);
}
[Fact]
public void TryGetResource_Should_Find_Resource_From_Merged_Dictionary()
{
var target = new ResourceDictionary
{
MergedDictionaries =
{
new ResourceDictionary
{
{ "foo", "bar" },
}
}
};
Assert.True(target.TryGetResource("foo", out var result));
Assert.Equal("bar", result);
}
[Fact]
public void TryGetResource_Should_Find_Resource_From_Itself_Before_Merged_Dictionary()
{
var target = new ResourceDictionary
{
{ "foo", "bar" },
};
target.MergedDictionaries.Add(new ResourceDictionary
{
{ "foo", "baz" },
});
Assert.True(target.TryGetResource("foo", out var result));
Assert.Equal("bar", result);
}
[Fact]
public void TryGetResource_Should_Find_Resource_From_Later_Merged_Dictionary()
{
var target = new ResourceDictionary
{
MergedDictionaries =
{
new ResourceDictionary
{
{ "foo", "bar" },
},
new ResourceDictionary
{
{ "foo", "baz" },
}
}
};
Assert.True(target.TryGetResource("foo", out var result));
Assert.Equal("baz", result);
}
[Fact]
public void ResourcesChanged_Should_Be_Raised_On_Resource_Add()
{
var target = new ResourceDictionary();
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.Add("foo", "bar");
Assert.True(raised);
}
[Fact]
public void ResourcesChanged_Should_Be_Raised_On_MergedDictionary_Add()
{
var target = new ResourceDictionary();
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.MergedDictionaries.Add(new ResourceDictionary
{
{ "foo", "bar" },
});
Assert.True(raised);
}
[Fact]
public void ResourcesChanged_Should_Not_Be_Raised_On_Empty_MergedDictionary_Add()
{
var target = new ResourceDictionary();
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.MergedDictionaries.Add(new ResourceDictionary());
Assert.False(raised);
}
[Fact]
public void ResourcesChanged_Should_Be_Raised_On_MergedDictionary_Remove()
{
var target = new ResourceDictionary
{
MergedDictionaries =
{
new ResourceDictionary { { "foo", "bar" } },
}
};
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.MergedDictionaries.RemoveAt(0);
Assert.True(raised);
}
[Fact]
public void ResourcesChanged_Should_Not_Be_Raised_On_Empty_MergedDictionary_Remove()
{
var target = new ResourceDictionary
{
MergedDictionaries =
{
new ResourceDictionary(),
}
};
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.MergedDictionaries.RemoveAt(0);
Assert.False(raised);
}
[Fact]
public void ResourcesChanged_Should_Be_Raised_On_MergedDictionary_Resource_Add()
{
var target = new ResourceDictionary
{
MergedDictionaries =
{
new ResourceDictionary(),
}
};
var raised = false;
target.ResourcesChanged += (_, __) => raised = true;
target.MergedDictionaries[0].Add("foo", "bar");
Assert.True(raised);
}
}
}
Loading…
Cancel
Save