File: System.Activities.Presentation\System\Activities\Presentation\Base\Core\PropertyEditing\PropertyContainer.cs
Project: ndp\cdf\src\NetFx40\Tools\System.Activities.Presentation.csproj (System.Activities.Presentation)
namespace System.Activities.Presentation.PropertyEditing
{
    using System.Windows.Controls;
    using System.Windows;
    using System;
    using System.Windows.Data;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using System.Windows.Controls.Primitives;
    using System.Windows.Media;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.Activities.Presentation;
    using System.Runtime;
    using System.Activities.Presentation.Internal.PropertyEditing.Editors;
    using System.Activities.Presentation.Internal.PropertyEditing;
 
    /// <summary>
    /// This control is used as a graphical container for PropertyEntry instances.  The control is
    /// look-less.  However, it is generally styled as a horizontal row that includes the
    /// name of the property followed by an editor for its value.  This control, however, is
    /// intended to be restiled by 3rd-parties to suite their needs.  The style is controled
    /// by three ControlTemplates (InlineRowTemplate, ExtendedPopupRowTemplate, and
    /// ExtendedPinnedRowTemplate) that are chosed by the logic within this control based
    /// on the current value of ActiveEditMode.  This control also exposes three DataTemplates
    /// (InlineEditor, ExtendedEditor, and DialogEditor) that each of the row templates can use 
    /// to display the appropriate value editor for the PropertyValue being edited.
    /// </summary>
    class PropertyContainer : Control, INotifyPropertyChanged
    {
 
        private static RoutedCommand _openDialogWindow;
 
        DataTemplate flagEditorTemplate;
 
        /// <summary>
        /// INotifyPropertyChanged event
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
 
        internal event DependencyPropertyChangedEventHandler DependencyPropertyChanged;
 
        private bool _attachedToPropertyEntryEvents;
 
        /// <summary>
        /// Creates a PropertyContainer
        /// </summary>
        [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public PropertyContainer()
        {
 
            // Set the OwningPropertyContainer (attached, inherited DP) to self,
            // so that all of the children of this control know which PropertyContainer
            // they belong to
            SetOwningPropertyContainer(this, this);
 
            this.Loaded += new RoutedEventHandler(OnLoaded);
            this.Unloaded += new RoutedEventHandler(OnUnloaded);
        }
 
        // Useful DPs
 
        // PropertyEntry DP
 
        public static readonly DependencyProperty IsValueEditEnabledProperty = DependencyProperty.Register(
            "IsValueEditEnabled",
            typeof(bool),
            typeof(PropertyContainer),
            new UIPropertyMetadata(true));
 
 
        /// <summary>
        /// Gets or sets the PropertyEntry instance on which this PropertyContainer operates. 
        /// That is the context of the PropertyContainer.  The exposed editor templates 
        /// (InlineEditor, ExtendedEditor, and DialogEditor) are based on the value of this property.
        /// </summary>
        public static readonly DependencyProperty PropertyEntryProperty =
            DependencyProperty.Register(
                "PropertyEntry",
                typeof(PropertyEntry),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    new PropertyChangedCallback(PropertyEntryPropertyChanged)));
 
        /// <summary>
        /// Gets or sets the PropertyEntry instance on which this PropertyContainer operates. 
        /// That is the context of the PropertyContainer.  The exposed editor templates 
        /// (InlineEditor, ExtendedEditor, and DialogEditor) are based on the value of this property.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public PropertyEntry PropertyEntry
        {
            get { return (PropertyEntry)this.GetValue(PropertyContainer.PropertyEntryProperty); }
            set { this.SetValue(PropertyContainer.PropertyEntryProperty, value); }
        }
 
        public bool IsValueEditEnabled
        {
            get { return (bool)GetValue(IsValueEditEnabledProperty); }
            set { SetValue(IsValueEditEnabledProperty, value); }
        }
 
        private static void PropertyEntryPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            PropertyContainer theThis = (PropertyContainer)obj;
 
