using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup.Primitives;
using Microsoft.Windows.Controls.PropertyGrid.Commands;
using Microsoft.Windows.Controls.PropertyGrid.Attributes;
namespace Microsoft.Windows.Controls.PropertyGrid
{
public class PropertyItem : Control
{
#region Members
private DependencyPropertyDescriptor _dpDescriptor;
private MarkupObject _markupObject;
#endregion //Members
#region Properties
public string BindingPath { get; private set; }
#region Category
public static readonly DependencyProperty CategoryProperty = DependencyProperty.Register("Category", typeof(string), typeof(PropertyItem), new UIPropertyMetadata(string.Empty));
public string Category
{
get { return (string)GetValue(CategoryProperty); }
set { SetValue(CategoryProperty, value); }
}
#endregion //Category
#region Description
public string Description
{
get { return PropertyDescriptor.Description; }
}
#endregion //Description
#region DisplayName
public static readonly DependencyProperty DisplayNameProperty = DependencyProperty.Register("DisplayName", typeof(string), typeof(PropertyItem), 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(PropertyItem), new UIPropertyMetadata(null, OnEditorChanged));
public FrameworkElement Editor
{
get { return (FrameworkElement)GetValue(EditorProperty); }
set { SetValue(EditorProperty, value); }
}
private static void OnEditorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PropertyItem propertyItem = o as PropertyItem;
if (propertyItem != null)
propertyItem.OnEditorChanged((FrameworkElement)e.OldValue, (FrameworkElement)e.NewValue);
}
protected virtual void OnEditorChanged(FrameworkElement oldValue, FrameworkElement newValue)
{
if (oldValue != null)
oldValue.DataContext = null;
if (newValue != null)
newValue.DataContext = this;
}
#endregion //Editor
#region Instance
private object _instance;
public object Instance
{
get { return _instance; }
private set
{
_instance = value;
_markupObject = MarkupWriter.GetMarkupObjectFor(_instance);
}
}
#endregion //Instance
#region IsDataBound
///
/// Gets if the property is data bound
///
public bool IsDataBound
{
get
{
var dependencyObject = Instance as DependencyObject;
if (dependencyObject != null && _dpDescriptor != null)
return BindingOperations.GetBindingExpressionBase(dependencyObject, _dpDescriptor.DependencyProperty) != null;
return false;
}
}
#endregion //IsDataBound
#region IsDynamicResource
public bool IsDynamicResource
{
get
{
var markupProperty = _markupObject.Properties.Where(p => p.Name == PropertyDescriptor.Name).FirstOrDefault();
if (markupProperty != null)
return markupProperty.Value is DynamicResourceExtension;
return false;
}
}
#endregion //IsDynamicResource
#region IsExpanded
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(PropertyItem), new UIPropertyMetadata(false, OnIsExpandedChanged));
public bool IsExpanded
{
get { return (bool)GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
private static void OnIsExpandedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PropertyItem propertyItem = o as PropertyItem;
if (propertyItem != null)
propertyItem.OnIsExpandedChanged((bool)e.OldValue, (bool)e.NewValue);
}
protected virtual void OnIsExpandedChanged(bool oldValue, bool newValue)
{
if (newValue && (Properties == null || Properties.Count == 0))
{
GetChildProperties();
}
}
#endregion IsExpanded
#region HasChildProperties
public static readonly DependencyProperty HasChildPropertiesProperty = DependencyProperty.Register("HasChildProperties", typeof(bool), typeof(PropertyItem), new UIPropertyMetadata(false));
public bool HasChildProperties
{
get { return (bool)GetValue(HasChildPropertiesProperty); }
set { SetValue(HasChildPropertiesProperty, value); }
}
#endregion HasChildProperties
#region HasResourceApplied
public bool HasResourceApplied
{
//TODO: need to find a better way to determine if a StaticResource has been applied to any property not just a style
get
{
var markupProperty = _markupObject.Properties.Where(p => p.Name == PropertyDescriptor.Name).FirstOrDefault();
if (markupProperty != null)
return markupProperty.Value is Style;
return false;
}
}
#endregion //HasResourceApplied
public bool IsReadOnly { get; private set; }
#region IsSelected
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(PropertyItem), new UIPropertyMetadata(false, OnIsSelectedChanged));
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
private static void OnIsSelectedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PropertyItem propertyItem = o as PropertyItem;
if (propertyItem != null)
propertyItem.OnIsSelectedChanged((bool)e.OldValue, (bool)e.NewValue);
}
protected virtual void OnIsSelectedChanged(bool oldValue, bool newValue)
{
if (newValue)
PropertyGrid.SelectedProperty = this;
}
#endregion //IsSelected
#region Level
public static readonly DependencyProperty LevelProperty = DependencyProperty.Register("Level", typeof(int), typeof(PropertyItem), new UIPropertyMetadata(0));
public int Level
{
get { return (int)GetValue(LevelProperty); }
set { SetValue(LevelProperty, value); }
}
#endregion //Level
#region Properties
public static readonly DependencyProperty PropertiesProperty = DependencyProperty.Register("Properties", typeof(PropertyItemCollection), typeof(PropertyItem), new UIPropertyMetadata(null));
public PropertyItemCollection Properties
{
get { return (PropertyItemCollection)GetValue(PropertiesProperty); }
set { SetValue(PropertiesProperty, value); }
}
#endregion //Properties
#region PropertyDescriptor
private PropertyDescriptor _propertyDescriptor;
public PropertyDescriptor PropertyDescriptor
{
get
{
return _propertyDescriptor;
}
private set
{
_propertyDescriptor = value;
_dpDescriptor = DependencyPropertyDescriptor.FromProperty(_propertyDescriptor);
}
}
#endregion //PropertyDescriptor
public PropertyGrid PropertyGrid { get; private set; }
#region PropertyType
public Type PropertyType
{
get { return PropertyDescriptor.PropertyType; }
}
#endregion //PropertyType
public ICommand ResetValueCommand { get; private set; }
#region Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(PropertyItem), new UIPropertyMetadata(null, OnValueChanged));
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PropertyItem propertyItem = o as PropertyItem;
if (propertyItem != null)
propertyItem.OnValueChanged((object)e.OldValue, (object)e.NewValue);
}
protected virtual void OnValueChanged(object oldValue, object newValue)
{
// TODO: Add your property changed side-effects. Descendants can override as well.
}
#endregion //Value
#region ValueSource
///
/// Gets the value source.
///
public BaseValueSource ValueSource
{
get
{
var dependencyObject = Instance as DependencyObject;
if (_dpDescriptor != null && dependencyObject != null)
return DependencyPropertyHelper.GetValueSource(dependencyObject, _dpDescriptor.DependencyProperty).BaseValueSource;
return BaseValueSource.Unknown;
}
}
#endregion //ValueSource
#endregion //Properties
#region Constructors
static PropertyItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PropertyItem), new FrameworkPropertyMetadata(typeof(PropertyItem)));
}
public PropertyItem(object instance, PropertyDescriptor property, PropertyGrid propertyGrid, string bindingPath)
{
PropertyDescriptor = property;
PropertyGrid = propertyGrid;
Instance = instance;
BindingPath = bindingPath;
SetPropertyDescriptorProperties();
ResolveExpandableObject();
CommandBindings.Add(new CommandBinding(PropertyItemCommands.ResetValue, ExecuteResetValueCommand, CanExecuteResetValueCommand));
AddHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(PropertyItem_PreviewMouseDown), true);
}
#endregion //Constructors
#region Event Handlers
void PropertyItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
IsSelected = true;
}
#endregion //Event Handlers
#region Commands
private void ExecuteResetValueCommand(object sender, ExecutedRoutedEventArgs e)
{
if (PropertyDescriptor.CanResetValue(Instance))
PropertyDescriptor.ResetValue(Instance);
//TODO: notify UI that the ValueSource may have changed to update the icon
}
private void CanExecuteResetValueCommand(object sender, CanExecuteRoutedEventArgs e)
{
bool canExecute = false;
if (PropertyDescriptor.CanResetValue(Instance) && !PropertyDescriptor.IsReadOnly)
{
canExecute = true;
}
e.CanExecute = canExecute;
}
#endregion //Commands
#region Methods
private void GetChildProperties()
{
if (Value == null)
return;
var propertyItems = new List();
try
{
PropertyDescriptorCollection descriptors = PropertyGridUtilities.GetPropertyDescriptors(Value);
foreach (PropertyDescriptor descriptor in descriptors)
{
if (descriptor.IsBrowsable)
propertyItems.Add(PropertyGridUtilities.CreatePropertyItem(descriptor, Instance, PropertyGrid, String.Format("{0}.{1}", BindingPath, descriptor.Name), Level + 1));
}
}
catch (Exception ex)
{
//TODO: handle this some how
}
Properties = PropertyGridUtilities.GetAlphabetizedProperties(propertyItems);
}
private void ResolveExpandableObject()
{
var attribute = PropertyGridUtilities.GetAttribute(PropertyDescriptor);
if (attribute != null)
{
HasChildProperties = true;
IsReadOnly = true;
}
}
private void SetPropertyDescriptorProperties()
{
Name = PropertyDescriptor.Name;
DisplayName = PropertyDescriptor.DisplayName;
Category = PropertyDescriptor.Category;
IsReadOnly = PropertyDescriptor.IsReadOnly;
}
#endregion //Methods
}
}