using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using Catel.Articles.Base.Data;
using Catel.Articles.Base.Data.Attributes;
using Catel.Articles.Base.Properties;
using Catel.Data;
using Catel.MVVM;
using Catel.MVVM.Services;
using log4net;
namespace Catel.Articles.Base.UI.ViewModels
{
/// <summary>
/// Examples view model.
/// </summary>
public class ExamplesViewModel : ViewModelBase
{
#region Variables
private readonly string _title;
#endregion
#region Constructor & destructor
/// <summary>
/// Initializes a new instance of the <see cref="ExamplesViewModel"/> class.
/// </summary>
/// <param name="title">The title.</param>
public ExamplesViewModel(string title)
{
// Store values
_title = title;
}
#endregion
#region Properties
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return _title; } }
#region View model
/// <summary>
/// Gets or sets the description.
/// </summary>
public string Description
{
get { return GetValue<string>(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}
/// <summary>
/// Register the Description property so it is known in the class.
/// </summary>
public static readonly PropertyData DescriptionProperty = RegisterProperty("Description", typeof(string), Resources.ExamplesDescription);
/// <summary>
/// Gets or sets a collection of themes.
/// </summary>
public Collection<ThemeInfo> ThemeCollection
{
get { return GetValue<Collection<ThemeInfo>>(ThemeCollectionProperty); }
set { SetValue(ThemeCollectionProperty, value); }
}
/// <summary>
/// Register the ThemeCollection property so it is known in the class.
/// </summary>
public static readonly PropertyData ThemeCollectionProperty = RegisterProperty("ThemeCollection", typeof(Collection<ThemeInfo>));
/// <summary>
/// Gets or sets the selected theme.
/// </summary>
public ThemeInfo SelectedTheme
{
get { return GetValue<ThemeInfo>(SelectedThemeProperty); }
set { SetValue(SelectedThemeProperty, value); }
}
/// <summary>
/// Register the SelectedTheme property so it is known in the class.
/// </summary>
public static readonly PropertyData SelectedThemeProperty = RegisterProperty("SelectedTheme", typeof(ThemeInfo),
(sender, e) => ((ExamplesViewModel)sender).OnSelectedThemeChanged());
/// <summary>
/// Gets or sets the examples collection.
/// </summary>
public ObservableCollection<ExampleInfo> Examples
{
get { return GetValue<ObservableCollection<ExampleInfo>>(ExamplesProperty); }
set { SetValue(ExamplesProperty, value); }
}
/// <summary>
/// Register the Examples property so it is known in the class.
/// </summary>
public static readonly PropertyData ExamplesProperty = RegisterProperty("Examples", typeof(ObservableCollection<ExampleInfo>), new ObservableCollection<ExampleInfo>());
/// <summary>
/// Gets or sets the selected example.
/// </summary>
public ExampleInfo SelectedExample
{
get { return GetValue<ExampleInfo>(SelectedExampleProperty); }
set { SetValue(SelectedExampleProperty, value); }
}
/// <summary>
/// Register the SelectedExample property so it is known in the class.
/// </summary>
public static readonly PropertyData SelectedExampleProperty = RegisterProperty("SelectedExample", typeof(ExampleInfo));
#endregion
#endregion
#region Methods
/// <summary>
/// Initializes the object by setting default values.
/// </summary>
protected override void Initialize()
{
// Log
Log.Info("Welcome to the examples app");
Log.StartStopwatchTrace("Searching for all examples in the current AppDomain");
// Get all the types of the app domain
foreach (Assembly assembly in AssemblyHelper.GetLoadedAssemblies())
{
try
{
foreach (Type type in assembly.GetTypes())
{
// Is the type decorated with the example attribute?
if (type.IsClass)
{
ExampleAttribute[] exampleAttributes = (ExampleAttribute[])type.GetCustomAttributes(typeof(ExampleAttribute), false);
if (exampleAttributes.Length > 0)
{
// Create example info
ExampleInfo exampleInfo = new ExampleInfo(exampleAttributes[0]);
// Does the attribute have a click handler?
if (!string.IsNullOrEmpty(exampleAttributes[0].ClickHandlerName))
{
// Try to find the handler
MethodInfo methodInfo = type.GetMethod(exampleAttributes[0].ClickHandlerName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (methodInfo != null)
{
// Store it
exampleInfo.ClickHandler = Delegate.CreateDelegate(typeof(VoidDelegate), methodInfo) as VoidDelegate;
}
}
// Add
if (!Examples.Contains(exampleInfo)) Examples.Add(exampleInfo);
}
}
}
}
catch (Exception ex)
{
// Log and continue
Log.Error(ex, "Failed to get types of an assembly");
}
}
// Log
Log.StopStopwatchTrace("Searching for all examples in the current AppDomain");
Log.Info("Found '{0}' example(s)", Examples.Count);
// Set initial example
if (Examples.Count > 0) SelectedExample = Examples[0];
// Initialize themes
ThemeCollection = new Collection<ThemeInfo>();
ThemeCollection.Add(new ThemeInfo("Aero - normal", "/Catel.Windows;component/themes/aero/catel.aero.normal.xaml"));
ThemeCollection.Add(new ThemeInfo("Aero - large", "/Catel.Windows;component/themes/aero/catel.aero.large.xaml"));
ThemeCollection.Add(new ThemeInfo("Expression Dark - normal", "/Catel.Windows;component/themes/expressiondark/catel.expressiondark.normal.xaml"));
ThemeCollection.Add(new ThemeInfo("Expression Dark - large", "/Catel.Windows;component/themes/expressiondark/catel.expressiondark.large.xaml"));
ThemeCollection.Add(new ThemeInfo("Jetpack", "/Catel.Windows;component/themes/jetpack/generic.xaml"));
ThemeCollection.Add(new ThemeInfo("Sunny Orange", "/Catel.Windows;component/themes/sunnyorange/generic.xaml"));
// Set selected (default) theme
SelectedTheme = ThemeCollection[0];
}
/// <summary>
/// Called when the <see cref="SelectedTheme"/> property has changed.
/// </summary>
private void OnSelectedThemeChanged()
{
// Clear app resources
var currentApp = Application.Current;
if (currentApp == null)
{
// Show error
var messageService = GetService<IMessageService>();
messageService.ShowError("There is no current application object, cannot switch theme");
// Exit
return;
}
// Need to call this twice because the first update fixes the dictionaries, and the second one actually updates the UI
UpdateApplicationResources(currentApp);
UpdateApplicationResources(currentApp);
}
/// <summary>
/// Updates the application resources.
/// </summary>
/// <param name="currentApp">The current application.</param>
private void UpdateApplicationResources(Application currentApp)
{
// Clear resources
currentApp.Resources.Clear();
currentApp.Resources.MergedDictionaries.Clear();
// Merge resources
ResourceDictionary resourceDictionary = new ResourceDictionary();
resourceDictionary.Source = new Uri(SelectedTheme.Source, UriKind.RelativeOrAbsolute);
// Now merge the dictionaries
currentApp.Resources.MergedDictionaries.Add(resourceDictionary);
// Create style forwarders
Catel.Windows.StyleHelper.CreateStyleForwardersForDefaultStyles();
}
#endregion
}
}