using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Threading;
using Ganzer;
namespace ValidatorTests.ViewModels
{
//############################################################################
/// <summary>
/// The ViewModelBase class defines a basic view model that supports notification
/// of changed properties.
/// </summary>
///
public abstract class ViewModelBase : INotifyPropertyChanged
{
#region ViewModelBase
#region types
//############################################################################
/// <summary>
/// The DefaultMessageProvider class provides access to message boxes if no
/// other provider is set by <see cref="MessageProvider"/>.
/// </summary>
///
public class DefaultMessageProvider : IViewModelMessageProvider
{
#region IViewModelMessageProvider Member
/// <summary>
/// Displays a modal message box.
/// </summary>
///
/// <param name="text">The message text to show.</param>
/// <param name="caption">The text of the message box' title bar. If this is
/// <c>null</c> <see cref="ApplicationInfo.Title"/> is used.</param>
/// <param name="button">The button to show.</param>
/// <param name="icon">The icon to display.</param>
/// <param name="defResult">The default result.</param>
/// <param name="options">The opitons to set.</param>
///
/// <returns>The result of the message box.</returns>
///
/// <remarks>
/// The window that owns the shown message box ist set to the application's
/// active window.
/// </remarks>
///
public MessageBoxResult ShowMessageBox(
string text,
string caption = null,
MessageBoxButton button = MessageBoxButton.OK,
MessageBoxImage icon = MessageBoxImage.None,
MessageBoxResult defResult = MessageBoxResult.OK,
MessageBoxOptions options = MessageBoxOptions.None )
{
return ShowMessageBox(ViewModelBase.ActiveWindow, text, caption ?? ApplicationInfo.Title, button, icon, defResult, options);
}
/// <summary>
/// Displays a modal message box.
/// </summary>
///
/// <param name="owner">The window that owns the message box.</param>
/// <param name="text">The message text to show.</param>
/// <param name="caption">The text of the message box' name bar.</param>
/// <param name="button">The button to show.</param>
/// <param name="icon">The icon to display.</param>
/// <param name="defResult">The default result.</param>
/// <param name="options">The opitons to set.</param>
///
/// <returns>The result of the message box.</returns>
///
private MessageBoxResult ShowMessageBox(
Window owner,
string text,
string caption,
MessageBoxButton button,
MessageBoxImage icon,
MessageBoxResult defResult,
MessageBoxOptions options )
{
if( owner != null && !owner.CheckAccess() )
{
return (MessageBoxResult)owner.Dispatcher.Invoke(
new Func<Window, string, string, MessageBoxButton, MessageBoxImage, MessageBoxResult, MessageBoxOptions, MessageBoxResult>(ShowMessageBox),
owner, text, caption, button, icon, defResult, options);
}
else
{
if( CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft )
options |= MessageBoxOptions.RtlReading;
if( owner != null )
return MessageBox.Show(owner, text, caption, button, icon, defResult, options);
return MessageBox.Show(text, caption, button, icon, defResult, options);
}
}
#endregion
}
#endregion
#region properties
private string _name;
/// <summary>
/// Gets or sets the name of the view model.
/// </summary>
///
/// <returns>The name of the view model or <c>null</c> if no name is set.
/// </returns>
///
/// <remarks>
/// <para>This property is not especially proposed to provide a unique
/// identifier for a view model. It can be used freely and its meaning
/// is defined by the application.
/// </para>
/// <para>The <see cref="PropertyChanged"/> event is raised when this property has
/// changed. Changing this property does also raise the <see cref="PropertyChanged"/>
/// event for <see cref="Title"/>.</para>
/// </remarks>
///
public virtual string Name
{
get
{
return _name;
}
set
{
if( value == _name )
return;
_name = value;
OnPropertyChanged("Name");
OnPropertyChanged("Title");
}
}
/// <summary>
/// Gets the title of the view model.
/// </summary>
///
/// <returns>This implementation does always return <see cref="Name"/>.
/// </returns>
///
/// <remarks>
/// <para>Implementors should build the title within its view models.
/// This property is implemented to provide views a display text that
/// i.e. contains a file name or modification marks beneath the name
/// of the view model.
/// </para>
/// <para>The <see cref="PropertyChanged">PropertyChanged</see> event
/// is raised when this property has changed.</para>
/// </remarks>
///
public virtual string Title
{
get
{
return _name;
}
}
private static IViewModelMessageProvider _messageProvider;
/// <summary>
/// Gets or sets an object that provides access to message boxes.
/// </summary>
///
/// <returns>The set provider or <c>null</c> if no provider is set.</returns>
///
/// <remarks>
/// If no provider is set, messages are shown by using the default message
/// box of the current OS. The caption of this message box is set to the
/// name of the application's executable file without the extension. The
/// owner window of the message box is set to the currently active window.
/// </remarks>
///
public static IViewModelMessageProvider MessageProvider
{
get
{
return _messageProvider;
}
set
{
_messageProvider = value;
}
}
private static IViewModelMessageProvider _defaultMessageProvider;
/// <summary>
/// Gets a message provider independent of whether a provieder is set.
/// </summary>
///
/// <returns>The message provider that is set by <see cref="MessageProvider"/>
/// of a default provider if <see cref="MessageProvider"/> is not set.</returns>
///
protected static IViewModelMessageProvider MessageProviderResolved
{
get
{
if( _messageProvider != null )
return _messageProvider;
if( _defaultMessageProvider == null )
_defaultMessageProvider = new DefaultMessageProvider();
return _defaultMessageProvider;
}
}
/// <summary>
/// Gets the currently active window.
/// </summary>
///
/// <returns>The currently active window or <c>null</c> if the main window
/// is not created yet.</returns>
///
/// <remarks>
/// This property is valid only if it is called within the thread that has
/// created the application object.
/// </remarks>
///
internal static Window ActiveWindow
{
get
{
foreach( Window window in Application.Current.Windows )
if( window.IsActive )
return window;
return Application.Current.MainWindow;
}
}
#endregion
#region initialization
/// <summary>
/// Creates an empty instance.
/// </summary>
///
protected ViewModelBase()
{
}
/// <summary>
/// Initializes this object with the specified argument.
/// </summary>
///
/// <param name="name">The name to set.</param>
///
protected ViewModelBase( string name )
{
_name = name;
}
#endregion
#endregion
#region INotifyPropertyChanged Member
#region events
/// <summary>
/// Raised when an observable property has changed.
/// </summary>
///
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event.
/// </summary>
///
/// <param name="propertyName">The name of the proiperty that has been changed.
/// </param>
///
/// <remarks>
/// Inheritors can override <see cref="OnPropertyChanged(PropertyChangedEventArgs)"/>
/// to handle the event.
/// </remarks>
///
protected void OnPropertyChanged( string propertyName )
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event.
/// </summary>
///
/// <param name="e">The event arguments.</param>
///
/// <remarks>
/// Inheritors that overrides this method must call the base method to raise
/// the <see cref="PropertyChanged"/> event.
/// </remarks>
///
protected virtual void OnPropertyChanged( PropertyChangedEventArgs e )
{
Debug.Assert(e != null);
if( e == null )
throw new ArgumentNullException("e");
VerifyPropertyName(e.PropertyName);
if( PropertyChanged != null )
PropertyChanged(this, e);
}
#endregion
#region debugging
/// <summary>
/// Detects whether the specified string contains a valid property name for
/// the current object.
/// </summary>
///
/// <param name="name">The name of the property to verify.</param>
///
/// <remarks>
/// This can be used to verify a string that contains a properrty name. It is
/// used only if the symbol "DEBUG" is defined and calls <see cref="Debug.Fail(string)"/>
/// if a property name with the specified name does not exist.
/// </remarks>
///
[Conditional("DEBUG")]
public void VerifyPropertyName( string name )
{
if( TypeDescriptor.GetProperties(this)[name] == null )
Debug.Fail("Invalid Property Name.");
}
#endregion
#endregion
}
}