            // Since the underlying property has changed, chances are that the inline or extended editors
            // have changed as well, so fire events indicating that their values have changed
            theThis.NotifyTemplatesChanged();
            theThis.OnPropertyChanged("MatchesFilter");
 
            // Switch back to Inline mode
            theThis.ActiveEditMode = PropertyContainerEditMode.Inline;
 
            // Ensure that the Template property of this control is set to the right ControlTemplate
            UpdateControlTemplate(theThis);
 
            // Hook into PropertyEntry's changed events
            if (e.OldValue != null)
                theThis.DisassociatePropertyEventHandlers((PropertyEntry)e.OldValue);
            if (e.NewValue != null)
                theThis.AssociatePropertyEventHandlers((PropertyEntry)e.NewValue);
        }
 
 
        // ActiveEditMode DP
 
        // 
 
 
 
 
        /// <summary>
        /// Gets or sets currently displayed edit mode of this container (ie. ExtendedPopup,
        /// ExtendedPinned, Inline or Dialog).  
        /// </summary>
        public static readonly DependencyProperty ActiveEditModeProperty =
            DependencyProperty.Register(
                "ActiveEditMode",
                typeof(PropertyContainerEditMode),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    PropertyContainerEditMode.Inline,
                    new PropertyChangedCallback(OnActiveEditModePropertyChanged)));
 
        /// <summary>
        /// Gets or sets currently displayed edit mode of this container (ie. ExtendedPopup,
        /// ExtendedPinned, Inline or Dialog).  
        /// </summary>
        public PropertyContainerEditMode ActiveEditMode
        {
            get { return (PropertyContainerEditMode)this.GetValue(PropertyContainer.ActiveEditModeProperty); }
            set { this.SetValue(PropertyContainer.ActiveEditModeProperty, value); }
        }
 
        private static void OnActiveEditModePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            PropertyContainer theThis = (PropertyContainer)obj;
 
            // Ensure that the Template property of this control is set to the right ControlTemplate
            UpdateControlTemplate(theThis);
 
            // Invoke a dialog editor if needed
            if (object.Equals(e.NewValue, PropertyContainerEditMode.Dialog))
            {
 
                if (OpenDialogWindow.CanExecute(null, theThis))
                {
                    // There is someone who handles this command, so let it deal with it
                    // however it wants.
                    OpenDialogWindow.Execute(null, theThis);
                }
                else
                {
                    // There is no-one handling this command, so see if there is a virtual
                    // method we can invoke
                    DialogPropertyValueEditor editor = theThis.FindDialogPropertyValueEditor();
                    if (editor != null)
                    {
                        // If the DialogCommandSource is not explicitly set, use this control as the
                        // command source
                        IInputElement dialogCommandSource = theThis.DialogCommandSource ?? theThis;
                        editor.ShowDialog(theThis.PropertyEntry.PropertyValue, dialogCommandSource);
                    }
                }
 
                // And revert back to old edit mode once done
                theThis.ActiveEditMode = (PropertyContainerEditMode)e.OldValue;
            }
        }
 
 
        // DialogCommandSource DP
 
        /// <summary>
        /// Gets or sets the IInputElement to pass into the ShowDialog() method as the command source.
        /// If null (default), _this_ will be passed in.
        /// Note: ShowDialog() method is called on a DialogPropertyValueEditor instance if a dialog editor
        /// is invoked and the editor does not specify any dialog DataTemplate.
        /// </summary>
        public static readonly DependencyProperty DialogCommandSourceProperty =
            DependencyProperty.Register(
                "DialogCommandSource",
                typeof(IInputElement),
                typeof(PropertyContainer),
                new PropertyMetadata((IInputElement)null));
 
        /// <summary>
        /// Gets or sets the IInputElement to pass into the ShowDialog() method as the command source.
        /// If null (default), _this_ will be passed in.
        /// Note: ShowDialog() method is called on a DialogPropertyValueEditor instance if a dialog editor
        /// is invoked and the editor does not specify any dialog DataTemplate.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public IInputElement DialogCommandSource
        {
            get { return (IInputElement)this.GetValue(DialogCommandSourceProperty); }
            set { this.SetValue(DialogCommandSourceProperty, value); }
        }
 
 
        // OwningPropertyContainer Attached, Inherited DP
 
        /// <summary>
        /// Attached, inherited DP that can be used by UI elements of PropertyValueEditors
        /// to gain access to their parent PropertyContainer.
        /// </summary>
        public static readonly DependencyProperty OwningPropertyContainerProperty =
            DependencyProperty.RegisterAttached(
                "OwningPropertyContainer",
                typeof(PropertyContainer),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
 
        /// <summary>
        /// Setter for attached, inherited DP that can be used by UI elements of PropertyValueEditors
        /// to gain access to their parent PropertyContainer.
        /// </summary>
        /// <param name="dependencyObject">The DO to set the property on</param>
        /// <param name="value">The Owning PropertyContainer</param>
        public static void SetOwningPropertyContainer(DependencyObject dependencyObject, PropertyContainer value)
        {
            if (dependencyObject == null)
                throw FxTrace.Exception.ArgumentNull("dependencyObject");
 
            dependencyObject.SetValue(PropertyContainer.OwningPropertyContainerProperty, value);
        }
 
        /// <summary>
        /// Getter for attached, inherited DP that can be used by UI elements of PropertyValueEditors
        /// to gain access to their parent PropertyContainer.
        /// </summary>
        /// <param name="dependencyObject">The DO to get the property from</param>
        /// <returns>The owning PropertyContainer</returns>
        public static PropertyContainer GetOwningPropertyContainer(DependencyObject dependencyObject)
        {
            if (dependencyObject == null)
                throw FxTrace.Exception.ArgumentNull("dependencyObject");
 
            return (PropertyContainer)dependencyObject.GetValue(PropertyContainer.OwningPropertyContainerProperty);
        }
 
 
        // ControlTemplates for PropertyContainer to define the UI for the different edit modes
 
        // InlineRowTemplate DP
 
        /// <summary>
        /// This DP is used to get/set the InlineRowTemplate for the PropertyContainer.  The 
        /// InlineRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = Inline.
        /// </summary>
        public static readonly DependencyProperty InlineRowTemplateProperty =
            DependencyProperty.Register(
                "InlineRowTemplate",
                typeof(ControlTemplate),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback(RowTemplateChanged)));
 
        /// <summary>
        /// Gets or sets the InlineRowTemplate for the PropertyContainer.  The 
        /// InlineRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = Inline.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public ControlTemplate InlineRowTemplate
        {
            get { return (ControlTemplate)this.GetValue(PropertyContainer.InlineRowTemplateProperty); }
            set { this.SetValue(PropertyContainer.InlineRowTemplateProperty, value); }
        }
 
        // Called when any of the row templates (InlineRowTemplate, ExtendedPopupRowTemplate, ExtendedPinnedRowTemplate)
        // change
        private static void RowTemplateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            PropertyContainer theThis = (PropertyContainer)obj;
            bool updateControlTemplate = false;
 
            // Check InlineRowTemplate
            updateControlTemplate = updateControlTemplate |
                (e.Property == PropertyContainer.InlineRowTemplateProperty &&
                theThis.ActiveEditMode == PropertyContainerEditMode.Inline);
 
            // Check ExtendedPopup
            updateControlTemplate = updateControlTemplate |
                (e.Property == PropertyContainer.ExtendedPopupRowTemplateProperty &&
                theThis.ActiveEditMode == PropertyContainerEditMode.ExtendedPopup);
 
            // Check ExtendedPinned
            updateControlTemplate = updateControlTemplate |
                (e.Property == PropertyContainer.ExtendedPinnedRowTemplateProperty &&
                theThis.ActiveEditMode == PropertyContainerEditMode.ExtendedPinned);
 
            if (updateControlTemplate)
                UpdateControlTemplate(theThis);
        }
 
 
        // ExtendedPopupRowTemplate DP
 
        /// <summary>
        /// This DP is used to get/set the ExtendedPopupRowTemplate for this PropertyContainer.
        /// The ExtendedPopupRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = ExtendedPopup.  Generally, host implementations will define this
        /// template to automatically include the InlineRowTemplate as well.
        /// </summary>
        public static readonly DependencyProperty ExtendedPopupRowTemplateProperty =
            DependencyProperty.Register(
                "ExtendedPopupRowTemplate",
                typeof(ControlTemplate),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback(RowTemplateChanged)));
 
        /// <summary>
        /// Gets or sets the ExtendedPopupRowTemplate for this PropertyContainer.  
        /// The ExtendedPopupRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = ExtendedPopup.  Generally, host implementations will define this
        /// template to automatically include the InlineRowTemplate as well.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public ControlTemplate ExtendedPopupRowTemplate
        {
            get { return (ControlTemplate)this.GetValue(PropertyContainer.ExtendedPopupRowTemplateProperty); }
            set { this.SetValue(PropertyContainer.ExtendedPopupRowTemplateProperty, value); }
        }
 
 
        // ExtendedPinnedRowTemplate DP
 
        /// <summary>
        /// This DP is used to get/set the ExtendedPinnedRowTemplate for this PropertyContainer.  
        /// The ExtendedPinnedRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = ExtendedPinned.  Generally, host implementations will define this
        /// template to automatically include the InlineRowTemplate as well.
        /// </summary>
        public static readonly DependencyProperty ExtendedPinnedRowTemplateProperty =
            DependencyProperty.Register(
                "ExtendedPinnedRowTemplate",
                typeof(ControlTemplate),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback(RowTemplateChanged)));
 
        /// <summary>
        /// Get/set the ExtendedPinnedRowTemplate for this PropertyContainer.  
        /// The ExtendedPinnedRowTemplate defines how the PropertyContainer renders itself when 
        /// ActiveEditMode = ExtendedPinned.  Generally, host implementations will define this
        /// template to automatically include the InlineRowTemplate as well.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public ControlTemplate ExtendedPinnedRowTemplate
        {
            get { return (ControlTemplate)this.GetValue(PropertyContainer.ExtendedPinnedRowTemplateProperty); }
            set { this.SetValue(PropertyContainer.ExtendedPinnedRowTemplateProperty, value); }
        }
 
 
        // Default PropertyValueEditors to use when a given property doesn't specify its own
 
        // DefaultStandardValuesPropertyValueEditor DP
 
        /// <summary>
        /// DP to get or set the default standard-values editor which is used when a PropertyEntry supports
        /// StandardValues (enum or through a TypeConverter) and there isn't a PropertyValueEditor
        /// defined for the PropertyEntry or Type explicitely.
        /// </summary>
        public static readonly DependencyProperty DefaultStandardValuesPropertyValueEditorProperty =
            DependencyProperty.Register(
                "DefaultStandardValuesPropertyValueEditor",
                typeof(PropertyValueEditor),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    new PropertyChangedCallback(DefaultPropertyValueEditorChanged)));
 
        /// <summary>
        /// Gets or set the default standard-values editor which is used when a PropertyEntry supports
        /// StandardValues (enum or through a TypeConverter) and there isn't a PropertyValueEditor
        /// defined for the PropertyEntry or Type explicitely.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public PropertyValueEditor DefaultStandardValuesPropertyValueEditor
        {
            get { return (PropertyValueEditor)this.GetValue(PropertyContainer.DefaultStandardValuesPropertyValueEditorProperty); }
            set { this.SetValue(PropertyContainer.DefaultStandardValuesPropertyValueEditorProperty, value); }
        }
 
        private static void DefaultPropertyValueEditorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            PropertyContainer theThis = (PropertyContainer)obj;
 
            // Since one of the default PVE's has changed, chances are that the Inline or the Extended
            // editor template has changed as well.
            theThis.NotifyTemplatesChanged();
        }
 
 
        // DefaultPropertyValueEditor DP
 
        /// <summary>
        /// DP to get or set the default PropertyValueEditor which is the editor used when the
        /// PropertyEntry or Type does not explicitely define its own PropertyValueEditor and does not
        /// support StandardValues.
        /// </summary>
        public static readonly DependencyProperty DefaultPropertyValueEditorProperty =
            DependencyProperty.Register(
                "DefaultPropertyValueEditor",
                typeof(PropertyValueEditor),
                typeof(PropertyContainer),
                new FrameworkPropertyMetadata(
                    null,
                    new PropertyChangedCallback(DefaultPropertyValueEditorChanged)));
 
        /// <summary>
        /// Gets or sets the default PropertyValueEditor which is the editor used when the
        /// PropertyEntry or Type does not explicitely define its own PropertyValueEditor and does not
        /// support StandardValues.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public PropertyValueEditor DefaultPropertyValueEditor
        {
            get { return (PropertyValueEditor)this.GetValue(PropertyContainer.DefaultPropertyValueEditorProperty); }
            set { this.SetValue(PropertyContainer.DefaultPropertyValueEditorProperty, value); }
        }
 
 
        // Regular properties (read-only values for DataBinding)
 
        // InlineEditorTemplate read-only CLR property
 
        /// <summary>
        /// Gets the most appropriate InlineEditorTemplate for the current PropertyEntry.
        /// A row template may decide to use this value to render the editor on the appropriate place.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public DataTemplate InlineEditorTemplate
        {
            get
            {
                return FindPropertyValueEditorTemplate(PropertyContainerEditMode.Inline);
            }
        }
 
 
        // ExtendedEditorTemplate read-only CLR property
 
        /// <summary>
        /// Gets the most appropriate ExtendedEditorTemplate for the current PropertyEntry.
        /// A row template may decide to use this value to render the editor on the appropriate place.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public DataTemplate ExtendedEditorTemplate
        {
            get
            {
                return FindPropertyValueEditorTemplate(PropertyContainerEditMode.ExtendedPinned);
            }
        }
 
 
        // DialogEditorTemplate read-only CLR property
 
        /// <summary>
        /// Gets the most appropriate DialogEditorTemplate for the current PropertyEntry.
        /// A row template or a Dialog may decide to use this value to render the editor on the
        /// appropriate place.
        /// </summary>
        [Fx.Tag.KnownXamlExternalAttribute]
        public DataTemplate DialogEditorTemplate
        {
            get
            {
                return FindPropertyValueEditorTemplate(PropertyContainerEditMode.Dialog);
            }
        }
 
 
        // MatchesFilter read-only CLR property
 
        /// <summary>
        /// Gets the value for MatchesFilter stored in the contained PropertyEntry.  If the PropertyEntry
        /// is null, the value returned is false.
        /// This property can be used to trigger UI changes to the PropertyContainer based on
        /// whether the current PropertyEntry matches the current filter or not.
        /// </summary>
        public bool MatchesFilter
        {
            get
            {
                PropertyEntry property = this.PropertyEntry;
                return property != null && property.MatchesFilter;
            }
        }
 
 
        // OpenDialogWindow static, read-only command property
 
        /// <summary>
        /// Gets the command that is fired when someone changes the ActiveEditMode property to "Dialog".
        /// The host may choose to handle this command and, display the DialogEditorTemplate
        /// (if one exists) in a host-specific dialog container.  If the host does not handle
        /// this command (OpenDialogWindow.CanExecute is false), the PropertyContainer itself
        /// defaults to calling into the virtual DialogPropertyValueEditor.ShowDialog()
        /// method, but only if DialogPropertyValueEditor is found.
        /// </summary>
        public static RoutedCommand OpenDialogWindow
        {
            get
            {
                if (_openDialogWindow == null)
                    _openDialogWindow = new RoutedCommand("OpenDialogWindow", typeof(PropertyContainer));
 
                return _openDialogWindow;
            }
        }
 
 
        internal bool SupportsEditMode(PropertyContainerEditMode mode)
        {
            // special handling for dialog editor
            if (mode == PropertyContainerEditMode.Dialog)
                return FindDialogPropertyValueEditor() != null;
 
            // for everything else
            return FindPropertyValueEditorTemplate(mode) != null;
        }
 
        // When the control gets unloaded, unhook any remaining event handlers
        // so that it can be garbage collected
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            PropertyEntry entry = this.PropertyEntry;
            if (entry != null)
                DisassociatePropertyEventHandlers(entry);
        }
 
        // When the control gets re-loaded, re-hook any previous event handlers
        // that may have been disassociated during Unload
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            PropertyEntry entry = this.PropertyEntry;
            if (entry != null)
                AssociatePropertyEventHandlers(entry);
        }
 
        // Helper that hooks into PropertyChanged events on the given Property
        private void AssociatePropertyEventHandlers(PropertyEntry property)
        {
            if (!_attachedToPropertyEntryEvents)
            {
                property.PropertyChanged += new PropertyChangedEventHandler(OnPropertyPropertyChanged);
                _attachedToPropertyEntryEvents = true;
            }
        }
 
        // Helper that unhooks from PropertyChanged events on the given Property
        private void DisassociatePropertyEventHandlers(PropertyEntry property)
        {
            if (_attachedToPropertyEntryEvents)
            {
                property.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyPropertyChanged);
                _attachedToPropertyEntryEvents = false;
            }
        }
 
        // Called when the properties of the Property object change
        private void OnPropertyPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            // Propagate MatchesFilter change notifications outwards so that
            // people can set up triggers against it
            if ("MatchesFilter".Equals(e.PropertyName))
                this.OnPropertyChanged("MatchesFilter");
            else if ("PropertyValueEditor".Equals(e.PropertyName))
                this.NotifyTemplatesChanged();
        }
 
        /// <summary>
        /// Helper class that attempts to find the DataTemplate for the requested PropertyContainerEditMode
        /// given the currently displayed PropertyEntry and the currently set default PropertyValueEditors.
        /// 
        /// If the requested DataTemplate is found on the PropertyValueEditor associated with the displayed
        /// control, is it returned.
        /// 
        /// Otherwise if the requested DataTemplate is found on DefaultStandardValuesPropertyValueEditor,
        /// it is returned.
        /// 
        /// Otherwise if the requested DataTemplate is found on DefaultPropertyValueEditor,
        /// it is returned.
        /// 
        /// Otherwise null is returned.
        /// </summary>
        /// <param name="editMode">The editMode for which the DataTemplate should be retrieved</param>
        /// <returns>Most relevant DataTemplate for the specified edit mode based on the currently
        /// displayed PropertyEntry and the current set of default PropertyValueEditors, or null if not
        /// found.</returns>
        private DataTemplate FindPropertyValueEditorTemplate(PropertyContainerEditMode editMode)
        {
            PropertyEntry property = this.PropertyEntry;
            PropertyValueEditor editor = null;
            DataTemplate requestedTemplate = null;
 
            // Look at property
            if (property != null)
            {
                editor = property.PropertyValueEditor;
                if (editor != null)
                {
                    requestedTemplate = editor.GetPropertyValueEditor(editMode);
                }
            }
 
            if (requestedTemplate != null)
                return requestedTemplate;
 
            // Is the property of type enum and used as flags?
            if (IsFlagsProperty(property))
            {
                requestedTemplate = this.GetFlagEditorTemplate(editMode);
            }
 
            if (requestedTemplate != null)
            {
                return requestedTemplate;
            }
 
            // Does the property have standard values?
            if (property != null && property.HasStandardValuesInternal)
            {
                editor = this.DefaultStandardValuesPropertyValueEditor;
                if (editor != null)
                {
                    requestedTemplate = editor.GetPropertyValueEditor(editMode);
                }
            }
 
            if (requestedTemplate != null)
                return requestedTemplate;
 
            // Use the default
            editor = this.DefaultPropertyValueEditor;
            if (editor != null)
            {
                requestedTemplate = editor.GetPropertyValueEditor(editMode);
            }
 
            return requestedTemplate;
        }
 
        bool IsFlagsProperty(PropertyEntry property)
        {
            return property != null && property.PropertyType != null && property.PropertyType.IsEnum &&
                   ExtensibilityAccessor.GetAttribute<FlagsAttribute>(property.PropertyType) != null;
        }
 
        DataTemplate GetFlagEditorTemplate(PropertyContainerEditMode editMode)
        {
            Type propertyType = this.PropertyEntry.PropertyType;
            if (editMode == PropertyContainerEditMode.Inline)
            {
                if (this.flagEditorTemplate == null)
                {
                    this.flagEditorTemplate = new DataTemplate();
                    this.flagEditorTemplate.VisualTree = new FrameworkElementFactory(typeof(FlagEditor));
                    this.flagEditorTemplate.VisualTree.SetValue(FlagEditor.FlagTypeProperty, propertyType);
                    Binding binding = new Binding("Value");
                    binding.Converter = new FlagStringConverter();
                    binding.ConverterParameter = propertyType;
                    binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
                    this.flagEditorTemplate.VisualTree.SetBinding(FlagEditor.TextProperty, binding);
                }
                return this.flagEditorTemplate;
            }
            else
            {
                return null;
            }
        }
 
        // Helper that tries to find the first applicable DialogPropertyValueEditor
        private DialogPropertyValueEditor FindDialogPropertyValueEditor()
        {
            PropertyEntry property = this.PropertyEntry;
            DialogPropertyValueEditor editor = null;
 
            // Look at property
            if (property != null)
            {
                editor = property.PropertyValueEditor as DialogPropertyValueEditor;
            }
 
            if (editor != null)
                return editor;
 
            // Does the property have standard values?
            if (property != null && property.HasStandardValuesInternal)
            {
                editor = this.DefaultStandardValuesPropertyValueEditor as DialogPropertyValueEditor;
            }
 
            if (editor != null)
                return editor;
 
            // Use the default
            editor = this.DefaultPropertyValueEditor as DialogPropertyValueEditor;
 
            return editor;
        }
 
        // Updates the ControlTemplate of this control based on the currently ActiveEditMode
        private static void UpdateControlTemplate(PropertyContainer container)
        {
 
            PropertyContainerEditMode editMode = container.ActiveEditMode;
            ControlTemplate newTemplate = null;
 
            switch (editMode)
            {
                case PropertyContainerEditMode.Inline:
                    newTemplate = container.InlineRowTemplate;
                    break;
                case PropertyContainerEditMode.ExtendedPopup:
                    newTemplate = container.ExtendedPopupRowTemplate;
                    break;
                case PropertyContainerEditMode.ExtendedPinned:
                    newTemplate = container.ExtendedPinnedRowTemplate;
                    break;
                case PropertyContainerEditMode.Dialog:
                    // In dialog case, just keep the same value
                    return;
                default:
                    Debug.Fail(
                        string.Format(
                            System.Globalization.CultureInfo.CurrentCulture,
                            "PropertyContainerEditMode does not yet support PropertyContainerEditMode '{0}'.",
                            editMode.ToString()));
                    newTemplate = container.Template;
                    break;
            }
 
            if (newTemplate != container.Template)
                container.Template = newTemplate;
        }
 
        private void NotifyTemplatesChanged()
        {
            OnPropertyChanged("InlineEditorTemplate");
            OnPropertyChanged("ExtendedEditorTemplate");
            OnPropertyChanged("DialogEditorTemplate");
        }
 
        /// <summary>
        /// Called when a property changes
        /// </summary>
        /// <param name="propertyName">Name of the property</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
 
        /// <summary>
        /// Called when a property changes
        /// </summary>
        /// <param name="e">Name of the property</param>
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if (DependencyPropertyChanged != null)
                DependencyPropertyChanged(this, e);
 
            base.OnPropertyChanged(e);
        }
    }
}