Skip to content

Commit

Permalink
Fixes #705
Browse files Browse the repository at this point in the history
  • Loading branch information
batzen committed Sep 17, 2019
1 parent d482e70 commit 088217b
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 2 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
- [#688](../../issues/688) - Backstage and StartScreen closing when pressing Alt
- [#698](../../issues/698) - Submenus in the application menu are not opened each time
- [#704](../../issues/704) - CheckBox.Header - InvalidCastException
- [#705](../../issues/705) - ApplicationMenu header can't be set to text
- [#714](../../issues/714) - ResizeMode="NoResize" and ShowInTaskbar="False" causes crash on startup
- [#722](../../issues/722) - NullReferenceException in KeyTipService.OnAdornerChainTerminated
- [#730](../../issues/730) - Add null check for Application.Current to ThemeManager (thanks @Evangelink)
Expand Down
45 changes: 45 additions & 0 deletions Fluent.Ribbon.Tests/Converters/ObjectToImageConverterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace Fluent.Tests.Converters
{
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using Fluent.Converters;
using NUnit.Framework;

[TestFixture]
public class ObjectToImageConverterTests
{
[Test]
public void TestDynamicResource()
{
var fluentRibbonImagesApplicationmenuResourceKey = (object)"Fluent.Ribbon.Images.ApplicationMenu";

var expressionType = typeof(ResourceReferenceExpressionConverter).Assembly.GetType("System.Windows.ResourceReferenceExpression");

var expression = Activator.CreateInstance(expressionType, fluentRibbonImagesApplicationmenuResourceKey);

var convertedValue = StaticConverters.ObjectToImageConverter.Convert(new object[]
{
expression, // value to convert
new ApplicationMenu() // target visual
}, null, null, null);

Assert.That(convertedValue, Is.Not.Null);
Assert.That(convertedValue, Is.InstanceOf<Image>());

var convertedImageValue = (Image)convertedValue;
Assert.That(convertedImageValue.Source, Is.InstanceOf<DrawingImage>());

var drawingImage = (DrawingImage)convertedImageValue.Source;
Assert.That(drawingImage.Drawing, Is.InstanceOf<DrawingGroup>());

var drawingGroup = (DrawingGroup)drawingImage.Drawing;

Assert.That(drawingGroup.Children.Cast<GeometryDrawing>().Select(x => x.Geometry.ToString()),
Is.EquivalentTo(((DrawingGroup)((DrawingImage)Application.Current.FindResource(fluentRibbonImagesApplicationmenuResourceKey)).Drawing).Children.Cast<GeometryDrawing>().Select(x => x.Geometry.ToString())));
}
}
}
41 changes: 41 additions & 0 deletions Fluent.Ribbon/Converters/ObjectToImageConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
Expand Down Expand Up @@ -360,6 +361,46 @@ public static ImageSource CreateImageSource(object value, Visual targetVisual, S
return ExtractImageSource(icon, targetVisual, desiredSize);
}

// !!! Danger zone ahead !!!
// !!! Please do not copy that code somewhere and blame me for failures !!!
// Hack to get the value from resource expressions
{
if (targetVisual is null == false // to get values for resource expressions we need a DependencyObject
&& value is Expression expression)
{
var type = expression.GetType();
var method = type.GetMethod("GetValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

if (method != null)
{
var valueFromExpression = method.Invoke(expression, new object[]
{
targetVisual,
// to get values from resource expressions we need a DependencyProperty, so just pass a random one
RibbonProperties.SizeProperty
});

return CreateImageSource(valueFromExpression, targetVisual, desiredSize);
}
}

if (value.GetType().InheritsFrom("DeferredReference"))
{
var type = value.GetType();
var method = type.GetMethod("GetValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

if (method != null)
{
var valueFromDeferredReference = method.Invoke(value, new object[]
{
null
});

return CreateImageSource(valueFromDeferredReference, targetVisual, desiredSize);
}
}
}

return null;
}

Expand Down
26 changes: 26 additions & 0 deletions Fluent.Ribbon/Internal/TypeHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace Fluent.Internal
{
using System;

internal static class TypeHelper
{
public static bool InheritsFrom(this Type type, string typeName)
{
var currentType = type;

do
{
if (currentType.Name == typeName)
{
return true;
}

currentType = currentType.BaseType;
}
while (currentType != null
&& currentType != typeof(object));

return false;
}
}
}
4 changes: 2 additions & 2 deletions Fluent.Ribbon/Themes/Controls/ApplicationMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
Height="23"
Background="{TemplateBinding Background}">
<ContentControl x:Name="contentPresenter"
Content="{converters:ObjectToImageConverter {Binding Header, RelativeSource={RelativeSource TemplatedParent}}, '32,16', {Binding RelativeSource={RelativeSource TemplatedParent}}}"
Content="{TemplateBinding Header}"
Margin="10,0,10,0"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
Expand Down Expand Up @@ -129,7 +129,7 @@
<Setter Property="Template" Value="{DynamicResource ApplicationMenuButtonControlTemplate}" />
<Setter Property="Background" Value="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}" />
<Setter Property="Foreground" Value="{DynamicResource Fluent.Ribbon.Brushes.IdealForegroundColorBrush}" />
<Setter Property="Header" Value="{DynamicResource Fluent.Ribbon.Images.ApplicationMenu}" />
<Setter Property="Header" Value="{converters:ObjectToImageConverter {DynamicResource Fluent.Ribbon.Images.ApplicationMenu}, '40,16', {Binding RelativeSource={RelativeSource Self}}}" />
<Setter Property="ItemContainerStyleSelector" Value="{x:Static styleSelectors:ApplicationMenuItemContainerStyleSelector.Instance}" />
</Style>
</ResourceDictionary>

0 comments on commit 088217b

Please sign in to comment.