You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
15 KiB
529 lines
15 KiB
/*************************************************************************************
|
|
|
|
Extended WPF Toolkit
|
|
|
|
Copyright (C) 2007-2013 Xceed Software Inc.
|
|
|
|
This program is provided to you under the terms of the Microsoft Public
|
|
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|
|
|
For more features, controls, and fast professional support,
|
|
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
|
|
|
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
|
|
|
***********************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using Xceed.Wpf.Toolkit.PropertyGrid.Commands;
|
|
using System.Windows.Media;
|
|
using System.Collections;
|
|
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
|
|
using System.Diagnostics;
|
|
using System.ComponentModel;
|
|
using System.Windows.Markup.Primitives;
|
|
using System.Windows.Data;
|
|
using System.Windows.Media.Imaging;
|
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
|
|
|
namespace Xceed.Wpf.Toolkit.PropertyGrid
|
|
{
|
|
internal abstract class DescriptorPropertyDefinitionBase : DependencyObject
|
|
{
|
|
#region Members
|
|
|
|
private string _category;
|
|
private string _categoryValue;
|
|
private string _description;
|
|
private string _displayName;
|
|
private int _displayOrder;
|
|
private bool _expandableAttribute;
|
|
private bool _isReadOnly;
|
|
private IList<Type> _newItemTypes;
|
|
private IEnumerable<CommandBinding> _commandBindings;
|
|
|
|
#endregion
|
|
|
|
internal abstract PropertyDescriptor PropertyDescriptor
|
|
{
|
|
get;
|
|
}
|
|
|
|
#region Initialization
|
|
|
|
internal DescriptorPropertyDefinitionBase( bool isPropertyGridCategorized )
|
|
{
|
|
this.IsPropertyGridCategorized = isPropertyGridCategorized;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Virtual Methods
|
|
|
|
protected virtual string ComputeCategory()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual string ComputeCategoryValue()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual string ComputeDescription()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
protected virtual int ComputeDisplayOrder( bool isPropertyGridCategorized )
|
|
{
|
|
return int.MaxValue;
|
|
}
|
|
|
|
protected virtual bool ComputeExpandableAttribute()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected abstract bool ComputeIsExpandable();
|
|
|
|
protected virtual IList<Type> ComputeNewItemTypes()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual bool ComputeIsReadOnly()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected virtual bool ComputeCanResetValue()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected virtual object ComputeAdvancedOptionsTooltip()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual void ResetValue()
|
|
{
|
|
}
|
|
|
|
protected abstract BindingBase CreateValueBinding();
|
|
|
|
#endregion
|
|
|
|
#region Internal Methods
|
|
|
|
internal abstract ObjectContainerHelperBase CreateContainerHelper( IPropertyContainer parent );
|
|
|
|
internal void RaiseContainerHelperInvalidated()
|
|
{
|
|
if( this.ContainerHelperInvalidated != null )
|
|
{
|
|
this.ContainerHelperInvalidated( this, EventArgs.Empty );
|
|
}
|
|
}
|
|
|
|
internal virtual ITypeEditor CreateDefaultEditor()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
internal virtual ITypeEditor CreateAttributeEditor()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
internal void UpdateAdvanceOptionsForItem( MarkupObject markupObject, DependencyObject dependencyObject, DependencyPropertyDescriptor dpDescriptor,
|
|
out object tooltip )
|
|
{
|
|
tooltip = StringConstants.AdvancedProperties;
|
|
|
|
bool isResource = false;
|
|
bool isDynamicResource = false;
|
|
|
|
var markupProperty = markupObject.Properties.Where( p => p.Name == PropertyName ).FirstOrDefault();
|
|
if( ( markupProperty != null )
|
|
&& ( markupProperty.PropertyType != typeof( object ) )
|
|
&& !markupProperty.PropertyType.IsEnum
|
|
&& !markupProperty.PropertyType.IsArray )
|
|
{
|
|
//TODO: need to find a better way to determine if a StaticResource has been applied to any property not just a style
|
|
isResource = ( markupProperty.Value is Style );
|
|
isDynamicResource = ( markupProperty.Value is DynamicResourceExtension );
|
|
}
|
|
|
|
if( isResource || isDynamicResource )
|
|
{
|
|
tooltip = StringConstants.Resource;
|
|
}
|
|
else
|
|
{
|
|
if( ( dependencyObject != null ) && ( dpDescriptor != null ) )
|
|
{
|
|
if( BindingOperations.GetBindingExpressionBase( dependencyObject, dpDescriptor.DependencyProperty ) != null )
|
|
{
|
|
tooltip = StringConstants.Databinding;
|
|
}
|
|
else
|
|
{
|
|
BaseValueSource bvs =
|
|
DependencyPropertyHelper
|
|
.GetValueSource( dependencyObject, dpDescriptor.DependencyProperty )
|
|
.BaseValueSource;
|
|
|
|
switch( bvs )
|
|
{
|
|
case BaseValueSource.Inherited:
|
|
case BaseValueSource.DefaultStyle:
|
|
case BaseValueSource.ImplicitStyleReference:
|
|
tooltip = StringConstants.Inheritance;
|
|
break;
|
|
case BaseValueSource.DefaultStyleTrigger:
|
|
break;
|
|
case BaseValueSource.Style:
|
|
tooltip = StringConstants.StyleSetter;
|
|
break;
|
|
|
|
case BaseValueSource.Local:
|
|
tooltip = StringConstants.Local;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void UpdateAdvanceOptions()
|
|
{
|
|
// Only set the Tooltip. the Icon will be added in XAML based on the Tooltip.
|
|
this.AdvancedOptionsTooltip = this.ComputeAdvancedOptionsTooltip();
|
|
}
|
|
|
|
internal void UpdateIsExpandable()
|
|
{
|
|
this.IsExpandable =
|
|
this.ExpandableAttribute
|
|
&& this.ComputeIsExpandable();
|
|
}
|
|
|
|
internal void UpdateValueFromSource()
|
|
{
|
|
BindingOperations.GetBindingExpressionBase( this, DescriptorPropertyDefinitionBase.ValueProperty ).UpdateTarget();
|
|
}
|
|
|
|
|
|
|
|
|
|
internal object ComputeDescriptionForItem( object item )
|
|
{
|
|
PropertyDescriptor pd = item as PropertyDescriptor;
|
|
|
|
//We do not simply rely on the "Description" property of PropertyDescriptor
|
|
//since this value is cached by PropertyDescriptor and the localized version
|
|
//(e.g., LocalizedDescriptionAttribute) value can dynamicaly change.
|
|
DescriptionAttribute descriptionAtt = PropertyGridUtilities.GetAttribute<DescriptionAttribute>( pd );
|
|
return ( descriptionAtt != null )
|
|
? descriptionAtt.Description
|
|
: pd.Description;
|
|
}
|
|
|
|
internal object ComputeNewItemTypesForItem( object item )
|
|
{
|
|
PropertyDescriptor pd = item as PropertyDescriptor;
|
|
var attribute = PropertyGridUtilities.GetAttribute<NewItemTypesAttribute>( pd );
|
|
|
|
return ( attribute != null )
|
|
? attribute.Types
|
|
: null;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal object ComputeDisplayOrderForItem( object item )
|
|
{
|
|
PropertyDescriptor pd = item as PropertyDescriptor;
|
|
List<PropertyOrderAttribute> list = pd.Attributes.OfType<PropertyOrderAttribute>().ToList();
|
|
|
|
if( list.Count > 0 )
|
|
{
|
|
this.ValidatePropertyOrderAttributes( list );
|
|
|
|
if( this.IsPropertyGridCategorized )
|
|
{
|
|
var attribute = list.FirstOrDefault( x => ( ( x.UsageContext == UsageContextEnum.Categorized )
|
|
|| ( x.UsageContext == UsageContextEnum.Both ) ) );
|
|
if( attribute != null )
|
|
return attribute.Order;
|
|
}
|
|
else
|
|
{
|
|
var attribute = list.FirstOrDefault( x => ( ( x.UsageContext == UsageContextEnum.Alphabetical )
|
|
|| ( x.UsageContext == UsageContextEnum.Both ) ) );
|
|
if( attribute != null )
|
|
return attribute.Order;
|
|
}
|
|
}
|
|
|
|
// Max Value. Properties with no order will be displayed last.
|
|
return int.MaxValue;
|
|
}
|
|
|
|
internal object ComputeExpandableAttributeForItem( object item )
|
|
{
|
|
PropertyDescriptor pd = ( PropertyDescriptor )item;
|
|
var attribute = PropertyGridUtilities.GetAttribute<ExpandableObjectAttribute>( pd );
|
|
return ( attribute != null );
|
|
}
|
|
|
|
internal int ComputeDisplayOrderInternal( bool isPropertyGridCategorized )
|
|
{
|
|
return this.ComputeDisplayOrder( isPropertyGridCategorized );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void ExecuteResetValueCommand( object sender, ExecutedRoutedEventArgs e )
|
|
{
|
|
if( ComputeCanResetValue() )
|
|
ResetValue();
|
|
}
|
|
|
|
private void CanExecuteResetValueCommand( object sender, CanExecuteRoutedEventArgs e )
|
|
{
|
|
e.CanExecute = ComputeCanResetValue();
|
|
}
|
|
|
|
private string ComputeDisplayName()
|
|
{
|
|
string displayName = PropertyDescriptor.DisplayName;
|
|
var attribute = PropertyGridUtilities.GetAttribute<ParenthesizePropertyNameAttribute>( PropertyDescriptor );
|
|
if( ( attribute != null ) && attribute.NeedParenthesis )
|
|
{
|
|
displayName = "(" + displayName + ")";
|
|
}
|
|
|
|
return displayName;
|
|
}
|
|
|
|
private void ValidatePropertyOrderAttributes( List<PropertyOrderAttribute> list )
|
|
{
|
|
if( list.Count > 0 )
|
|
{
|
|
PropertyOrderAttribute both = list.FirstOrDefault( x => x.UsageContext == UsageContextEnum.Both );
|
|
if( ( both != null ) && ( list.Count > 1 ) )
|
|
Debug.Assert( false, "A PropertyItem can't have more than 1 PropertyOrderAttribute when it has UsageContext : Both" );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
public event EventHandler ContainerHelperInvalidated;
|
|
|
|
#endregion
|
|
|
|
#region AdvancedOptionsIcon (DP)
|
|
|
|
public static readonly DependencyProperty AdvancedOptionsIconProperty =
|
|
DependencyProperty.Register( "AdvancedOptionsIcon", typeof( ImageSource ), typeof( DescriptorPropertyDefinitionBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public ImageSource AdvancedOptionsIcon
|
|
{
|
|
get
|
|
{
|
|
return ( ImageSource )GetValue( AdvancedOptionsIconProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( AdvancedOptionsIconProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AdvancedOptionsTooltip (DP)
|
|
|
|
public static readonly DependencyProperty AdvancedOptionsTooltipProperty =
|
|
DependencyProperty.Register( "AdvancedOptionsTooltip", typeof( object ), typeof( DescriptorPropertyDefinitionBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public object AdvancedOptionsTooltip
|
|
{
|
|
get
|
|
{
|
|
return ( object )GetValue( AdvancedOptionsTooltipProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( AdvancedOptionsTooltipProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion //AdvancedOptionsTooltip
|
|
|
|
#region IsExpandable (DP)
|
|
|
|
public static readonly DependencyProperty IsExpandableProperty =
|
|
DependencyProperty.Register( "IsExpandable", typeof( bool ), typeof( DescriptorPropertyDefinitionBase ), new UIPropertyMetadata( false ) );
|
|
|
|
public bool IsExpandable
|
|
{
|
|
get
|
|
{
|
|
return ( bool )GetValue( IsExpandableProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( IsExpandableProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion //IsExpandable
|
|
|
|
public string Category
|
|
{
|
|
get { return _category; }
|
|
internal set { _category = value; }
|
|
}
|
|
|
|
public string CategoryValue
|
|
{
|
|
get { return _categoryValue; }
|
|
internal set { _categoryValue = value; }
|
|
}
|
|
|
|
public IEnumerable<CommandBinding> CommandBindings
|
|
{
|
|
get { return _commandBindings; }
|
|
}
|
|
|
|
public string DisplayName
|
|
{
|
|
get { return _displayName; }
|
|
internal set { _displayName = value; }
|
|
}
|
|
|
|
|
|
|
|
public string Description
|
|
{
|
|
get { return _description; }
|
|
internal set { _description = value; }
|
|
}
|
|
|
|
public int DisplayOrder
|
|
{
|
|
get { return _displayOrder; }
|
|
internal set { _displayOrder = value; }
|
|
}
|
|
|
|
public bool IsReadOnly
|
|
{
|
|
get { return _isReadOnly; }
|
|
}
|
|
|
|
public IList<Type> NewItemTypes
|
|
{
|
|
get { return _newItemTypes; }
|
|
}
|
|
|
|
public string PropertyName
|
|
{
|
|
get
|
|
{
|
|
// A common property which is present in all selectedObjects will always have the same name.
|
|
return PropertyDescriptor.Name;
|
|
}
|
|
}
|
|
|
|
public Type PropertyType
|
|
{
|
|
get
|
|
{
|
|
return PropertyDescriptor.PropertyType;
|
|
}
|
|
}
|
|
|
|
internal bool ExpandableAttribute
|
|
{
|
|
get { return _expandableAttribute; }
|
|
set
|
|
{
|
|
_expandableAttribute = value;
|
|
this.UpdateIsExpandable();
|
|
}
|
|
}
|
|
|
|
internal bool IsPropertyGridCategorized
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
#region Value Property (DP)
|
|
|
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof( object ), typeof( DescriptorPropertyDefinitionBase ), new UIPropertyMetadata( null, OnValueChanged ) );
|
|
public object Value
|
|
{
|
|
get
|
|
{
|
|
return GetValue( ValueProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( ValueProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnValueChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
( ( DescriptorPropertyDefinitionBase )o ).OnValueChanged( e.OldValue, e.NewValue );
|
|
}
|
|
|
|
internal virtual void OnValueChanged( object oldValue, object newValue )
|
|
{
|
|
UpdateIsExpandable();
|
|
UpdateAdvanceOptions();
|
|
|
|
// Reset command also affected.
|
|
CommandManager.InvalidateRequerySuggested();
|
|
}
|
|
|
|
#endregion //Value Property
|
|
|
|
public virtual void InitProperties()
|
|
{
|
|
// Do "IsReadOnly" and PropertyName first since the others may need that value.
|
|
_isReadOnly = ComputeIsReadOnly();
|
|
_category = ComputeCategory();
|
|
_categoryValue = ComputeCategoryValue();
|
|
_description = ComputeDescription();
|
|
_displayName = ComputeDisplayName();
|
|
_displayOrder = ComputeDisplayOrder( this.IsPropertyGridCategorized );
|
|
_expandableAttribute = ComputeExpandableAttribute();
|
|
_newItemTypes = ComputeNewItemTypes();
|
|
_commandBindings = new CommandBinding[] { new CommandBinding( PropertyItemCommands.ResetValue, ExecuteResetValueCommand, CanExecuteResetValueCommand ) };
|
|
|
|
UpdateIsExpandable();
|
|
UpdateAdvanceOptions();
|
|
|
|
BindingBase valueBinding = this.CreateValueBinding();
|
|
BindingOperations.SetBinding( this, DescriptorPropertyDefinitionBase.ValueProperty, valueBinding );
|
|
}
|
|
}
|
|
}
|
|
|