Skip to content

Commit

Permalink
Changed resource markup extension to attached behaviors. Fixes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
danielmoore committed Mar 30, 2014
1 parent afe486c commit b319fe4
Show file tree
Hide file tree
Showing 39 changed files with 2,659 additions and 134 deletions.
16 changes: 16 additions & 0 deletions Igniter.Tests.Live/DirectoryResourcesBehaviorTestWindow.xaml
@@ -0,0 +1,16 @@
<Window x:Class="Igniter.Tests.Live.DirectoryResourcesBehaviorTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ign="http://schemas.northhorizon.net/igniter"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="DirectoryResourcesBehaviorTestWindow" Height="300" Width="300">
<i:Interaction.Behaviors>
<ign:DirectoryResourcesBehavior Directory="DirectoryResourcesBehaviorTestFolder" IsSubdirectoriesIncluded="False"/>
</i:Interaction.Behaviors>
<UniformGrid Columns="1">
<Border Background="{StaticResource Color1}"/>
<Border Background="{StaticResource Color2}"/>
<Border Background="{DynamicResource Color1}"/>
<Border Background="{DynamicResource Color2}"/>
</UniformGrid>
</Window>
Expand Up @@ -3,12 +3,12 @@
namespace Igniter.Tests.Live
{
/// <summary>
/// Interaction logic for FolderResourceDictionaryTestWindow.xaml
/// Interaction logic for DirectoryResourcesBehaviorTestWindow.xaml
/// </summary>
[LiveTest("Folder Resource Dictionary")]
public partial class FolderResourceDictionaryTestWindow : Window
public partial class DirectoryResourcesBehaviorTestWindow : Window
{
public FolderResourceDictionaryTestWindow()
public DirectoryResourcesBehaviorTestWindow()
{
InitializeComponent();
}
Expand Down
13 changes: 0 additions & 13 deletions Igniter.Tests.Live/FolderResourceDictionaryTestWindow.xaml

This file was deleted.

29 changes: 19 additions & 10 deletions Igniter.Tests.Live/Igniter.Tests.Live.csproj
Expand Up @@ -15,6 +15,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<ExpressionBlendVersion>12.0.41212.0</ExpressionBlendVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
Expand Down Expand Up @@ -64,6 +65,9 @@
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.6\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Interactivity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Expression.Blend.Sdk.1.0.2\lib\net40-client\System.Windows.Interactivity.dll</HintPath>
</Reference>
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
Expand All @@ -83,11 +87,11 @@
<Compile Include="CommandParameterTestWindow.xaml.cs">
<DependentUpon>CommandParameterTestWindow.xaml</DependentUpon>
</Compile>
<Compile Include="FolderResourceDictionaryTestWindow.xaml.cs">
<DependentUpon>FolderResourceDictionaryTestWindow.xaml</DependentUpon>
<Compile Include="DirectoryResourcesBehaviorTestWindow.xaml.cs">
<DependentUpon>DirectoryResourcesBehaviorTestWindow.xaml</DependentUpon>
</Compile>
<Compile Include="SharedResourceDictionaryTestWindow.xaml.cs">
<DependentUpon>SharedResourceDictionaryTestWindow.xaml</DependentUpon>
<Compile Include="SharedResourceBehaviorTestWindow.xaml.cs">
<DependentUpon>SharedResourceBehaviorTestWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ViewElementTests\TestView1.xaml.cs">
<DependentUpon>TestView1.xaml</DependentUpon>
Expand All @@ -108,19 +112,19 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="FolderResourceDictionaryTestFolder\Subfolder\Test3.xaml">
<Page Include="DirectoryResourcesBehaviorTestFolder\Subfolder\Test3.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="FolderResourceDictionaryTestFolder\Test1.xaml">
<Page Include="DirectoryResourcesBehaviorTestFolder\Test1.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="FolderResourceDictionaryTestFolder\Test2.xaml">
<Page Include="DirectoryResourcesBehaviorTestFolder\Test2.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="FolderResourceDictionaryTestWindow.xaml">
<Page Include="DirectoryResourcesBehaviorTestWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
Expand All @@ -143,7 +147,12 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="SharedResourceDictionaryTestWindow.xaml">
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>
<Page Include="SharedResourceBehaviorTestWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
Expand Down Expand Up @@ -196,7 +205,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="FolderResourceDictionaryTestFolder\Dialup.png" />
<Resource Include="DirectoryResourcesBehaviorTestFolder\Dialup.png" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Expand Down
7 changes: 7 additions & 0 deletions Igniter.Tests.Live/MainViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;

namespace Igniter.Tests.Live
Expand All @@ -19,6 +20,12 @@ public MainViewModel()
{
TestName = ((LiveTestAttribute)Attribute.GetCustomAttribute(t, typeof(LiveTestAttribute))).Name,
RunCommand = new DelegateCommand(() => ((Window)Activator.CreateInstance(t)).Show())
})
.Concat(new[] {
new {
TestName = "Garbage Collect",
RunCommand = new DelegateCommand(GC.Collect)
}
});
}

