Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3285 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
25 changed files with 16 additions and 2055 deletions
@ -1,110 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Windows.Data; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Dom; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.AddIn |
|
||||||
{ |
|
||||||
public class ChooseClass : INotifyPropertyChanged |
|
||||||
{ |
|
||||||
public ChooseClass(IProjectContent projectContent) |
|
||||||
{ |
|
||||||
this.projectContent = projectContent; |
|
||||||
|
|
||||||
AddClassesRecursive(""); |
|
||||||
|
|
||||||
projectClasses.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); |
|
||||||
|
|
||||||
classes = new ListCollectionView(projectClasses); |
|
||||||
classes.Filter = FilterPredicate; |
|
||||||
} |
|
||||||
|
|
||||||
IProjectContent projectContent; |
|
||||||
List<IClass> projectClasses = new List<IClass>(); |
|
||||||
|
|
||||||
void AddClassesRecursive(string ns) |
|
||||||
{ |
|
||||||
foreach (var item in projectContent.GetNamespaceContents(ns)) { |
|
||||||
if (item is string) { |
|
||||||
AddClassesRecursive(ns.Length == 0 ? item.ToString() : ns + "." + item); |
|
||||||
} else if (item is IClass) { |
|
||||||
IClass c = item as IClass; |
|
||||||
if (c.IsPartial) { |
|
||||||
if (projectClasses.Contains(c)) continue; |
|
||||||
} |
|
||||||
if (c.ClassType == ClassType.Class && c.IsPublic) { |
|
||||||
projectClasses.Add(c); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ListCollectionView classes; |
|
||||||
|
|
||||||
public ICollectionView Classes { |
|
||||||
get { return classes; } |
|
||||||
} |
|
||||||
|
|
||||||
string filter; |
|
||||||
|
|
||||||
public string Filter { |
|
||||||
get { |
|
||||||
return filter; |
|
||||||
} |
|
||||||
set { |
|
||||||
filter = value; |
|
||||||
Classes.Refresh(); |
|
||||||
RaisePropertyChanged("Filter"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool showSystemClasses; |
|
||||||
|
|
||||||
public bool ShowSystemClasses { |
|
||||||
get { |
|
||||||
return showSystemClasses; |
|
||||||
} |
|
||||||
set { |
|
||||||
showSystemClasses = value; |
|
||||||
Classes.Refresh(); |
|
||||||
RaisePropertyChanged("ShowSystemClasses"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IClass CurrentClass { |
|
||||||
get { return Classes.CurrentItem as IClass; } |
|
||||||
} |
|
||||||
|
|
||||||
bool FilterPredicate(object item) |
|
||||||
{ |
|
||||||
IClass c = item as IClass; |
|
||||||
if (!ShowSystemClasses) { |
|
||||||
if (c.Namespace.StartsWith("System") || c.Namespace.StartsWith("Microsoft")) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
return Match(c.Name, Filter); |
|
||||||
} |
|
||||||
|
|
||||||
static bool Match(string className, string filter) |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(filter)) |
|
||||||
return true; |
|
||||||
else |
|
||||||
return className.StartsWith(filter, StringComparison.InvariantCultureIgnoreCase); |
|
||||||
} |
|
||||||
|
|
||||||
#region INotifyPropertyChanged Members
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged; |
|
||||||
|
|
||||||
void RaisePropertyChanged(string name) |
|
||||||
{ |
|
||||||
if (PropertyChanged != null) { |
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(name)); |
|
||||||
} |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
} |
|
||||||
} |
|
@ -1,69 +0,0 @@ |
|||||||
<Window x:Class="ICSharpCode.WpfDesign.AddIn.ChooseClassDialog" |
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|
||||||
xmlns:sd="clr-namespace:ICSharpCode.WpfDesign.AddIn" |
|
||||||
Background="{x:Static SystemColors.ControlBrush}" |
|
||||||
SnapsToDevicePixels="True" |
|
||||||
WindowStartupLocation="CenterScreen" |
|
||||||
ResizeMode="CanResizeWithGrip" |
|
||||||
Title="Choose Class" |
|
||||||
Height="438" |
|
||||||
Width="488"> |
|
||||||
|
|
||||||
<Grid> |
|
||||||
<TextBlock Text="Starts with:" |
|
||||||
HorizontalAlignment="Left" |
|
||||||
Margin="12,12,0,0" |
|
||||||
VerticalAlignment="Top" |
|
||||||
Height="13" |
|
||||||
Width="55" /> |
|
||||||
<TextBox x:Name="uxFilter" |
|
||||||
Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}" |
|
||||||
Height="23" |
|
||||||
Margin="12,31,12,0" |
|
||||||
VerticalAlignment="Top" /> |
|
||||||
|
|
||||||
<sd:ClassListBox x:Name="uxList" |
|
||||||
Margin="12,60,12,78" |
|
||||||
ItemsSource="{Binding Classes}" |
|
||||||
IsSynchronizedWithCurrentItem="True" |
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden" |
|
||||||
> |
|
||||||
<ListBox.ItemTemplate> |
|
||||||
<DataTemplate> |
|
||||||
<StackPanel Orientation="Horizontal"> |
|
||||||
<Image Source="{sd:GetBitmap Icons.16x16.Class}" |
|
||||||
Stretch="None" /> |
|
||||||
<TextBlock Margin="5 0 0 0" |
|
||||||
Text="{Binding Converter={x:Static sd:ClassNameConverter.Instance}}" |
|
||||||
VerticalAlignment="Center"/> |
|
||||||
</StackPanel> |
|
||||||
</DataTemplate> |
|
||||||
</ListBox.ItemTemplate> |
|
||||||
</sd:ClassListBox> |
|
||||||
|
|
||||||
<CheckBox Content="Show System Classes" |
|
||||||
IsChecked="{Binding ShowSystemClasses}" |
|
||||||
Height="16" |
|
||||||
HorizontalAlignment="Left" |
|
||||||
Margin="12,0,0,56" |
|
||||||
VerticalAlignment="Bottom" |
|
||||||
Width="120" /> |
|
||||||
<Button x:Name="uxOk" |
|
||||||
Content="OK" |
|
||||||
Height="23" |
|
||||||
Margin="0,0,93,12" |
|
||||||
VerticalAlignment="Bottom" |
|
||||||
HorizontalAlignment="Right" |
|
||||||
Width="75" |
|
||||||
IsDefault="True" |
|
||||||
IsEnabled="{Binding SelectedItem, ElementName=uxList, Converter={x:Static sd:NullToBoolConverter.Instance}}"/> |
|
||||||
<Button Content="Cancel" |
|
||||||
Height="23" |
|
||||||
HorizontalAlignment="Right" |
|
||||||
Margin="0,0,12,12" |
|
||||||
VerticalAlignment="Bottom" |
|
||||||
Width="75" |
|
||||||
IsCancel="True" /> |
|
||||||
</Grid> |
|
||||||
</Window> |
|
@ -1,114 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections.Specialized; |
|
||||||
using System.Globalization; |
|
||||||
using System.Reflection; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Windows.Controls.Primitives; |
|
||||||
using System.Windows.Data; |
|
||||||
using System.Windows.Input; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Dom; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.AddIn |
|
||||||
{ |
|
||||||
public partial class ChooseClassDialog |
|
||||||
{ |
|
||||||
public ChooseClassDialog(ChooseClass core) |
|
||||||
{ |
|
||||||
DataContext = core; |
|
||||||
InitializeComponent(); |
|
||||||
|
|
||||||
uxFilter.Focus(); |
|
||||||
uxList.MouseDoubleClick += uxList_MouseDoubleClick; |
|
||||||
uxOk.Click += delegate { Ok(); }; |
|
||||||
|
|
||||||
AddHandler(Keyboard.GotKeyboardFocusEvent, |
|
||||||
new KeyboardFocusChangedEventHandler( |
|
||||||
(sender, e) => uxList.SetValue(IsSelectionActivePropertyKey, true) |
|
||||||
), |
|
||||||
true); |
|
||||||
} |
|
||||||
|
|
||||||
//HACK: listbox is always highlighted
|
|
||||||
public static DependencyPropertyKey IsSelectionActivePropertyKey = |
|
||||||
(DependencyPropertyKey)typeof(Selector).GetField("IsSelectionActivePropertyKey", |
|
||||||
BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); |
|
||||||
|
|
||||||
protected override void OnPreviewKeyDown(KeyEventArgs e) |
|
||||||
{ |
|
||||||
if (e.Key == Key.Enter) { |
|
||||||
Ok(); |
|
||||||
e.Handled = true; |
|
||||||
} else if (e.Key == Key.Up) { |
|
||||||
uxList.SelectedIndex = Math.Max(0, uxList.SelectedIndex - 1); |
|
||||||
e.Handled = true; |
|
||||||
} else if (e.Key == Key.Down) { |
|
||||||
uxList.SelectedIndex++; |
|
||||||
e.Handled = true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void uxList_MouseDoubleClick(object sender, MouseButtonEventArgs e) |
|
||||||
{ |
|
||||||
var f = e.OriginalSource as FrameworkElement; |
|
||||||
if (f != null && f.DataContext is IClass) { |
|
||||||
Ok(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void Ok() |
|
||||||
{ |
|
||||||
DialogResult = true; |
|
||||||
Close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class ClassListBox : ListBox |
|
||||||
{ |
|
||||||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
base.OnItemsChanged(e); |
|
||||||
SelectedIndex = 0; |
|
||||||
ScrollIntoView(SelectedItem); |
|
||||||
} |
|
||||||
|
|
||||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
base.OnSelectionChanged(e); |
|
||||||
ScrollIntoView(SelectedItem); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public class ClassNameConverter : IValueConverter |
|
||||||
{ |
|
||||||
public static ClassNameConverter Instance = new ClassNameConverter(); |
|
||||||
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
|
||||||
{ |
|
||||||
var c = value as IClass; |
|
||||||
if (c == null) return value; |
|
||||||
return c.Name + " (" + c.Namespace + ")"; |
|
||||||
} |
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
|
||||||
{ |
|
||||||
throw new NotImplementedException(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public class NullToBoolConverter : IValueConverter |
|
||||||
{ |
|
||||||
public static NullToBoolConverter Instance = new NullToBoolConverter(); |
|
||||||
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
|
||||||
{ |
|
||||||
return value == null ? false : true; |
|
||||||
} |
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
|
||||||
{ |
|
||||||
throw new NotImplementedException(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Dom; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.AddIn |
|
||||||
{ |
|
||||||
public class ChooseClassService |
|
||||||
{ |
|
||||||
public IClass ChooseClass() |
|
||||||
{ |
|
||||||
var core = new ChooseClass(ParserService.CurrentProjectContent); |
|
||||||
var window = new ChooseClassDialog(core); |
|
||||||
|
|
||||||
if (window.ShowDialog().Value) { |
|
||||||
return core.CurrentClass; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Data; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Windows.Documents; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Type editor used to edit bool properties.
|
|
||||||
/// </summary>
|
|
||||||
sealed class BooleanEditor : CheckBox |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Creates a new BooleanEditor instance.
|
|
||||||
/// </summary>
|
|
||||||
public BooleanEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
SetBinding(IsCheckedProperty, PropertyEditorBindingHelper.CreateBinding(this, property)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision: 2667$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// wraps a DesignItemDataProperty (with IsEvent=true) for the property editor/grid.
|
|
||||||
/// </summary>
|
|
||||||
sealed class DesignItemDataEvent : DesignItemDataMember, IPropertyEditorDataEvent |
|
||||||
{ |
|
||||||
internal DesignItemDataEvent(DesignItemDataSource ownerDataSource, DesignItemProperty property) |
|
||||||
: base(ownerDataSource, property) |
|
||||||
{ |
|
||||||
Debug.Assert(property.IsEvent); |
|
||||||
} |
|
||||||
|
|
||||||
public event EventHandler HandlerNameChanged { |
|
||||||
add { property.ValueChanged += value; } |
|
||||||
remove { property.ValueChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
public string HandlerName { |
|
||||||
get { |
|
||||||
return (string)property.ValueOnInstance; |
|
||||||
} |
|
||||||
set { |
|
||||||
if (string.IsNullOrEmpty(value)) |
|
||||||
property.Reset(); |
|
||||||
else |
|
||||||
property.SetValue(value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void GoToHandler() |
|
||||||
{ |
|
||||||
IEventHandlerService ehs = ownerDataSource.Services.GetService<IEventHandlerService>(); |
|
||||||
if (ehs != null) { |
|
||||||
ehs.CreateEventHandler(ownerDataSource.DesignItem, property); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,61 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// wraps a DesignItemDataProperty for the property editor/grid.
|
|
||||||
/// </summary>
|
|
||||||
class DesignItemDataMember : IPropertyEditorDataMember |
|
||||||
{ |
|
||||||
protected readonly DesignItemDataSource ownerDataSource; |
|
||||||
protected readonly DesignItemProperty property; |
|
||||||
|
|
||||||
protected DesignItemDataMember(DesignItemDataSource ownerDataSource, DesignItemProperty property) |
|
||||||
{ |
|
||||||
Debug.Assert(ownerDataSource != null); |
|
||||||
Debug.Assert(property != null); |
|
||||||
|
|
||||||
this.ownerDataSource = ownerDataSource; |
|
||||||
this.property = property; |
|
||||||
} |
|
||||||
|
|
||||||
public IPropertyEditorDataSource OwnerDataSource { |
|
||||||
get { return ownerDataSource; } |
|
||||||
} |
|
||||||
|
|
||||||
public string Name { |
|
||||||
get { return property.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
public object GetDescription() |
|
||||||
{ |
|
||||||
IPropertyDescriptionService p = ownerDataSource.DesignItem.Services.GetService<IPropertyDescriptionService>(); |
|
||||||
if (p != null) |
|
||||||
return p.GetDescription(property); |
|
||||||
else |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type that declares the property.
|
|
||||||
/// </summary>
|
|
||||||
public Type DeclaringType { |
|
||||||
get { return property.DeclaringType; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the property value.
|
|
||||||
/// </summary>
|
|
||||||
public Type ReturnType { |
|
||||||
get { return property.ReturnType; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,96 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// wraps a DesignItemDataProperty (with IsEvent=false) for the property editor/grid.
|
|
||||||
/// </summary>
|
|
||||||
sealed class DesignItemDataProperty : DesignItemDataMember, IPropertyEditorDataProperty |
|
||||||
{ |
|
||||||
internal DesignItemDataProperty(DesignItemDataSource ownerDataSource, DesignItemProperty property) |
|
||||||
: base(ownerDataSource, property) |
|
||||||
{ |
|
||||||
Debug.Assert(!property.IsEvent); |
|
||||||
} |
|
||||||
|
|
||||||
public string Category { |
|
||||||
get { return property.Category; } |
|
||||||
} |
|
||||||
|
|
||||||
public System.ComponentModel.TypeConverter TypeConverter { |
|
||||||
get { return property.TypeConverter; } |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsSet { |
|
||||||
get { |
|
||||||
return property.IsSet; |
|
||||||
} |
|
||||||
set { |
|
||||||
if (value != property.IsSet) { |
|
||||||
if (value) { |
|
||||||
// copy default value to local value
|
|
||||||
property.SetValue(property.ValueOnInstance); |
|
||||||
} else { |
|
||||||
property.Reset(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public event EventHandler IsSetChanged { |
|
||||||
add { property.IsSetChanged += value; } |
|
||||||
remove { property.IsSetChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsAmbiguous { |
|
||||||
get { return false; } |
|
||||||
} |
|
||||||
|
|
||||||
public object Value { |
|
||||||
get { |
|
||||||
return property.ValueOnInstance; |
|
||||||
} |
|
||||||
set { |
|
||||||
property.SetValue(value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public event EventHandler ValueChanged { |
|
||||||
add { property.ValueChanged += value; } |
|
||||||
remove { property.ValueChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
public bool CanUseCustomExpression { |
|
||||||
get { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void SetCustomExpression(string expression) |
|
||||||
{ |
|
||||||
throw new NotImplementedException(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a UIElement that can edit the property value.
|
|
||||||
/// </summary>
|
|
||||||
public UIElement CreateEditor() |
|
||||||
{ |
|
||||||
EditorManager manager = ownerDataSource.Services.GetService<EditorManager>(); |
|
||||||
if (manager != null) { |
|
||||||
return manager.CreateEditor(this); |
|
||||||
} else { |
|
||||||
return new FallbackEditor(this); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,206 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Linq; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Media; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Implements IPropertyEditorDataSource accessing the properties on a DesignItem.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class DesignItemDataSource : IPropertyEditorDataSource |
|
||||||
{ |
|
||||||
readonly DesignItem item; |
|
||||||
readonly List<IPropertyEditorDataProperty> properties = new List<IPropertyEditorDataProperty>(); |
|
||||||
readonly List<IPropertyEditorDataEvent> events = new List<IPropertyEditorDataEvent>(); |
|
||||||
|
|
||||||
#region Available properties
|
|
||||||
// cache properties available for a type - retrieving this list takes ~100ms on my machine, so
|
|
||||||
// we cannot do this for every selected component, but must reuse the list
|
|
||||||
static readonly Dictionary<Type, string[]> availableProperties = new Dictionary<Type, string[]>(); |
|
||||||
|
|
||||||
static string[] GetAvailableProperties(Type forType) |
|
||||||
{ |
|
||||||
Debug.Assert(forType != null); |
|
||||||
string[] result; |
|
||||||
lock (availableProperties) { |
|
||||||
if (availableProperties.TryGetValue(forType, out result)) |
|
||||||
return result; |
|
||||||
} |
|
||||||
List<string> names = new List<string>(); |
|
||||||
foreach (PropertyDescriptor p in TypeDescriptor.GetProperties(forType)) { |
|
||||||
if (!p.IsBrowsable) continue; |
|
||||||
if (p.IsReadOnly) continue; |
|
||||||
if (p.Name.Contains(".")) continue; |
|
||||||
names.Add(p.Name); |
|
||||||
} |
|
||||||
result = names.ToArray(); |
|
||||||
lock (availableProperties) { |
|
||||||
availableProperties[forType] = result; |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Available events
|
|
||||||
// cache events available for a type
|
|
||||||
static readonly Dictionary<Type, string[]> availableEvents = new Dictionary<Type, string[]>(); |
|
||||||
|
|
||||||
static string[] GetAvailableEvents(Type forType) |
|
||||||
{ |
|
||||||
Debug.Assert(forType != null); |
|
||||||
string[] result; |
|
||||||
lock (availableEvents) { |
|
||||||
if (availableEvents.TryGetValue(forType, out result)) |
|
||||||
return result; |
|
||||||
} |
|
||||||
List<string> names = new List<string>(); |
|
||||||
foreach (EventDescriptor p in TypeDescriptor.GetEvents(forType)) { |
|
||||||
if (!p.IsBrowsable) continue; |
|
||||||
if (p.Name.Contains(".")) continue; |
|
||||||
names.Add(p.Name); |
|
||||||
} |
|
||||||
result = names.ToArray(); |
|
||||||
lock (availableEvents) { |
|
||||||
availableEvents[forType] = result; |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new DesignItemDataSource for the specified design item.
|
|
||||||
/// </summary>
|
|
||||||
public DesignItemDataSource(DesignItem item) |
|
||||||
{ |
|
||||||
if (item == null) |
|
||||||
throw new ArgumentNullException("item"); |
|
||||||
this.item = item; |
|
||||||
|
|
||||||
List<DesignItemProperty> designItemProperties = new List<DesignItemProperty>(); |
|
||||||
foreach (string name in GetAvailableProperties(item.ComponentType)) { |
|
||||||
designItemProperties.Add(item.Properties[name]); |
|
||||||
} |
|
||||||
foreach (string name in GetAvailableEvents(item.ComponentType)) { |
|
||||||
designItemProperties.Add(item.Properties[name]); |
|
||||||
} |
|
||||||
designItemProperties.AddRange(item.Properties); |
|
||||||
|
|
||||||
foreach (DesignItemProperty p in designItemProperties.Distinct()) { |
|
||||||
if (p.IsEvent) { |
|
||||||
events.Add(new DesignItemDataEvent(this, p)); |
|
||||||
} else { |
|
||||||
properties.Add(new DesignItemDataProperty(this, p)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a data source for the specified design item.
|
|
||||||
/// This tries to get an existing data source instance (as behavior), or constructs a new
|
|
||||||
/// DesignItemDataSource instance if that fails.
|
|
||||||
/// </summary>
|
|
||||||
public static IPropertyEditorDataSource GetDataSourceForDesignItem(DesignItem item) |
|
||||||
{ |
|
||||||
return item.GetBehavior<IPropertyEditorDataSource>() ?? new DesignItemDataSource(item); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a data source for the specified design item.
|
|
||||||
/// This tries to get an existing data source instance (as behavior), or constructs a new
|
|
||||||
/// DesignItemDataSource instance if that fails.
|
|
||||||
/// </summary>
|
|
||||||
public static IPropertyEditorDataSource GetDataSourceForDesignItems(ICollection<DesignItem> items) |
|
||||||
{ |
|
||||||
IPropertyEditorDataSource[] sources = new IPropertyEditorDataSource[items.Count]; |
|
||||||
DesignContext context = null; |
|
||||||
int i = 0; |
|
||||||
foreach (DesignItem item in items) { |
|
||||||
if (context == null) |
|
||||||
context = item.Context; |
|
||||||
else if (context != item.Context) |
|
||||||
throw new DesignerException("All specified items must use the same design context!"); |
|
||||||
|
|
||||||
sources[i++] = GetDataSourceForDesignItem(item); |
|
||||||
} |
|
||||||
return MultipleSelectionDataSource.CreateDataSource(context != null ? context.Services : null, sources); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the design item for which this DesignItemDataSource was created.
|
|
||||||
/// </summary>
|
|
||||||
public DesignItem DesignItem { |
|
||||||
get { return item; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public string Name { |
|
||||||
get { return item.Name ?? ""; } |
|
||||||
set { item.Name = value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is raised when the name of the design item changes.
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler NameChanged { |
|
||||||
add { item.NameChanged += value; } |
|
||||||
remove { item.NameChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public string Type { |
|
||||||
get { |
|
||||||
return item.ComponentType.Name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public ImageSource Icon { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public ICollection<IPropertyEditorDataProperty> Properties { |
|
||||||
get { return properties.AsReadOnly(); } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public ICollection<IPropertyEditorDataEvent> Events { |
|
||||||
get { return events.AsReadOnly(); } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public bool CanAddAttachedProperties { |
|
||||||
get { |
|
||||||
return item.Component is DependencyObject; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public ServiceContainer Services { |
|
||||||
get { return item.Services; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public Brush CreateThumbnailBrush() |
|
||||||
{ |
|
||||||
if (item.View != null) { |
|
||||||
VisualBrush b = new VisualBrush(item.View); |
|
||||||
b.AutoLayoutContent = false; |
|
||||||
return b; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Reflection; |
|
||||||
using System.Windows; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Manages registered type and property editors.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class EditorManager |
|
||||||
{ |
|
||||||
// property return type => editor type
|
|
||||||
Dictionary<Type, Type> _typeEditors = new Dictionary<Type, Type>(); |
|
||||||
// property full name => editor type
|
|
||||||
Dictionary<string, Type> _propertyEditors = new Dictionary<string, Type>(); |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an editor for the specified property.
|
|
||||||
/// </summary>
|
|
||||||
public UIElement CreateEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
try { |
|
||||||
return (UIElement)Activator.CreateInstance(GetEditorType(property), property); |
|
||||||
} catch (Exception ex) { |
|
||||||
Debug.WriteLine(ex.ToString()); |
|
||||||
throw; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the fallback editor for the specified property.
|
|
||||||
/// </summary>
|
|
||||||
public static UIElement CreateFallbackEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
return (UIElement)Activator.CreateInstance(GetFallbackEditorType(property), property); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the editor that can edit the specified property.
|
|
||||||
/// </summary>
|
|
||||||
public Type GetEditorType(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
if (property == null) |
|
||||||
throw new ArgumentNullException("property"); |
|
||||||
|
|
||||||
Type editorType; |
|
||||||
if (_propertyEditors.TryGetValue(property.DeclaringType.FullName + "." + property.Name, out editorType)) |
|
||||||
return editorType; |
|
||||||
else if (_typeEditors.TryGetValue(property.ReturnType, out editorType)) |
|
||||||
return editorType; |
|
||||||
else |
|
||||||
return GetFallbackEditorType(property); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the fallback editor used for the specified property.
|
|
||||||
/// </summary>
|
|
||||||
public static Type GetFallbackEditorType(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
if (property == null) |
|
||||||
throw new ArgumentNullException("property"); |
|
||||||
|
|
||||||
Type returnType = property.ReturnType; |
|
||||||
if (returnType.IsEnum) { |
|
||||||
return typeof(StandardValuesComboBoxEditor); |
|
||||||
} else if (returnType == typeof(bool)) { |
|
||||||
return typeof(BooleanEditor); |
|
||||||
} else { |
|
||||||
TypeConverter c = property.TypeConverter; |
|
||||||
if (c != null && c.CanConvertFrom(typeof(string)) && c.CanConvertTo(typeof(string))) |
|
||||||
return typeof(TextBoxEditor); |
|
||||||
else |
|
||||||
return typeof(FallbackEditor); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers property editors defined in the specified assembly.
|
|
||||||
/// </summary>
|
|
||||||
public void RegisterAssembly(Assembly assembly) |
|
||||||
{ |
|
||||||
if (assembly == null) |
|
||||||
throw new ArgumentNullException("assembly"); |
|
||||||
|
|
||||||
foreach (Type type in assembly.GetExportedTypes()) { |
|
||||||
foreach (TypeEditorAttribute editorAttribute in type.GetCustomAttributes(typeof(TypeEditorAttribute), false)) { |
|
||||||
CheckValidEditor(type); |
|
||||||
_typeEditors[editorAttribute.SupportedPropertyType] = type; |
|
||||||
} |
|
||||||
foreach (PropertyEditorAttribute editorAttribute in type.GetCustomAttributes(typeof(PropertyEditorAttribute), false)) { |
|
||||||
CheckValidEditor(type); |
|
||||||
string propertyName = editorAttribute.PropertyDeclaringType.FullName + "." + editorAttribute.PropertyName; |
|
||||||
_propertyEditors[propertyName] = type; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static readonly Type[] typeArrayWithPropertyEditorDataProperty = { typeof(IPropertyEditorDataProperty) }; |
|
||||||
|
|
||||||
static void CheckValidEditor(Type type) |
|
||||||
{ |
|
||||||
if (!typeof(UIElement).IsAssignableFrom(type)) { |
|
||||||
throw new DesignerException("Editor types must derive from UIElement!"); |
|
||||||
} |
|
||||||
if (type.GetConstructor(typeArrayWithPropertyEditorDataProperty) == null) { |
|
||||||
throw new DesignerException("Editor types must have a constructor that takes a IPropertyEditorDataProperty as argument!"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,69 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Windows.Documents; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// The type editor used when no other type editor could be found.
|
|
||||||
/// </summary>
|
|
||||||
[TypeEditor(typeof(object))] |
|
||||||
public sealed class FallbackEditor : TextBlock |
|
||||||
{ |
|
||||||
readonly IPropertyEditorDataProperty property; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new FallbackEditor instance for the specified property.
|
|
||||||
/// </summary>
|
|
||||||
public FallbackEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
if (property == null) |
|
||||||
throw new ArgumentNullException("property"); |
|
||||||
|
|
||||||
this.property = property; |
|
||||||
|
|
||||||
this.TextTrimming = TextTrimming.CharacterEllipsis; |
|
||||||
PropertyEditorBindingHelper.AddValueChangedEventHandler(this, property, OnValueChanged); |
|
||||||
OnValueChanged(null, null); |
|
||||||
} |
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] |
|
||||||
void OnValueChanged(object sender, EventArgs e) |
|
||||||
{ |
|
||||||
if (property.IsSet) { |
|
||||||
this.FontWeight = FontWeights.Bold; |
|
||||||
} else { |
|
||||||
this.FontWeight = FontWeights.Regular; |
|
||||||
} |
|
||||||
if (property.IsAmbiguous) { |
|
||||||
this.Text = ""; |
|
||||||
} else { |
|
||||||
object val = property.Value; |
|
||||||
if (val == null) { |
|
||||||
this.Text = "null"; |
|
||||||
this.FontStyle = FontStyles.Italic; |
|
||||||
} else { |
|
||||||
this.FontStyle = FontStyles.Normal; |
|
||||||
try { |
|
||||||
this.Text = val.ToString(); |
|
||||||
} catch (Exception ex) { |
|
||||||
this.FontWeight = FontWeights.Regular; |
|
||||||
Inlines.Clear(); |
|
||||||
Inlines.Add(new Italic(new Run(ex.GetType().Name))); |
|
||||||
Inlines.Add(" "); |
|
||||||
Inlines.Add(ex.Message); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,178 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Windows.Media; |
|
||||||
using System.Windows; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Interface for data sources used by the property editor to display the list of properties.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPropertyEditorDataSource |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets the name of the item. Returns null when the item does not support having a name.
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; set; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is raised whenever the Name property changes value.
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler NameChanged; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the item (for display only).
|
|
||||||
/// </summary>
|
|
||||||
string Type { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the icon of the item (for display only)
|
|
||||||
/// </summary>
|
|
||||||
ImageSource Icon { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of properties.
|
|
||||||
/// </summary>
|
|
||||||
ICollection<IPropertyEditorDataProperty> Properties { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of events.
|
|
||||||
/// </summary>
|
|
||||||
ICollection<IPropertyEditorDataEvent> Events { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets if adding attached properties is supported.
|
|
||||||
/// </summary>
|
|
||||||
bool CanAddAttachedProperties { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the service container attached to this data source.
|
|
||||||
/// </summary>
|
|
||||||
ServiceContainer Services { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a brush used as a preview for the data source.
|
|
||||||
/// </summary>
|
|
||||||
Brush CreateThumbnailBrush(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a property or event inside a <see cref="IPropertyEditorDataSource"/>.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPropertyEditorDataMember |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Gets the data source that own this property.
|
|
||||||
/// </summary>
|
|
||||||
IPropertyEditorDataSource OwnerDataSource { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the property.
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type that declares the property.
|
|
||||||
/// </summary>
|
|
||||||
Type DeclaringType { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the property value / the type of the event delegate.
|
|
||||||
/// </summary>
|
|
||||||
Type ReturnType { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the description of the property. The returned object should be something that
|
|
||||||
/// can be used as Content for a WPF tooltip.
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] |
|
||||||
object GetDescription(); // is not a property because it can create a new instance on every call
|
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a property inside a <see cref="IPropertyEditorDataSource"/>.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPropertyEditorDataProperty : IPropertyEditorDataMember |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Gets the category this property uses.
|
|
||||||
/// </summary>
|
|
||||||
string Category { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type converter used to convert property values to/from string.
|
|
||||||
/// </summary>
|
|
||||||
TypeConverter TypeConverter { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets if the property has been assigned a local value.
|
|
||||||
/// Setting this property to false has the effect of resetting the value, setting it to true
|
|
||||||
/// copies the default value to a local value.
|
|
||||||
/// </summary>
|
|
||||||
bool IsSet { get; set; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is raised when the IsSet property has changed.
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler IsSetChanged; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets if the property value is ambiguous.
|
|
||||||
/// </summary>
|
|
||||||
bool IsAmbiguous { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets the value of the property.
|
|
||||||
/// </summary>
|
|
||||||
object Value { get; set; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is raised when the Value property has changed.
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler ValueChanged; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets if using a custom expression is supported.
|
|
||||||
/// </summary>
|
|
||||||
bool CanUseCustomExpression { get; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a custom expression.
|
|
||||||
/// </summary>
|
|
||||||
void SetCustomExpression(string expression); |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a UIElement that can edit the property value.
|
|
||||||
/// </summary>
|
|
||||||
UIElement CreateEditor(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an event inside a <see cref="IPropertyEditorDataSource"/>.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPropertyEditorDataEvent : IPropertyEditorDataMember |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets the name of the event handler.
|
|
||||||
/// </summary>
|
|
||||||
string HandlerName { get; set; } |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is raised when the HandlerName property has changed.
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler HandlerNameChanged; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Goes to the event handler, creating it when necessary.
|
|
||||||
/// </summary>
|
|
||||||
void GoToHandler(); |
|
||||||
} |
|
||||||
} |
|
@ -1,230 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
sealed class MultipleSelectionDataProperty : IPropertyEditorDataProperty |
|
||||||
{ |
|
||||||
readonly MultipleSelectionDataSource ownerDataSource; |
|
||||||
readonly IPropertyEditorDataProperty[] data; |
|
||||||
|
|
||||||
public MultipleSelectionDataProperty(MultipleSelectionDataSource ownerDataSource, IPropertyEditorDataProperty[] data) |
|
||||||
{ |
|
||||||
Debug.Assert(ownerDataSource != null); |
|
||||||
Debug.Assert(data != null); |
|
||||||
Debug.Assert(data.Length >= 2); |
|
||||||
|
|
||||||
this.ownerDataSource = ownerDataSource; |
|
||||||
this.data = data; |
|
||||||
} |
|
||||||
|
|
||||||
#region IsSet + IsSetChanged
|
|
||||||
EventHandler isSetChangedHandlers; |
|
||||||
bool cachedIsSet; |
|
||||||
|
|
||||||
public event EventHandler IsSetChanged { |
|
||||||
add { |
|
||||||
if (isSetChangedHandlers == null) { |
|
||||||
cachedIsSet = GetIsSetInternal(); |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.IsSetChanged += OnIsSetChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
isSetChangedHandlers += value; |
|
||||||
} |
|
||||||
remove { |
|
||||||
isSetChangedHandlers -= value; |
|
||||||
if (isSetChangedHandlers == null) { |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.IsSetChanged -= OnIsSetChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void OnIsSetChanged(object sender, EventArgs e) |
|
||||||
{ |
|
||||||
bool newIsSet = GetIsSetInternal(); |
|
||||||
if (newIsSet != cachedIsSet) { |
|
||||||
cachedIsSet = newIsSet; |
|
||||||
isSetChangedHandlers(this, e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool GetIsSetInternal() |
|
||||||
{ |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
if (p.IsSet) |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsSet { |
|
||||||
get { |
|
||||||
if (isSetChangedHandlers != null) |
|
||||||
return cachedIsSet; |
|
||||||
else |
|
||||||
return GetIsSetInternal(); |
|
||||||
} |
|
||||||
set { |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.IsSet = value; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Value
|
|
||||||
EventHandler valueChangedHandlers; |
|
||||||
object cachedValue; |
|
||||||
bool cachedIsAmbiguous; |
|
||||||
/// <summary>0 = don't prevent, 1 = prevent, 2 = prevented</summary>
|
|
||||||
byte preventOnValueChanged; |
|
||||||
|
|
||||||
public event EventHandler ValueChanged { |
|
||||||
add { |
|
||||||
if (valueChangedHandlers == null) { |
|
||||||
cachedValue = GetValueInternal(); |
|
||||||
cachedIsAmbiguous = GetIsAmbiguousInternal(); |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.ValueChanged += OnValueChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
valueChangedHandlers += value; |
|
||||||
} |
|
||||||
remove { |
|
||||||
valueChangedHandlers -= value; |
|
||||||
if (valueChangedHandlers == null) { |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.ValueChanged -= OnValueChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void OnValueChanged(object sender, EventArgs e) |
|
||||||
{ |
|
||||||
if (preventOnValueChanged > 0) { |
|
||||||
preventOnValueChanged = 2; |
|
||||||
return; |
|
||||||
} |
|
||||||
cachedValue = GetValueInternal(); |
|
||||||
cachedIsAmbiguous = GetIsAmbiguousInternal(); |
|
||||||
valueChangedHandlers(this, e); |
|
||||||
} |
|
||||||
|
|
||||||
object GetValueInternal() |
|
||||||
{ |
|
||||||
object val = data[0].Value; |
|
||||||
for (int i = 1; i < data.Length; i++) { |
|
||||||
if (!object.Equals(data[i].Value, val)) |
|
||||||
return null; |
|
||||||
} |
|
||||||
return val; |
|
||||||
} |
|
||||||
|
|
||||||
bool GetIsAmbiguousInternal() |
|
||||||
{ |
|
||||||
object val = data[0].Value; |
|
||||||
for (int i = 1; i < data.Length; i++) { |
|
||||||
if (!object.Equals(data[i].Value, val)) |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public object Value { |
|
||||||
get { |
|
||||||
if (valueChangedHandlers != null) |
|
||||||
return cachedValue; |
|
||||||
else |
|
||||||
return GetValueInternal(); |
|
||||||
} |
|
||||||
set { |
|
||||||
preventOnValueChanged = 1; |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.Value = value; |
|
||||||
} |
|
||||||
if (preventOnValueChanged == 2) { |
|
||||||
preventOnValueChanged = 0; |
|
||||||
OnValueChanged(null, EventArgs.Empty); |
|
||||||
} |
|
||||||
preventOnValueChanged = 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsAmbiguous { |
|
||||||
get { |
|
||||||
if (valueChangedHandlers != null) |
|
||||||
return cachedIsAmbiguous; |
|
||||||
else |
|
||||||
return GetIsAmbiguousInternal(); |
|
||||||
} |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
|
|
||||||
public IPropertyEditorDataSource OwnerDataSource { |
|
||||||
get { return ownerDataSource; } |
|
||||||
} |
|
||||||
|
|
||||||
public string Category { |
|
||||||
get { return data[0].Category; } |
|
||||||
} |
|
||||||
|
|
||||||
public string Name { |
|
||||||
get { return data[0].Name; } |
|
||||||
} |
|
||||||
|
|
||||||
public Type ReturnType { |
|
||||||
get { return data[0].ReturnType; } |
|
||||||
} |
|
||||||
|
|
||||||
public Type DeclaringType { |
|
||||||
get { return data[0].DeclaringType; } |
|
||||||
} |
|
||||||
|
|
||||||
public System.ComponentModel.TypeConverter TypeConverter { |
|
||||||
get { return data[0].TypeConverter; } |
|
||||||
} |
|
||||||
|
|
||||||
public object GetDescription() |
|
||||||
{ |
|
||||||
return data[0].GetDescription(); |
|
||||||
} |
|
||||||
|
|
||||||
public bool CanUseCustomExpression { |
|
||||||
get { |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
if (!p.CanUseCustomExpression) |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void SetCustomExpression(string expression) |
|
||||||
{ |
|
||||||
foreach (IPropertyEditorDataProperty p in data) { |
|
||||||
p.SetCustomExpression(expression); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public System.Windows.UIElement CreateEditor() |
|
||||||
{ |
|
||||||
EditorManager manager = ownerDataSource.Services.GetService<EditorManager>(); |
|
||||||
if (manager != null) { |
|
||||||
return manager.CreateEditor(this); |
|
||||||
} else { |
|
||||||
return new FallbackEditor(this); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,144 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Linq; |
|
||||||
using System.Windows.Media; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Implements IPropertyEditorDataSource by combining the information from multiple data sources.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class MultipleSelectionDataSource : IPropertyEditorDataSource |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Creates a data source for a collection of data sources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="services">The service container to use.</param>
|
|
||||||
/// <param name="sources">The collection of data sources.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <c>null</c>, if sources is <c>null</c> or empty.
|
|
||||||
/// <c>sources[0]</c>, if sources.Count == 1.
|
|
||||||
/// A new MultiSelectionDataSource, if sources.Count >= 2.
|
|
||||||
/// </returns>
|
|
||||||
public static IPropertyEditorDataSource CreateDataSource(ServiceContainer services, ICollection<IPropertyEditorDataSource> sources) |
|
||||||
{ |
|
||||||
if (sources == null || sources.Count == 0) { |
|
||||||
return null; |
|
||||||
} else if (sources.Count == 1) { |
|
||||||
foreach (IPropertyEditorDataSource s in sources) { |
|
||||||
return s; |
|
||||||
} |
|
||||||
throw new InvalidOperationException(); |
|
||||||
} else { |
|
||||||
return new MultipleSelectionDataSource(services, sources); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
readonly ServiceContainer services; |
|
||||||
readonly IPropertyEditorDataSource[] data; |
|
||||||
readonly List<IPropertyEditorDataProperty> properties = new List<IPropertyEditorDataProperty>(); |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new MultiSelectionDataSource instance.
|
|
||||||
/// </summary>
|
|
||||||
public MultipleSelectionDataSource(ServiceContainer services, ICollection<IPropertyEditorDataSource> sources) |
|
||||||
{ |
|
||||||
this.services = services; |
|
||||||
if (sources == null) |
|
||||||
throw new ArgumentNullException("sources"); |
|
||||||
data = sources.ToArray(); |
|
||||||
if (data.Length < 2) |
|
||||||
throw new ArgumentException("The collection must have at least 2 items!"); |
|
||||||
|
|
||||||
foreach (IPropertyEditorDataProperty property in data[0].Properties) { |
|
||||||
IPropertyEditorDataProperty[] properties = new IPropertyEditorDataProperty[data.Length]; |
|
||||||
properties[0] = property; |
|
||||||
for (int i = 1; i < data.Length; i++) { |
|
||||||
foreach (IPropertyEditorDataProperty p in data[i].Properties) { |
|
||||||
if (p.Name == property.Name && p.ReturnType == property.ReturnType) { |
|
||||||
properties[i] = p; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (properties[i] == null) { |
|
||||||
properties = null; // could not find the property for all data sources
|
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (properties != null) { |
|
||||||
this.properties.Add(new MultipleSelectionDataProperty(this, properties)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is never raised because Name cannot change.
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler NameChanged { |
|
||||||
add { } remove { } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Always returns null. The setter throws an exception.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { |
|
||||||
get { return null; } |
|
||||||
set { throw new NotSupportedException(); } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the selected objects.
|
|
||||||
/// </summary>
|
|
||||||
public string Type { |
|
||||||
get { return "multiple selection"; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the icon of the selected objects.
|
|
||||||
/// </summary>
|
|
||||||
public System.Windows.Media.ImageSource Icon { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of properties.
|
|
||||||
/// </summary>
|
|
||||||
public ICollection<IPropertyEditorDataProperty> Properties { |
|
||||||
get { return properties.AsReadOnly(); } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets if adding attached properties is supported.
|
|
||||||
/// </summary>
|
|
||||||
public bool CanAddAttachedProperties { |
|
||||||
get { return false; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the service container used by this data source.
|
|
||||||
/// </summary>
|
|
||||||
public ServiceContainer Services { |
|
||||||
get { return services; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public Brush CreateThumbnailBrush() |
|
||||||
{ |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataSource"/></summary>
|
|
||||||
public ICollection<IPropertyEditorDataEvent> Events { |
|
||||||
get { return new IPropertyEditorDataEvent[0]; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Attribute to specify that the decorated class is a editor for the specified property.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)] |
|
||||||
public sealed class PropertyEditorAttribute : Attribute |
|
||||||
{ |
|
||||||
readonly Type propertyDeclaringType; |
|
||||||
readonly string propertyName; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new PropertyEditorAttribute that specifies that the decorated class is a editor
|
|
||||||
/// for the "<paramref name="propertyDeclaringType"/>.<paramref name="propertyName"/>".
|
|
||||||
/// </summary>
|
|
||||||
public PropertyEditorAttribute(Type propertyDeclaringType, string propertyName) |
|
||||||
{ |
|
||||||
if (propertyDeclaringType == null) |
|
||||||
throw new ArgumentNullException("propertyDeclaringType"); |
|
||||||
if (propertyName == null) |
|
||||||
throw new ArgumentNullException("propertyName"); |
|
||||||
this.propertyDeclaringType = propertyDeclaringType; |
|
||||||
this.propertyName = propertyName; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type that declares the property that the decorated editor supports.
|
|
||||||
/// </summary>
|
|
||||||
public Type PropertyDeclaringType { |
|
||||||
get { return propertyDeclaringType; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the property that the decorated editor supports.
|
|
||||||
/// </summary>
|
|
||||||
public string PropertyName { |
|
||||||
get { return propertyName; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,137 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
// Enable additional Debug.WriteLines for Loading/Unloading event handlers
|
|
||||||
//#define PropertyEditorBindingHelperDebugging
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Globalization; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Data; |
|
||||||
using System.ComponentModel; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Provides a static method to create a binding between a dependency property
|
|
||||||
/// and a data property.
|
|
||||||
/// </summary>
|
|
||||||
public static class PropertyEditorBindingHelper |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Registers a value changed event handler for the data property that gets unregistered when the
|
|
||||||
/// editor FrameworkElement is unloaded.
|
|
||||||
/// </summary>
|
|
||||||
public static void AddValueChangedEventHandler(FrameworkElement editor, IPropertyEditorDataProperty dataProperty, EventHandler handler) |
|
||||||
{ |
|
||||||
if (editor == null) |
|
||||||
throw new ArgumentNullException("editor"); |
|
||||||
if (dataProperty == null) |
|
||||||
throw new ArgumentNullException("dataProperty"); |
|
||||||
if (handler == null) |
|
||||||
throw new ArgumentNullException("handler"); |
|
||||||
|
|
||||||
bool isAttached = false; |
|
||||||
|
|
||||||
editor.Loaded += delegate { |
|
||||||
if (!isAttached) { |
|
||||||
isAttached = true; |
|
||||||
dataProperty.ValueChanged += handler; |
|
||||||
} |
|
||||||
}; |
|
||||||
editor.Unloaded += delegate { |
|
||||||
if (isAttached) { |
|
||||||
isAttached = false; |
|
||||||
dataProperty.ValueChanged -= handler; |
|
||||||
} |
|
||||||
}; |
|
||||||
if (editor.IsLoaded) { |
|
||||||
isAttached = true; |
|
||||||
dataProperty.ValueChanged += handler; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Binds editor.property to dataProperty.Value.
|
|
||||||
/// </summary>
|
|
||||||
public static Binding CreateBinding(FrameworkElement editor, IPropertyEditorDataProperty dataProperty) |
|
||||||
{ |
|
||||||
if (editor == null) |
|
||||||
throw new ArgumentNullException("editor"); |
|
||||||
if (dataProperty == null) |
|
||||||
throw new ArgumentNullException("dataProperty"); |
|
||||||
|
|
||||||
#if PropertyEditorBindingHelperDebugging
|
|
||||||
Debug.WriteLine("Create CustomBinding"); |
|
||||||
#endif
|
|
||||||
|
|
||||||
CustomBinding customBinding = new CustomBinding(dataProperty); |
|
||||||
editor.Loaded += customBinding.OnLoaded; |
|
||||||
editor.Unloaded += customBinding.OnUnloaded; |
|
||||||
if (editor.IsLoaded) { |
|
||||||
customBinding.OnLoaded(editor, null); |
|
||||||
} |
|
||||||
|
|
||||||
Binding b = new Binding("BoundValue"); |
|
||||||
b.Source = customBinding; |
|
||||||
b.ConverterCulture = CultureInfo.InvariantCulture; |
|
||||||
return b; |
|
||||||
} |
|
||||||
|
|
||||||
sealed class CustomBinding : INotifyPropertyChanged |
|
||||||
{ |
|
||||||
readonly IPropertyEditorDataProperty dataProperty; |
|
||||||
bool isLoaded; |
|
||||||
|
|
||||||
public CustomBinding(IPropertyEditorDataProperty dataProperty) |
|
||||||
{ |
|
||||||
this.dataProperty = dataProperty; |
|
||||||
} |
|
||||||
|
|
||||||
internal void OnLoaded(object sender, RoutedEventArgs e) |
|
||||||
{ |
|
||||||
#if PropertyEditorBindingHelperDebugging
|
|
||||||
Debug.WriteLine("CustomBinding.OnLoaded (isLoaded=" + isLoaded + ")"); |
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!isLoaded) { |
|
||||||
isLoaded = true; |
|
||||||
dataProperty.ValueChanged += OnValueChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal void OnUnloaded(object sender, RoutedEventArgs e) |
|
||||||
{ |
|
||||||
#if PropertyEditorBindingHelperDebugging
|
|
||||||
Debug.WriteLine("CustomBinding.OnUnloaded (isLoaded=" + isLoaded + ")"); |
|
||||||
#endif
|
|
||||||
|
|
||||||
if (isLoaded) { |
|
||||||
isLoaded = false; |
|
||||||
dataProperty.ValueChanged -= OnValueChanged; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Used by the Binding using Reflection.
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
|
||||||
public object BoundValue { |
|
||||||
get { return dataProperty.Value; } |
|
||||||
set { dataProperty.Value = value; } |
|
||||||
} |
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged; |
|
||||||
|
|
||||||
void OnValueChanged(object sender, EventArgs e) |
|
||||||
{ |
|
||||||
if (PropertyChanged != null) { |
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs("BoundValue")); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,109 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Implements IPropertyEditorDataProperty by forwarding all calls to another IPropertyEditorDataProperty.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class ProxyPropertyEditorDataProperty : IPropertyEditorDataProperty |
|
||||||
{ |
|
||||||
readonly IPropertyEditorDataProperty data; |
|
||||||
|
|
||||||
/// <summary></summary>
|
|
||||||
protected ProxyPropertyEditorDataProperty(IPropertyEditorDataProperty data) |
|
||||||
{ |
|
||||||
if (data == null) |
|
||||||
throw new ArgumentNullException("data"); |
|
||||||
this.data = data; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual event EventHandler IsSetChanged { |
|
||||||
add { data.IsSetChanged += value; } |
|
||||||
remove { data.IsSetChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual event EventHandler ValueChanged { |
|
||||||
add { data.ValueChanged += value; } |
|
||||||
remove { data.ValueChanged -= value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual IPropertyEditorDataSource OwnerDataSource { |
|
||||||
get { return data.OwnerDataSource; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual string Category { |
|
||||||
get { return data.Category; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual string Name { |
|
||||||
get { return data.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual Type ReturnType { |
|
||||||
get { return data.ReturnType; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual Type DeclaringType { |
|
||||||
get { return data.DeclaringType; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual System.ComponentModel.TypeConverter TypeConverter { |
|
||||||
get { return data.TypeConverter; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual bool IsSet { |
|
||||||
get { return data.IsSet; } |
|
||||||
set { data.IsSet = value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual bool IsAmbiguous { |
|
||||||
get { return data.IsAmbiguous; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual object Value { |
|
||||||
get { return data.Value; } |
|
||||||
set { data.Value = value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual bool CanUseCustomExpression { |
|
||||||
get { return data.CanUseCustomExpression; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual object GetDescription() |
|
||||||
{ |
|
||||||
return data.GetDescription(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual void SetCustomExpression(string expression) |
|
||||||
{ |
|
||||||
data.SetCustomExpression(expression); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>See <see cref="IPropertyEditorDataProperty"/></summary>
|
|
||||||
public virtual System.Windows.UIElement CreateEditor() |
|
||||||
{ |
|
||||||
return data.CreateEditor(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Data; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Windows.Documents; |
|
||||||
using System.Windows.Media; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Type editor used to edit enum properties.
|
|
||||||
/// </summary>
|
|
||||||
sealed class StandardValuesComboBoxEditor : ComboBox |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Creates a new EnumEditor instance.
|
|
||||||
/// </summary>
|
|
||||||
public StandardValuesComboBoxEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
foreach (object o in property.TypeConverter.GetStandardValues()) { |
|
||||||
this.Items.Add(o); |
|
||||||
} |
|
||||||
SetBinding(ComboBox.SelectedItemProperty, PropertyEditorBindingHelper.CreateBinding(this, property)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,163 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.ComponentModel; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Windows; |
|
||||||
using System.Windows.Data; |
|
||||||
using System.Windows.Media; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Windows.Controls.Primitives; |
|
||||||
using System.Windows.Documents; |
|
||||||
using System.Windows.Threading; |
|
||||||
using System.Windows.Input; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Type editor used to edit properties using a text box and the type's default type converter.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class TextBoxEditor : TextBox |
|
||||||
{ |
|
||||||
readonly IPropertyEditorDataProperty property; |
|
||||||
bool isDirty; |
|
||||||
bool hasError; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The property edited by the TextBoxEditor.
|
|
||||||
/// </summary>
|
|
||||||
public IPropertyEditorDataProperty Property { |
|
||||||
get { return property; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new TextBoxEditor instance.
|
|
||||||
/// </summary>
|
|
||||||
public TextBoxEditor(IPropertyEditorDataProperty property) |
|
||||||
{ |
|
||||||
if (property == null) |
|
||||||
throw new ArgumentNullException("property"); |
|
||||||
|
|
||||||
this.property = property; |
|
||||||
UpdateFromSource(); |
|
||||||
PropertyEditorBindingHelper.AddValueChangedEventHandler( |
|
||||||
this, property, delegate { UpdateFromSource(); } |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
void UpdateFromSource() |
|
||||||
{ |
|
||||||
if (property.IsAmbiguous) { |
|
||||||
this.Text = ""; |
|
||||||
this.Background = SystemColors.ControlBrush; |
|
||||||
} else { |
|
||||||
this.Text = property.TypeConverter.ConvertToInvariantString(property.Value); |
|
||||||
} |
|
||||||
hasError = false; |
|
||||||
isDirty = false; |
|
||||||
if (property.IsSet) { |
|
||||||
this.Foreground = SystemColors.WindowTextBrush; |
|
||||||
} else { |
|
||||||
this.Foreground = SystemColors.GrayTextBrush; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void SaveValueToSource() |
|
||||||
{ |
|
||||||
isDirty = false; |
|
||||||
hasError = false; |
|
||||||
try { |
|
||||||
property.Value = property.TypeConverter.ConvertFromInvariantString(this.Text); |
|
||||||
} catch (Exception) { |
|
||||||
hasError = true; |
|
||||||
throw; |
|
||||||
} |
|
||||||
if (ValueSaved != null) |
|
||||||
ValueSaved(this, EventArgs.Empty); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when the user changes the property value using this text box.
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler ValueSaved; |
|
||||||
|
|
||||||
static UIElement DescribeError(Exception ex) |
|
||||||
{ |
|
||||||
return new TextBlock(new Run(ex.Message)); |
|
||||||
} |
|
||||||
|
|
||||||
static void ShowError(ServiceContainer serviceContainer, FrameworkElement control, UIElement errorDescription) |
|
||||||
{ |
|
||||||
IErrorService errorService = null; |
|
||||||
if (serviceContainer != null) |
|
||||||
errorService = serviceContainer.GetService<IErrorService>(); |
|
||||||
|
|
||||||
if (errorService != null) { |
|
||||||
errorService.ShowErrorTooltip(control, errorDescription); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
protected override void OnTextChanged(TextChangedEventArgs e) |
|
||||||
{ |
|
||||||
isDirty = true; |
|
||||||
this.Background = SystemColors.WindowBrush; |
|
||||||
this.Foreground = SystemColors.WindowTextBrush; |
|
||||||
base.OnTextChanged(e); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] |
|
||||||
protected override void OnLostFocus(RoutedEventArgs e) |
|
||||||
{ |
|
||||||
if (isDirty) { |
|
||||||
try { |
|
||||||
SaveValueToSource(); |
|
||||||
} catch (Exception ex) { |
|
||||||
Dispatcher.BeginInvoke( |
|
||||||
DispatcherPriority.Normal, new Action<Exception>( |
|
||||||
delegate (Exception exception) { |
|
||||||
if (Focus()) { |
|
||||||
ShowError(property.OwnerDataSource.Services, this, DescribeError(exception)); |
|
||||||
} |
|
||||||
}), ex); |
|
||||||
} |
|
||||||
} else if (hasError) { |
|
||||||
UpdateFromSource(); |
|
||||||
} |
|
||||||
base.OnLostFocus(e); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] |
|
||||||
protected override void OnKeyDown(KeyEventArgs e) |
|
||||||
{ |
|
||||||
base.OnKeyDown(e); |
|
||||||
if (e.Handled) return; |
|
||||||
if (e.Key == Key.Enter) { |
|
||||||
string oldText = this.Text; |
|
||||||
try { |
|
||||||
SaveValueToSource(); |
|
||||||
} catch (Exception ex) { |
|
||||||
ShowError(property.OwnerDataSource.Services, this, DescribeError(ex)); |
|
||||||
} |
|
||||||
if (this.Text != oldText) { |
|
||||||
this.SelectAll(); |
|
||||||
} |
|
||||||
e.Handled = true; |
|
||||||
} else if (e.Key == Key.Escape) { |
|
||||||
string oldText = this.Text; |
|
||||||
UpdateFromSource(); |
|
||||||
if (this.Text != oldText) { |
|
||||||
this.SelectAll(); |
|
||||||
} |
|
||||||
e.Handled = true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,39 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
namespace ICSharpCode.WpfDesign.PropertyEditor |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Attribute to specify that the decorated class is a editor for properties with the specified
|
|
||||||
/// return type.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)] |
|
||||||
public sealed class TypeEditorAttribute : Attribute |
|
||||||
{ |
|
||||||
readonly Type supportedPropertyType; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new TypeEditorAttribute that specifies that the decorated class is a editor
|
|
||||||
/// for properties with the return type "<paramref name="supportedPropertyType"/>".
|
|
||||||
/// </summary>
|
|
||||||
public TypeEditorAttribute(Type supportedPropertyType) |
|
||||||
{ |
|
||||||
if (supportedPropertyType == null) |
|
||||||
throw new ArgumentNullException("supportedPropertyType"); |
|
||||||
this.supportedPropertyType = supportedPropertyType; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the supported property type.
|
|
||||||
/// </summary>
|
|
||||||
public Type SupportedPropertyType { |
|
||||||
get { return supportedPropertyType; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue