// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WrapControlHelper.cs" company="Catel development team">
// Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
// Available wrap options that can be used in the <see cref="WrapControlHelper" />.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Catel.Windows.Controls;
namespace Catel.Windows
{
#region Enums
/// <summary>
/// Available wrap options that can be used in the <see cref="WrapControlHelper"/>.
/// </summary>
[Flags]
internal enum WrapOptions
{
/// <summary>
/// Generates a <see cref="InfoBarMessageControl"/> around the element to wrap.
/// </summary>
GenerateInfoBarMessageControl = 1,
/// <summary>
/// Generates a <see cref="WarningAndErrorValidator"/> for the data context.
/// </summary>
GenerateWarningAndErrorValidatorForDataContext = 2,
/// <summary>
/// All available options.
/// </summary>
All = GenerateInfoBarMessageControl | GenerateWarningAndErrorValidatorForDataContext
}
#endregion
/// <summary>
/// An helper to wrap controls and windows with several controls, such as the <see cref="InfoBarMessageControl"/>.
/// </summary>
internal static class WrapControlHelper
{
#region Constants
/// <summary>
/// The name of the internal grid. Retrieve the grid with this name to add custom controls to the inner grid.
/// </summary>
public const string InternalGridName = "_InternalGridName";
/// <summary>
/// The name of the wrap panel that contains the buttons.
/// </summary>
public const string ButtonsWrapPanelName = "_ButtonsWrapPanel";
/// <summary>
/// The name of the main content holder, used to prevent that an element is wrapped multiple times.
/// </summary>
public const string MainContentHolderName = "_MainContentHolder";
/// <summary>
/// The name of the info bar message control.
/// </summary>
public const string InfoBarMessageControlName = "_InfoBarMessageControl";
/// <summary>
/// The name of the warning and error validator control.
/// </summary>
public const string WarningAndErrorValidatorName = "_WarningAndErrorValidator";
#endregion
/// <summary>
/// Determines whether the specified <see cref="FrameworkElement"/> can be safely wrapped.
/// </summary>
/// <param name="frameworkElement">The framework element.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="FrameworkElement"/> can be safely wrapped; otherwise, <c>false</c>.
/// </returns>
public static bool CanBeWrapped(FrameworkElement frameworkElement)
{
if (frameworkElement == null)
{
return false;
}
if (frameworkElement.Name == MainContentHolderName)
{
return false;
}
return true;
}
/// <summary>
/// Wraps the specified framework element without any buttons.
/// </summary>
/// <param name="frameworkElement">The framework element.</param>
/// <param name="wrapOptions">The wrap options.</param>
/// <returns>
/// <see cref="Grid"/> that contains the wrapped content.
/// </returns>
/// <remarks>
/// The framework element that is passed must be disconnected from the parent first. It is recommended to first check whether a
/// framework element can be wrapped by using the <see cref="CanBeWrapped"/> method.
/// </remarks>
public static Grid Wrap(FrameworkElement frameworkElement, WrapOptions wrapOptions)
{
return Wrap(frameworkElement, wrapOptions, new DataWindowButton[] { }, null);
}
/// <summary>
/// Wraps the specified framework element without any buttons.
/// </summary>
/// <param name="frameworkElement">The framework element.</param>
/// <param name="wrapOptions">The wrap options.</param>
/// <param name="parentContentControl">The parent content control.</param>
/// <returns>
/// <see cref="Grid"/> that contains the wrapped content.
/// </returns>
/// <remarks>
/// The framework element that is passed must be disconnected from the parent first. It is recommended to first check whether a
/// framework element can be wrapped by using the <see cref="CanBeWrapped"/> method.
/// <para />
/// This method will automatically handle the disconnecting of the framework element from the parent is the <paramref name="parentContentControl"/>
/// is passed.
/// </remarks>
public static Grid Wrap(FrameworkElement frameworkElement, WrapOptions wrapOptions, ContentControl parentContentControl)
{
return Wrap(frameworkElement, wrapOptions, new DataWindowButton[] {}, parentContentControl);
}
/// <summary>
/// Wraps the specified framework element without any buttons.
/// </summary>
/// <param name="frameworkElement">The framework element.</param>
/// <param name="wrapOptions">The wrap options.</param>
/// <param name="buttons">The buttons.</param>
/// <returns>
/// <see cref="Grid"/> that contains the wrapped content.
/// </returns>
/// <remarks>
/// The framework element that is passed must be disconnected from the parent first. It is recommended to first check whether a
/// framework element can be wrapped by using the <see cref="CanBeWrapped"/> method.
/// </remarks>
public static Grid Wrap(FrameworkElement frameworkElement, WrapOptions wrapOptions, DataWindowButton[] buttons)
{
return Wrap(frameworkElement, wrapOptions, buttons, null);
}
/// <summary>
/// Wraps the specified framework element.
/// </summary>
/// <param name="frameworkElement">The framework element.</param>
/// <param name="wrapOptions">The wrap options.</param>
/// <param name="buttons">The buttons to add.</param>
/// <param name="parentContentControl">The parent content control.</param>
/// <returns><see cref="Grid"/> that contains the wrapped content.</returns>
/// <remarks>
/// The framework element that is passed must be disconnected from the parent first. It is recommended to first check whether a
/// framework element can be wrapped by using the <see cref="CanBeWrapped"/> method.
/// This method will automatically handle the disconnecting of the framework element from the parent is the <paramref name="parentContentControl"/>
/// is passed.
/// </remarks>
public static Grid Wrap(FrameworkElement frameworkElement, WrapOptions wrapOptions, DataWindowButton[] buttons, ContentControl parentContentControl)
{
if (frameworkElement == null)
{
throw new ArgumentNullException("frameworkElement");
}
if (buttons == null)
{
throw new ArgumentNullException("buttons");
}
if (frameworkElement.Name == MainContentHolderName)
{
return (Grid)frameworkElement;
}
if (parentContentControl != null)
{
parentContentControl.Content = null;
}
FrameworkElement mainContent = frameworkElement;
// Create the outside grid, so the inner grid is never the same as the main content holder
Grid outsideGrid = new Grid();
outsideGrid.Name = MainContentHolderName;
if (Application.Current != null)
{
#if SILVERLIGHT
// TODO: Fix styles for silverlight
#else
outsideGrid.Resources.MergedDictionaries.Add(Application.Current.Resources);
#endif
}
#region Generate buttons
if (buttons.Length > 0)
{
// Add wrappanel containing the buttons
WrapPanel buttonsWrapPanel = new WrapPanel();
buttonsWrapPanel.Name = ButtonsWrapPanelName;
#if SILVERLIGHT
buttonsWrapPanel.Style = Application.Current.Resources["RightAlignedButtonsWrapPanelStyle"] as Style;
#else
buttonsWrapPanel.SetResourceReference(WrapPanel.StyleProperty, "RightAlignedButtonsWrapPanelStyle");
#endif
foreach (DataWindowButton dataWindowButton in buttons)
{
Button button = new Button();
if (dataWindowButton.CommandBindingPath != null)
{
button.SetBinding(Button.CommandProperty, new Binding(dataWindowButton.CommandBindingPath));
}
else
{
button.Command = dataWindowButton.Command;
}
button.Content = dataWindowButton.Text;
#if SILVERLIGHT
button.Style = Application.Current.Resources["RightAlignedFixedSizeButtonStyle"] as Style;
#else
button.SetResourceReference(Button.StyleProperty, "RightAlignedFixedSizeButtonStyle");
button.IsDefault = dataWindowButton.IsDefault;
button.IsCancel = dataWindowButton.IsCancel;
#endif
buttonsWrapPanel.Children.Add(button);
}
// Create dockpanel that will dock the buttons underneath the content
DockPanel subDockPanel = new DockPanel();
subDockPanel.LastChildFill = true;
DockPanel.SetDock(buttonsWrapPanel, Dock.Bottom);
subDockPanel.Children.Add(buttonsWrapPanel);
// Add actual content
subDockPanel.Children.Add(frameworkElement);
// The dockpanel is now the main content
mainContent = subDockPanel;
}
#endregion
#region Generate internal grid
// Create grid
Grid internalGrid = new Grid();
internalGrid.Name = InternalGridName;
internalGrid.Children.Add(mainContent);
// Grid is now the main content
mainContent = internalGrid;
#endregion
#region Generate WarningAndErrorValidator
if (Enum<WrapOptions>.Flags.IsFlagSet(wrapOptions, WrapOptions.GenerateWarningAndErrorValidatorForDataContext))
{
// Create warning and error validator
WarningAndErrorValidator warningAndErrorValidator = new WarningAndErrorValidator();
warningAndErrorValidator.Name = WarningAndErrorValidatorName;
warningAndErrorValidator.SetBinding(WarningAndErrorValidator.SourceProperty, new Binding());
// Add to grid
internalGrid.Children.Add(warningAndErrorValidator);
}
#endregion
#region Generate InfoBarMessageControl
if (Enum<WrapOptions>.Flags.IsFlagSet(wrapOptions, WrapOptions.GenerateInfoBarMessageControl))
{
// Create info bar message control
InfoBarMessageControl infoBarMessageControl = new InfoBarMessageControl();
infoBarMessageControl.Name = InfoBarMessageControlName;
infoBarMessageControl.Content = mainContent;
// This is now the main content
mainContent = infoBarMessageControl;
}
#endregion
// Set content of the outside grid
outsideGrid.Children.Add(mainContent);
if (parentContentControl != null)
{
parentContentControl.Content = outsideGrid;
}
return outsideGrid;
}
/// <summary>
/// Gets a wrapped element mapped by the <paramref name="wrapOption"/>.
/// </summary>
/// <typeparam name="T">Type of the control to return.</typeparam>
/// <param name="wrappedGrid">The wrapped grid.</param>
/// <param name="wrapOption">The wrap option that is used, which will be mapped to the control. The value <see cref="WrapOptions.All"/> is not allowed and will throw an exception.</param>
/// <returns>
/// <see cref="FrameworkElement"/> or <c>null</c> if the element is not found.
/// </returns>
/// <exception cref="ArgumentNullException">when <paramref name="wrappedGrid"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">when <paramref name="wrapOption"/> is <see cref="WrapOptions.All"/>.</exception>
public static T GetWrappedElement<T>(Grid wrappedGrid, WrapOptions wrapOption) where T : FrameworkElement
{
return GetWrappedElement(wrappedGrid, wrapOption) as T;
}
/// <summary>
/// Gets a wrapped element mapped by the <paramref name="wrapOption"/>.
/// </summary>
/// <param name="wrappedGrid">The wrapped grid.</param>
/// <param name="wrapOption">The wrap option that is used, which will be mapped to the control. The value <see cref="WrapOptions.All"/> is not allowed and will throw an exception.</param>
/// <returns>
/// <see cref="FrameworkElement"/> or <c>null</c> if the element is not found.
/// </returns>
/// <exception cref="ArgumentNullException">when <paramref name="wrappedGrid"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">when <paramref name="wrapOption"/> is <see cref="WrapOptions.All"/>.</exception>
public static FrameworkElement GetWrappedElement(Grid wrappedGrid, WrapOptions wrapOption)
{
if (wrappedGrid == null)
{
throw new ArgumentNullException("wrappedGrid");
}
if (wrapOption == WrapOptions.All)
{
throw new ArgumentOutOfRangeException("wrapOption");
}
switch (wrapOption)
{
case WrapOptions.GenerateInfoBarMessageControl:
return GetWrappedElement(wrappedGrid, InfoBarMessageControlName);
case WrapOptions.GenerateWarningAndErrorValidatorForDataContext:
return GetWrappedElement(wrappedGrid, WarningAndErrorValidatorName);
}
return null;
}
/// <summary>
/// Gets a wrapped element by name.
/// </summary>
/// <typeparam name="T">Type of the control to return.</typeparam>
/// <param name="wrappedGrid">The wrapped grid.</param>
/// <param name="controlName">Name of the control.</param>
/// <returns>
/// <see cref="FrameworkElement"/> or <c>null</c> if the element is not found.
/// </returns>
/// <exception cref="ArgumentNullException">when <paramref name="wrappedGrid"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentNullException">when <paramref name="controlName"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">when the <paramref name="controlName"/> is not a valid control name.</exception>
public static T GetWrappedElement<T>(Grid wrappedGrid, string controlName) where T : FrameworkElement
{
return GetWrappedElement(wrappedGrid, controlName) as T;
}
/// <summary>
/// Gets a wrapped element by name.
/// </summary>
/// <param name="wrappedGrid">The wrapped grid.</param>
/// <param name="controlName">Name of the control.</param>
/// <returns>
/// <see cref="FrameworkElement"/> or <c>null</c> if the element is not found.
/// </returns>
/// <exception cref="ArgumentNullException">when <paramref name="wrappedGrid"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentNullException">when <paramref name="controlName"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">when the <paramref name="controlName"/> is not a valid control name.</exception>
public static FrameworkElement GetWrappedElement(Grid wrappedGrid, string controlName)
{
if (wrappedGrid == null)
{
throw new ArgumentNullException("wrappedGrid");
}
if (controlName == null)
{
throw new ArgumentNullException("controlName");
}
if ((controlName != InfoBarMessageControlName) && (controlName != WarningAndErrorValidatorName))
{
throw new ArgumentOutOfRangeException("controlName");
}
return LogicalTreeHelper.FindLogicalNode(wrappedGrid, controlName) as FrameworkElement;
}
}
}