Expand Down
8 changes: 8 additions & 0 deletions Igniter.Tests.Live/Properties/DesignTimeResources.xaml
@@ -0,0 +1,8 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Igniter.Tests.Live;component/TestSharedResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>
23 changes: 23 additions & 0 deletions Igniter.Tests.Live/SharedResourceBehaviorTestWindow.xaml
@@ -0,0 +1,23 @@
<Window x:Class="Igniter.Tests.Live.SharedResourceBehaviorTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ign="http://schemas.northhorizon.net/igniter"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="SharedResourceBehaviorTestWindow" Height="300" Width="300">
<UniformGrid Columns="1">
<UniformGrid Columns="1">
<i:Interaction.Behaviors>
<ign:SharedResourceBehavior Source="testsharedresources.xaml"/>
</i:Interaction.Behaviors>
<Border Background="{StaticResource Brush1}"/>
<Border Background="{DynamicResource Brush1}"/>
</UniformGrid>
<UniformGrid Columns="1">
<i:Interaction.Behaviors>
<ign:SharedResourceBehavior Source="TESTSHAREDRESOURCES.XAML"/>
</i:Interaction.Behaviors>
<Border Background="{StaticResource Brush2}"/>
<Border Background="{DynamicResource Brush2}"/>
</UniformGrid>
</UniformGrid>
</Window>
Expand Up @@ -3,9 +3,9 @@
namespace Igniter.Tests.Live
{
[LiveTest("Shared Resource Dictionary")]
public partial class SharedResourceDictionaryTestWindow : Window
public partial class SharedResourceBehaviorTestWindow : Window
{
public SharedResourceDictionaryTestWindow()
public SharedResourceBehaviorTestWindow()
{
InitializeComponent();
}
Expand Down
20 changes: 0 additions & 20 deletions Igniter.Tests.Live/SharedResourceDictionaryTestWindow.xaml

This file was deleted.

1 change: 1 addition & 0 deletions Igniter.Tests.Live/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Expression.Blend.Sdk" version="1.0.2" targetFramework="net40-Client" />
<package id="Microsoft.Bcl" version="1.1.6" targetFramework="net40-Client" />
<package id="Microsoft.Bcl.Build" version="1.0.13" targetFramework="net40-Client" />
<package id="Rx-Core" version="2.2.2" targetFramework="net40-Client" />
Expand Down
Expand Up @@ -10,20 +10,22 @@
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;
using Igniter.Core;

namespace Igniter.Markup
namespace Igniter.Behaviors
{
/// <summary>
/// Provides a <see cref="ResourceDictionary" /> that has merged in resource dictionaries contained in a given folder.
/// </summary>
public sealed class DirectoryResourceDictionaryExtension : MarkupExtension
public sealed class DirectoryResourcesBehavior : ResourceBehvior
{
/// <summary>
/// Initializes a new instance of the <see cref="DirectoryResourceDictionaryExtension"/> class.
/// Initializes a new instance of the <see cref="DirectoryResourcesBehavior"/> class.
/// </summary>
public DirectoryResourceDictionaryExtension()
public DirectoryResourcesBehavior()
{
IsSubdirectoriesIncluded = true;
IsShared = true;
}

/// <summary>
Expand All @@ -43,15 +45,16 @@ public DirectoryResourceDictionaryExtension()
public bool IsSubdirectoriesIncluded { get; set; }

/// <summary>
/// When implemented in a derived class, returns an object that is provided as the value of the target property for this markup extension.
/// Gets or sets a value indicating whether to use shared resources.
/// </summary>
/// <param name="serviceProvider">A service provider helper that can provide services for the markup extension.</param>
/// <returns>
/// The object value to set on the property where the extension is applied.
/// </returns>
public override object ProvideValue(IServiceProvider serviceProvider)
/// <value>
/// <c>true</c> if shared resources should be used; otherwise, <c>false</c>.
/// </value>
public bool IsShared { get; set; }

protected override ResourceDictionary ProvideAttachedResources(IUriContext uriContext)
{
var partUri = ResolveDirectoryUri(serviceProvider);
var partUri = ResolveDirectoryUri();

var resourceMgr = GetResourceManager(partUri);

Expand All @@ -69,28 +72,31 @@ public override object ProvideValue(IServiceProvider serviceProvider)

if (resourceUri.StartsWith(partUri.OriginalString, StringComparison.OrdinalIgnoreCase) &&
(IsSubdirectoriesIncluded || resourceUri.IndexOf('/', partUri.OriginalString.Length) < 0))
resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri(Path.ChangeExtension(resourceUri, ".xaml"), UriKind.Relative)
});
{
var uri = new Uri(Path.ChangeExtension(resourceUri, ".xaml"), UriKind.Relative);

var uriResources = IsShared ? ResourceCache.GetOrCreate(uri) : new ResourceDictionary {Source = uri};

resources.MergedDictionaries.Add(uriResources);
}
}
}

return resources;
}

