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.
514 lines
14 KiB
514 lines
14 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.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using System.Windows.Data;
|
|
using System.Collections;
|
|
using Xceed.Wpf.Toolkit.Core.Utilities;
|
|
using System.Reflection;
|
|
using System.Linq.Expressions;
|
|
|
|
namespace Xceed.Wpf.Toolkit.PropertyGrid
|
|
{
|
|
[TemplatePart( Name = PropertyGrid.PART_PropertyItemsControl, Type = typeof( PropertyItemsControl ) )]
|
|
[TemplatePart( Name = PropertyItemBase.PART_ValueContainer, Type = typeof( ContentControl ) )]
|
|
public abstract class PropertyItemBase : Control, IPropertyContainer, INotifyPropertyChanged
|
|
{
|
|
internal const string PART_ValueContainer = "PART_ValueContainer";
|
|
|
|
private ContentControl _valueContainer;
|
|
private ContainerHelperBase _containerHelper;
|
|
private IPropertyContainer _parentNode;
|
|
internal bool _isPropertyGridCategorized;
|
|
internal bool _isSortedAlphabetically = true;
|
|
|
|
#region Properties
|
|
|
|
#region AdvancedOptionsIcon
|
|
|
|
public static readonly DependencyProperty AdvancedOptionsIconProperty =
|
|
DependencyProperty.Register( "AdvancedOptionsIcon", typeof( ImageSource ), typeof( PropertyItemBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public ImageSource AdvancedOptionsIcon
|
|
{
|
|
get { return ( ImageSource )GetValue( AdvancedOptionsIconProperty ); }
|
|
set { SetValue( AdvancedOptionsIconProperty, value ); }
|
|
}
|
|
|
|
#endregion //AdvancedOptionsIcon
|
|
|
|
#region AdvancedOptionsTooltip
|
|
|
|
public static readonly DependencyProperty AdvancedOptionsTooltipProperty =
|
|
DependencyProperty.Register( "AdvancedOptionsTooltip", typeof( object ), typeof( PropertyItemBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public object AdvancedOptionsTooltip
|
|
{
|
|
get { return ( object )GetValue( AdvancedOptionsTooltipProperty ); }
|
|
set { SetValue( AdvancedOptionsTooltipProperty, value ); }
|
|
}
|
|
|
|
#endregion //AdvancedOptionsTooltip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Description
|
|
|
|
public static readonly DependencyProperty DescriptionProperty =
|
|
DependencyProperty.Register( "Description", typeof( string ), typeof( PropertyItemBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public string Description
|
|
{
|
|
get { return ( string )GetValue( DescriptionProperty ); }
|
|
set { SetValue( DescriptionProperty, value ); }
|
|
}
|
|
|
|
#endregion //Description
|
|
|
|
#region DisplayName
|
|
|
|
public static readonly DependencyProperty DisplayNameProperty =
|
|
DependencyProperty.Register( "DisplayName", typeof( string ), typeof( PropertyItemBase ), new UIPropertyMetadata( null ) );
|
|
|
|
public string DisplayName
|
|
{
|
|
get { return ( string )GetValue( DisplayNameProperty ); }
|
|
set { SetValue( DisplayNameProperty, value ); }
|
|
}
|
|
|
|
#endregion //DisplayName
|
|
|
|
#region Editor
|
|
|
|
public static readonly DependencyProperty EditorProperty = DependencyProperty.Register( "Editor", typeof( FrameworkElement ), typeof( PropertyItemBase ), new UIPropertyMetadata( null, OnEditorChanged ) );
|
|
public FrameworkElement Editor
|
|
{
|
|
get
|
|
{
|
|
return ( FrameworkElement )GetValue( EditorProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( EditorProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnEditorChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
PropertyItemBase propertyItem = o as PropertyItemBase;
|
|
if( propertyItem != null )
|
|
propertyItem.OnEditorChanged( ( FrameworkElement )e.OldValue, ( FrameworkElement )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnEditorChanged( FrameworkElement oldValue, FrameworkElement newValue )
|
|
{
|
|
}
|
|
|
|
#endregion //Editor
|
|
|
|
#region IsExpanded
|
|
|
|
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register( "IsExpanded", typeof( bool ), typeof( PropertyItemBase ), new UIPropertyMetadata( false, OnIsExpandedChanged ) );
|
|
public bool IsExpanded
|
|
{
|
|
get
|
|
{
|
|
return ( bool )GetValue( IsExpandedProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( IsExpandedProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnIsExpandedChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
PropertyItemBase propertyItem = o as PropertyItemBase;
|
|
if( propertyItem != null )
|
|
propertyItem.OnIsExpandedChanged( ( bool )e.OldValue, ( bool )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnIsExpandedChanged( bool oldValue, bool newValue )
|
|
{
|
|
}
|
|
|
|
#endregion IsExpanded
|
|
|
|
#region IsExpandable
|
|
|
|
public static readonly DependencyProperty IsExpandableProperty =
|
|
DependencyProperty.Register( "IsExpandable", typeof( bool ), typeof( PropertyItemBase ), new UIPropertyMetadata( false ) );
|
|
|
|
public bool IsExpandable
|
|
{
|
|
get { return ( bool )GetValue( IsExpandableProperty ); }
|
|
set { SetValue( IsExpandableProperty, value ); }
|
|
}
|
|
|
|
#endregion //IsExpandable
|
|
|
|
#region IsSelected
|
|
|
|
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( "IsSelected", typeof( bool ), typeof( PropertyItemBase ), new UIPropertyMetadata( false, OnIsSelectedChanged ) );
|
|
public bool IsSelected
|
|
{
|
|
get
|
|
{
|
|
return ( bool )GetValue( IsSelectedProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( IsSelectedProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnIsSelectedChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
PropertyItemBase propertyItem = o as PropertyItemBase;
|
|
if( propertyItem != null )
|
|
propertyItem.OnIsSelectedChanged( ( bool )e.OldValue, ( bool )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnIsSelectedChanged( bool oldValue, bool newValue )
|
|
{
|
|
this.RaiseItemSelectionChangedEvent();
|
|
}
|
|
|
|
#endregion //IsSelected
|
|
|
|
#region ParentElement
|
|
/// <summary>
|
|
/// Gets the parent property grid element of this property.
|
|
/// A PropertyItemBase instance if this is a sub-element,
|
|
/// or the PropertyGrid itself if this is a first-level property.
|
|
/// </summary>
|
|
public FrameworkElement ParentElement
|
|
{
|
|
get { return this.ParentNode as FrameworkElement; }
|
|
}
|
|
#endregion
|
|
|
|
#region ParentNode
|
|
|
|
internal IPropertyContainer ParentNode
|
|
{
|
|
get
|
|
{
|
|
return _parentNode;
|
|
}
|
|
set
|
|
{
|
|
_parentNode = value;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region ValueContainer
|
|
|
|
internal ContentControl ValueContainer
|
|
{
|
|
get
|
|
{
|
|
return _valueContainer;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Level
|
|
|
|
public int Level
|
|
{
|
|
get;
|
|
internal set;
|
|
}
|
|
|
|
#endregion //Level
|
|
|
|
#region Properties
|
|
|
|
public IList Properties
|
|
{
|
|
get
|
|
{
|
|
return _containerHelper.Properties;
|
|
}
|
|
}
|
|
|
|
#endregion //Properties
|
|
|
|
#region PropertyContainerStyle
|
|
/// <summary>
|
|
/// Get the PropertyContainerStyle for sub items of this property.
|
|
/// It return the value defined on PropertyGrid.PropertyContainerStyle.
|
|
/// </summary>
|
|
public Style PropertyContainerStyle
|
|
{
|
|
get
|
|
{
|
|
return ( ParentNode != null )
|
|
? ParentNode.PropertyContainerStyle
|
|
: null;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region ContainerHelper
|
|
|
|
internal ContainerHelperBase ContainerHelper
|
|
{
|
|
get
|
|
{
|
|
return _containerHelper;
|
|
}
|
|
set
|
|
{
|
|
if( value == null )
|
|
throw new ArgumentNullException( "value" );
|
|
|
|
_containerHelper = value;
|
|
// Properties property relies on the "Properties" property of the helper
|
|
// class. Raise a property-changed event.
|
|
this.RaisePropertyChanged( () => this.Properties );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WillRefreshPropertyGrid
|
|
|
|
public static readonly DependencyProperty WillRefreshPropertyGridProperty =
|
|
DependencyProperty.Register( "WillRefreshPropertyGrid", typeof( bool ), typeof( PropertyItemBase ), new UIPropertyMetadata( false ) );
|
|
|
|
public bool WillRefreshPropertyGrid
|
|
{
|
|
get
|
|
{
|
|
return ( bool )GetValue( WillRefreshPropertyGridProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( WillRefreshPropertyGridProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion //WillRefreshPropertyGrid
|
|
|
|
#endregion //Properties
|
|
|
|
#region Events
|
|
|
|
#region ItemSelectionChanged
|
|
|
|
internal static readonly RoutedEvent ItemSelectionChangedEvent = EventManager.RegisterRoutedEvent(
|
|
"ItemSelectionChangedEvent", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( PropertyItemBase ) );
|
|
|
|
private void RaiseItemSelectionChangedEvent()
|
|
{
|
|
RaiseEvent( new RoutedEventArgs( PropertyItemBase.ItemSelectionChangedEvent ) );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PropertyChanged event
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
internal void RaisePropertyChanged<TMember>( Expression<Func<TMember>> propertyExpression )
|
|
{
|
|
this.Notify( this.PropertyChanged, propertyExpression );
|
|
}
|
|
internal void RaisePropertyChanged( string name )
|
|
{
|
|
this.Notify( this.PropertyChanged, name );
|
|
}
|
|
#endregion
|
|
|
|
#endregion //Events
|
|
|
|
#region Constructors
|
|
|
|
static PropertyItemBase()
|
|
{
|
|
DefaultStyleKeyProperty.OverrideMetadata( typeof( PropertyItemBase ), new FrameworkPropertyMetadata( typeof( PropertyItemBase ) ) );
|
|
}
|
|
|
|
internal PropertyItemBase()
|
|
{
|
|
_containerHelper = new ObjectContainerHelper( this, null );
|
|
this.GotFocus += new RoutedEventHandler( PropertyItemBase_GotFocus );
|
|
AddHandler( PropertyItemsControl.PreparePropertyItemEvent, new PropertyItemEventHandler( OnPreparePropertyItemInternal ) );
|
|
AddHandler( PropertyItemsControl.ClearPropertyItemEvent, new PropertyItemEventHandler( OnClearPropertyItemInternal ) );
|
|
}
|
|
|
|
#endregion //Constructors
|
|
|
|
#region Event Handlers
|
|
|
|
private void OnPreparePropertyItemInternal( object sender, PropertyItemEventArgs args )
|
|
{
|
|
// This is the callback of the PreparePropertyItem comming from the template PropertyItemControl.
|
|
args.PropertyItem.Level = this.Level + 1;
|
|
_containerHelper.PrepareChildrenPropertyItem( args.PropertyItem, args.Item );
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnClearPropertyItemInternal( object sender, PropertyItemEventArgs args )
|
|
{
|
|
_containerHelper.ClearChildrenPropertyItem( args.PropertyItem, args.Item );
|
|
// This is the callback of the PreparePropertyItem comming from the template PropertyItemControl.
|
|
args.PropertyItem.Level = 0;
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
#endregion //Event Handlers
|
|
|
|
#region Methods
|
|
|
|
public override void OnApplyTemplate()
|
|
{
|
|
base.OnApplyTemplate();
|
|
_containerHelper.ChildrenItemsControl = GetTemplateChild( PropertyGrid.PART_PropertyItemsControl ) as PropertyItemsControl;
|
|
_valueContainer = GetTemplateChild( PropertyItemBase.PART_ValueContainer ) as ContentControl;
|
|
}
|
|
|
|
protected override void OnMouseDown( MouseButtonEventArgs e )
|
|
{
|
|
IsSelected = true;
|
|
if( !this.IsKeyboardFocusWithin )
|
|
{
|
|
this.Focus();
|
|
}
|
|
// Handle the event; otherwise, the possible
|
|
// parent property item will select itself too.
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void PropertyItemBase_GotFocus( object sender, RoutedEventArgs e )
|
|
{
|
|
IsSelected = true;
|
|
// Handle the event; otherwise, the possible
|
|
// parent property item will select itself too.
|
|
e.Handled = true;
|
|
}
|
|
|
|
protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e )
|
|
{
|
|
base.OnPropertyChanged( e );
|
|
|
|
// First check that the raised property is actually a real CLR property.
|
|
// This could be something else like an Attached DP.
|
|
if( ReflectionHelper.IsPublicInstanceProperty( GetType(), e.Property.Name ) )
|
|
{
|
|
this.RaisePropertyChanged( e.Property.Name );
|
|
}
|
|
}
|
|
|
|
#endregion //Methods
|
|
|
|
#region IPropertyContainer Members
|
|
|
|
|
|
|
|
|
|
|
|
Style IPropertyContainer.PropertyContainerStyle
|
|
{
|
|
get { return this.PropertyContainerStyle; }
|
|
}
|
|
|
|
EditorDefinitionCollection IPropertyContainer.EditorDefinitions
|
|
{
|
|
get
|
|
{
|
|
return (this.ParentNode != null) ? this.ParentNode.EditorDefinitions : null;
|
|
}
|
|
}
|
|
|
|
PropertyDefinitionCollection IPropertyContainer.PropertyDefinitions
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
ContainerHelperBase IPropertyContainer.ContainerHelper
|
|
{
|
|
get
|
|
{
|
|
return this.ContainerHelper;
|
|
}
|
|
}
|
|
|
|
bool IPropertyContainer.IsCategorized
|
|
{
|
|
get
|
|
{
|
|
return _isPropertyGridCategorized;
|
|
}
|
|
}
|
|
|
|
bool IPropertyContainer.IsSortedAlphabetically
|
|
{
|
|
get
|
|
{
|
|
return _isSortedAlphabetically;
|
|
}
|
|
}
|
|
|
|
bool IPropertyContainer.AutoGenerateProperties
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
bool IPropertyContainer.HideInheritedProperties
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
FilterInfo IPropertyContainer.FilterInfo
|
|
{
|
|
get { return new FilterInfo(); }
|
|
}
|
|
|
|
bool? IPropertyContainer.IsPropertyVisible( PropertyDescriptor pd )
|
|
{
|
|
if( _parentNode != null )
|
|
{
|
|
return _parentNode.IsPropertyVisible( pd );
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|
|
|