private Uri ResolveDirectoryUri(IServiceProvider serviceProvider)
private Uri ResolveDirectoryUri()
{
if (Directory == null || Directory.OriginalString == ".")
{
var baseUri = serviceProvider.GetService<IUriContext>().BaseUri;
var baseUri = ((IUriContext)this).BaseUri;
var directoryUri = new Uri(baseUri, Path.GetDirectoryName(baseUri.AbsolutePath) + '/');

return PackUriHelper.GetPartUri(directoryUri);
}

var directory = Directory.OriginalString.EndsWith("/") ? Directory : new Uri(Directory.OriginalString + '/', UriKind.RelativeOrAbsolute);
return serviceProvider.GetService<IUriContext>().ResolvePartUri(directory);
return this.ResolvePartUri(directory);
}

private static ResourceManager GetResourceManager(Uri partUri)
Expand Down
32 changes: 32 additions & 0 deletions Igniter/Behaviors/ResourceBehvior.cs
@@ -0,0 +1,32 @@
using System;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Markup;

namespace Igniter.Behaviors
{
public abstract class ResourceBehvior : Behavior<FrameworkElement>, IUriContext
{
private ResourceDictionary _attachedResources;

Uri IUriContext.BaseUri { get; set; }

protected abstract ResourceDictionary ProvideAttachedResources(IUriContext uriContext);

protected override void OnAttached()
{
base.OnAttached();

_attachedResources = ProvideAttachedResources(this);
AssociatedObject.Resources.MergedDictionaries.Add(_attachedResources);
}

protected override void OnDetaching()
{
AssociatedObject.Resources.MergedDictionaries.Remove(_attachedResources);
_attachedResources = null;

base.OnDetaching();
}
}
}
27 changes: 27 additions & 0 deletions Igniter/Behaviors/SharedResourceBehavior.cs
@@ -0,0 +1,27 @@
using System;
using System.Windows;
using System.Windows.Markup;
using Igniter.Core;

namespace Igniter.Behaviors
{
/// <summary>
/// Provides cached resource dictionaries to avoid loading the same resources multiple times.
/// </summary>
public sealed class SharedResourceBehavior : ResourceBehvior
{
/// <summary>
/// Gets or sets the URI of the dictionary to load.
/// </summary>
public Uri Source { get; set; }

protected override ResourceDictionary ProvideAttachedResources(IUriContext uriContext)
{
if (Source == null) return null;

var uri = this.ResolvePartUri(Source);

return ResourceCache.GetOrCreate(uri);
}
}
}

0 comments on commit b319fe4

Please sign in to comment.