Browse Source

Rework hit testing.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2258 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
2ea30969e5
  1. 2
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml
  2. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml
  3. 21
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs
  4. 235
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs
  5. 15
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs
  6. 159
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelInstanceFactory.cs
  7. 12
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs
  8. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs
  9. 57
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
  10. 27
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ViewService.cs
  11. 69
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/VisualDesignService.cs
  12. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
  13. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
  14. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs
  15. 27
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
  16. 61
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs
  17. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs
  18. 109
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignPanelHitTestResult.cs
  19. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs
  20. 23
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultInitializer.cs
  21. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs
  22. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs
  23. 24
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs
  24. 12
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs
  25. 55
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs
  26. 85
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs
  27. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

2
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
Title="WindowTitle"
BorderThickness="10" Width="400" Height="300">
<StackPanel>
<Canvas Height="50" Background="White"></Canvas>
<Canvas Height="50"></Canvas>
<Button>Button 1</Button>
<Button>Button 2</Button>
<TabControl Width="300" MinHeight="100">

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml

@ -21,6 +21,9 @@ @@ -21,6 +21,9 @@
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="thumbRectangle" Property="Fill" Value="Gray"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="thumbRectangle" Property="Fill" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>

21
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs

@ -22,14 +22,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors @@ -22,14 +22,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors
[TypeEditor(typeof(Brush))]
public sealed class BrushEditor : Border
{
readonly IPropertyEditorDataProperty property;
/// <summary>
/// Creates a new BooleanEditor instance.
/// </summary>
public BrushEditor(IPropertyEditorDataProperty property)
{
this.BorderBrush = Brushes.Black;
this.property = property;
this.SnapsToDevicePixels = true;
this.BorderThickness = new Thickness(1);
SetBinding(BackgroundProperty, PropertyEditorBindingHelper.CreateBinding(this, property));
PropertyEditorBindingHelper.AddValueChangedEventHandler(this, property, OnValueChanged);
OnValueChanged(null, null);
}
void OnValueChanged(object sender, EventArgs e)
{
Brush val = property.Value as Brush;
this.Background = val;
if (val == null) {
this.BorderBrush = null;
} else if (property.IsSet) {
this.BorderBrush = Brushes.Black;
} else {
this.BorderBrush = Brushes.Gray;
}
}
}
}

235
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs

@ -21,6 +21,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -21,6 +21,7 @@ namespace ICSharpCode.WpfDesign.Designer
{
sealed class DesignPanel : Decorator, IDesignPanel
{
#region Hit Testing
/// <summary>
/// this element is always hit (unless HitTestVisible is set to false)
/// </summary>
@ -37,6 +38,93 @@ namespace ICSharpCode.WpfDesign.Designer @@ -37,6 +38,93 @@ namespace ICSharpCode.WpfDesign.Designer
}
}
// Like VisualTreeHelper.HitTest(Visual,Point); but allows using a filter callback.
static PointHitTestResult RunHitTest(Visual reference, Point point, HitTestFilterCallback filterCallback)
{
HitTestResult result = null;
VisualTreeHelper.HitTest(reference, filterCallback,
delegate (HitTestResult resultParameter) {
result = resultParameter;
return HitTestResultBehavior.Stop;
},
new PointHitTestParameters(point));
return result as PointHitTestResult;
}
static HitTestFilterBehavior FilterHitTestInvisibleElements(DependencyObject potentialHitTestTarget)
{
UIElement element = potentialHitTestTarget as UIElement;
if (element != null) {
if (!(element.IsHitTestVisible && element.Visibility == Visibility.Visible)) {
return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
}
}
return HitTestFilterBehavior.Continue;
}
DesignPanelHitTestResult _lastHitTestResult;
/// <summary>
/// Performs a custom hit testing lookup for the specified mouse event args.
/// </summary>
public DesignPanelHitTestResult HitTest(MouseEventArgs e, bool testAdorners, bool testDesignSurface)
{
_lastHitTestResult = CustomHitTestInternal(e.GetPosition(this), testAdorners, testDesignSurface);
return _lastHitTestResult;
}
DesignPanelHitTestResult CustomHitTestInternal(Point mousePosition, bool testAdorners, bool testDesignSurface)
{
if (mousePosition.X < 0 || mousePosition.Y < 0 || mousePosition.X > this.RenderSize.Width || mousePosition.Y > this.RenderSize.Height) {
return DesignPanelHitTestResult.NoHit;
}
// First try hit-testing on the adorner layer.
PointHitTestResult result;
DesignPanelHitTestResult customResult;
if (testAdorners) {
result = RunHitTest(_adornerLayer, mousePosition, FilterHitTestInvisibleElements);
if (result != null && result.VisualHit != null) {
if (result.VisualHit == _lastHitTestResult.VisualHit)
return _lastHitTestResult;
customResult = new DesignPanelHitTestResult(result.VisualHit);
DependencyObject obj = result.VisualHit;
while (obj != null && obj != _adornerLayer) {
AdornerPanel adorner = obj as AdornerPanel;
if (adorner != null) {
customResult.AdornerHit = adorner;
}
obj = VisualTreeHelper.GetParent(obj);
}
return customResult;
}
}
if (testDesignSurface) {
result = RunHitTest(this.Child, mousePosition, FilterHitTestInvisibleElements);
if (result != null && result.VisualHit != null) {
customResult = new DesignPanelHitTestResult(result.VisualHit);
ViewService viewService = _context.Services.View;
DependencyObject obj = result.VisualHit;
while (obj != null) {
if ((customResult.ModelHit = viewService.GetModel(obj)) != null)
break;
obj = VisualTreeHelper.GetParent(obj);
}
if (customResult.ModelHit == null)
{
customResult.ModelHit = _context.RootItem;
}
return customResult;
}
}
return DesignPanelHitTestResult.NoHit;
}
#endregion
#region Fields + Constructor
DesignContext _context;
readonly EatAllHitTestRequests _eatAllHitTestRequests;
readonly AdornerLayer _adornerLayer;
@ -47,14 +135,51 @@ namespace ICSharpCode.WpfDesign.Designer @@ -47,14 +135,51 @@ namespace ICSharpCode.WpfDesign.Designer
this.Focusable = true;
this.VerticalAlignment = VerticalAlignment.Top;
this.HorizontalAlignment = HorizontalAlignment.Left;
this.Margin = new Thickness(10);
_eatAllHitTestRequests = new EatAllHitTestRequests();
_eatAllHitTestRequests.IsHitTestVisible = false;
_adornerLayer = new AdornerLayer(this);
_markerCanvas = new Canvas();
_markerCanvas.IsHitTestVisible = false;
}
#endregion
#region Properties
/// <summary>
/// Gets/Sets the design context.
/// </summary>
public DesignContext Context {
get { return _context; }
set { _context = value; }
}
public ICollection<AdornerPanel> Adorners {
get {
return _adornerLayer.Adorners;
}
}
public Canvas MarkerCanvas {
get { return _markerCanvas; }
}
/// <summary>
/// Gets/Sets if the design content is visible for hit-testing purposes.
/// </summary>
public bool IsContentHitTestVisible {
get { return !_eatAllHitTestRequests.IsHitTestVisible; }
set { _eatAllHitTestRequests.IsHitTestVisible = !value; }
}
/// <summary>
/// Gets/Sets if the adorner layer is visible for hit-testing purposes.
/// </summary>
public bool IsAdornerLayerHitTestVisible {
get { return _adornerLayer.IsHitTestVisible; }
set { _adornerLayer.IsHitTestVisible = value; }
}
#endregion
#region Visual Child Management
public override UIElement Child {
@ -127,110 +252,16 @@ namespace ICSharpCode.WpfDesign.Designer @@ -127,110 +252,16 @@ namespace ICSharpCode.WpfDesign.Designer
}
#endregion
/// <summary>
/// Gets/Sets the design context.
/// </summary>
public DesignContext Context {
get { return _context; }
set { _context = value; }
}
private IToolService ToolService {
[DebuggerStepThrough]
get { return _context.Services.Tool; }
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
if (!_isInInputAction) {
Debug.WriteLine("DesignPanel.PreviewMouseDown Source=" + e.Source.GetType().Name + " OriginalSource=" + e.OriginalSource.GetType().Name);
object topMostHitSource = null;
DesignItem site = FindDesignedElementForOriginalSource(e.OriginalSource, ref topMostHitSource);
InputHandlingLayer itemLayer = InputHandlingLayer.None;
if (site != null) {
Debug.WriteLine(" Found designed element: " + site.Component.GetType().Name);
IProvideComponentInputHandlingLayer layerProvider = site.GetBehavior<IProvideComponentInputHandlingLayer>();
if (layerProvider != null) {
itemLayer = layerProvider.InputLayer;
}
} else if (topMostHitSource == _adornerLayer) {
itemLayer = InputHandlingLayer.Adorners;
}
if (ToolService.CurrentTool.InputLayer > itemLayer) {
ToolService.CurrentTool.OnMouseDown(this, e);
}
}
}
// find a DesignItem for the clicked originalSource. This walks up the visual tree until it finds a designed item
// or the design surface itself.
// topMostSource is set to the element directly below the one that caused the tree walk to abort.
// For hits on the adorner layer, the method will return null and set topMostSource to _adornerLayer.
DesignItem FindDesignedElementForOriginalSource(object originalSource, ref object topMostSource)
protected override void OnQueryCursor(QueryCursorEventArgs e)
{
if (originalSource == null)
return null;
DesignItem site = _context.Services.Component.GetDesignItem(originalSource);
if (site != null)
return site;
if (originalSource == this)
return null;
topMostSource = originalSource;
DependencyObject dObj = originalSource as DependencyObject;
if (dObj == null)
return null;
return FindDesignedElementForOriginalSource(VisualTreeHelper.GetParent(dObj), ref topMostSource);
}
public DesignItem FindDesignedElementForOriginalSource(object originalSource)
{
object topMostSource = null;
return FindDesignedElementForOriginalSource(originalSource, ref topMostSource);
}
/// <summary>
/// prevent designed controls from getting the keyboard focus
/// </summary>
protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
if (e.NewFocus != this) {
if (e.NewFocus is TabItem) {
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(delegate { Focus(); }));
} else {
base.OnQueryCursor(e);
if (_context != null) {
Cursor cursor = _context.Services.Tool.CurrentTool.Cursor;
if (cursor != null) {
e.Cursor = cursor;
e.Handled = true;
Focus();
}
}
}
bool _isInInputAction;
void IDesignPanel.StartInputAction()
{
if (_isInInputAction) throw new InvalidOperationException();
_isInInputAction = true;
_eatAllHitTestRequests.IsHitTestVisible = true;
}
void IDesignPanel.StopInputAction()
{
if (!_isInInputAction) throw new InvalidOperationException();
_isInInputAction = false;
_eatAllHitTestRequests.IsHitTestVisible = false;
}
public ICollection<AdornerPanel> Adorners {
get {
return _adornerLayer.Adorners;
}
}
public Canvas MarkerCanvas {
get { return _markerCanvas; }
}
}
internal delegate void Action();
}

15
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs

@ -43,15 +43,6 @@ namespace ICSharpCode.WpfDesign.Designer @@ -43,15 +43,6 @@ namespace ICSharpCode.WpfDesign.Designer
get { return _designContext; }
}
/// <summary>
/// Gets the designed element.
/// </summary>
public UIElement DesignedElement {
get {
return _designPanel.Child;
}
}
/// <summary>
/// Initializes the designer content from the specified XmlReader.
/// </summary>
@ -75,7 +66,10 @@ namespace ICSharpCode.WpfDesign.Designer @@ -75,7 +66,10 @@ namespace ICSharpCode.WpfDesign.Designer
_designContext = context;
_designPanel.Context = context;
_designPanel.Child = context.RootItem.View;
Border designPanelBorder = new Border();
designPanelBorder.Padding = new Thickness(10);
_designPanel.Child = designPanelBorder;
designPanelBorder.Child = context.RootItem.View;
}
/// <summary>
@ -87,6 +81,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -87,6 +81,7 @@ namespace ICSharpCode.WpfDesign.Designer
_designPanel.Context = null;
_designPanel.Child = null;
_designPanel.Adorners.Clear();
_designPanel.MarkerCanvas.Children.Clear();
}
}
}

159
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelInstanceFactory.cs

@ -0,0 +1,159 @@ @@ -0,0 +1,159 @@
// <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.Windows.Media;
using System.Windows.Controls;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
/// <summary>
/// Instance factory used to create Panel instances.
/// Sets the panels Brush to a transparent brush, and modifies the panel's type descriptor so that
/// setting the Brush to null actually restores the transparent brush.
/// </summary>
[ExtensionFor(typeof(Panel))]
public class PanelInstanceFactory : CustomInstanceFactory
{
Brush _transparentBrush = new SolidColorBrush(Colors.Transparent);
/// <summary>
/// Creates an instance of the specified type, passing the specified arguments to its constructor.
/// </summary>
public override object CreateInstance(Type type, params object[] arguments)
{
object instance = base.CreateInstance(type, arguments);
Panel panel = instance as Panel;
if (panel != null) {
if (panel.Background == null) {
panel.Background = _transparentBrush;
}
TypeDescriptionProvider provider = new DummyValueInsteadOfNullTypeDescriptionProvider(
TypeDescriptor.GetProvider(panel), "Background", _transparentBrush);
TypeDescriptor.AddProvider(provider, panel);
}
return instance;
}
}
sealed class DummyValueInsteadOfNullTypeDescriptionProvider : TypeDescriptionProvider
{
// By using a TypeDescriptionProvider, we can intercept all access to the property that is
// using a PropertyDescriptor. WpfDesign.XamlDom uses a PropertyDescriptor for accessing
// properties (except for attached properties), so even DesignItemProperty/XamlProperty.ValueOnInstance
// will report null when the actual value is the dummy value.
readonly string _propertyName;
readonly object _dummyValue;
public DummyValueInsteadOfNullTypeDescriptionProvider(TypeDescriptionProvider existingProvider,
string propertyName, object dummyValue)
: base(existingProvider)
{
this._propertyName = propertyName;
this._dummyValue = dummyValue;
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new ShadowTypeDescriptor(this, base.GetTypeDescriptor(objectType, instance));
}
sealed class ShadowTypeDescriptor : CustomTypeDescriptor
{
readonly DummyValueInsteadOfNullTypeDescriptionProvider _parent;
public ShadowTypeDescriptor(DummyValueInsteadOfNullTypeDescriptionProvider parent,
ICustomTypeDescriptor existingDescriptor)
: base(existingDescriptor)
{
this._parent = parent;
}
public override PropertyDescriptorCollection GetProperties()
{
return Filter(base.GetProperties());
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return Filter(base.GetProperties(attributes));
}
PropertyDescriptorCollection Filter(PropertyDescriptorCollection properties)
{
PropertyDescriptor property = properties[_parent._propertyName];
if (property != null) {
if ((properties as System.Collections.IDictionary).IsReadOnly) {
properties = new PropertyDescriptorCollection(Linq.ToArray(properties));
}
properties.Remove(property);
properties.Add(new ShadowPropertyDescriptor(_parent, property));
}
return properties;
}
}
sealed class ShadowPropertyDescriptor : PropertyDescriptor
{
readonly DummyValueInsteadOfNullTypeDescriptionProvider _parent;
readonly PropertyDescriptor _baseDescriptor;
public ShadowPropertyDescriptor(DummyValueInsteadOfNullTypeDescriptionProvider parent,
PropertyDescriptor existingDescriptor)
: base(existingDescriptor)
{
this._parent = parent;
this._baseDescriptor = existingDescriptor;
}
public override Type ComponentType {
get { return _baseDescriptor.ComponentType; }
}
public override bool IsReadOnly {
get { return _baseDescriptor.IsReadOnly; }
}
public override Type PropertyType {
get { return _baseDescriptor.PropertyType; }
}
public override bool CanResetValue(object component)
{
return _baseDescriptor.CanResetValue(component);
}
public override object GetValue(object component)
{
object value = _baseDescriptor.GetValue(component);
if (value == _parent._dummyValue)
return null;
else
return value;
}
public override void ResetValue(object component)
{
_baseDescriptor.SetValue(component, _parent._dummyValue);
}
public override void SetValue(object component, object value)
{
_baseDescriptor.SetValue(component, value ?? _parent._dummyValue);
}
public override bool ShouldSerializeValue(object component)
{
return _baseDescriptor.ShouldSerializeValue(component)
&& _baseDescriptor.GetValue(component) != _parent._dummyValue;
}
}
}
}

12
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs

@ -15,18 +15,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -15,18 +15,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
/// Makes TabItems clickable.
/// </summary>
[ExtensionFor(typeof(TabItem))]
public sealed class TabItemClickableExtension : BehaviorExtension, IProvideComponentInputHandlingLayer
[ExtensionServer(typeof(PrimarySelectionExtensionServer))]
public sealed class TabItemClickableExtension : DefaultExtension
{
/// <summary/>
protected override void OnInitialized()
{
this.ExtendedItem.AddBehavior(typeof(IProvideComponentInputHandlingLayer), this);
}
InputHandlingLayer IProvideComponentInputHandlingLayer.InputLayer {
get {
return InputHandlingLayer.ComponentHigh;
}
TabItem tabItem = (TabItem)this.ExtendedItem.Component;
tabItem.BringIntoView();
}
}
}

8
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.ComponentModel;
using System.Collections.Generic;
namespace ICSharpCode.WpfDesign.Designer
@ -20,6 +21,13 @@ namespace ICSharpCode.WpfDesign.Designer @@ -20,6 +21,13 @@ namespace ICSharpCode.WpfDesign.Designer
return arr;
}
public static PropertyDescriptor[] ToArray(PropertyDescriptorCollection collection)
{
PropertyDescriptor[] arr = new PropertyDescriptor[collection.Count];
collection.CopyTo(arr, 0);
return arr;
}
/// <summary>
/// Returns a sorted copy of the collection.
/// </summary>

57
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs

@ -15,10 +15,16 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -15,10 +15,16 @@ namespace ICSharpCode.WpfDesign.Designer.Services
{
PointerTool _pointerTool;
ITool _currentTool;
IDesignPanel _designPanel;
public DefaultToolService()
public DefaultToolService(DesignContext context)
{
_currentTool = _pointerTool = new PointerTool();
context.Services.RunWhenAvailable<IDesignPanel>(
delegate(IDesignPanel designPanel) {
_designPanel = designPanel;
_currentTool.Activate(designPanel);
});
}
public ITool PointerTool {
@ -30,30 +36,53 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -30,30 +36,53 @@ namespace ICSharpCode.WpfDesign.Designer.Services
set {
if (value == null)
throw new ArgumentNullException("value");
if (_currentTool == value) return;
_currentTool.Deactivate(_designPanel);
_currentTool = value;
_currentTool.Activate(_designPanel);
}
}
}
sealed class PointerTool : ITool
{
public InputHandlingLayer InputLayer {
get { return InputHandlingLayer.Tool; }
public Cursor Cursor {
get { return null; }
}
public Cursor Cursor {
get { return Cursors.Arrow; }
public void Activate(IDesignPanel designPanel)
{
designPanel.MouseDown += OnMouseDown;
}
public void OnMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e)
public void Deactivate(IDesignPanel designPanel)
{
e.Handled = true;
new SelectionGesture().Start(designPanel, e);
designPanel.MouseDown -= OnMouseDown;
}
void OnMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left && MouseGestureBase.IsOnlyButtonPressed(e, MouseButton.Left)) {
e.Handled = true;
new SelectionGesture().Start((IDesignPanel)sender, e);
}
}
}
abstract class MouseGestureBase
{
/// <summary>
/// Checks if <paramref name="button"/> is the only button that is currently pressed.
/// </summary>
internal static bool IsOnlyButtonPressed(MouseEventArgs e, MouseButton button)
{
return e.LeftButton == (button == MouseButton.Left ? MouseButtonState.Pressed : MouseButtonState.Released)
&& e.MiddleButton == (button == MouseButton.Middle ? MouseButtonState.Pressed : MouseButtonState.Released)
&& e.RightButton == (button == MouseButton.Right ? MouseButtonState.Pressed : MouseButtonState.Released)
&& e.XButton1 == (button == MouseButton.XButton1 ? MouseButtonState.Pressed : MouseButtonState.Released)
&& e.XButton2 == (button == MouseButton.XButton2 ? MouseButtonState.Pressed : MouseButtonState.Released);
}
protected IDesignPanel designPanel;
protected ServiceContainer services;
bool isStarted;
@ -63,7 +92,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -63,7 +92,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
this.designPanel = designPanel;
this.services = designPanel.Context.Services;
isStarted = true;
designPanel.StartInputAction();
designPanel.IsAdornerLayerHitTestVisible = false;
RegisterEvents();
if (designPanel.CaptureMouse()) {
OnStarted(e);
@ -112,7 +141,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -112,7 +141,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
isStarted = false;
designPanel.ReleaseMouseCapture();
UnRegisterEvents();
designPanel.StopInputAction();
designPanel.IsAdornerLayerHitTestVisible = true;
OnStopped();
}
@ -125,11 +154,9 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -125,11 +154,9 @@ namespace ICSharpCode.WpfDesign.Designer.Services
protected override void OnStarted(MouseButtonEventArgs e)
{
base.OnStarted(e);
DesignItem item = designPanel.FindDesignedElementForOriginalSource(e.OriginalSource);
if (item != null) {
services.Selection.SetSelectedComponents(new DesignItem[] { item }, SelectionTypes.Auto);
} else {
services.Selection.SetSelectedComponents(new DesignItem[] { }, SelectionTypes.Auto);
DesignPanelHitTestResult result = designPanel.HitTest(e, false, true);
if (result.ModelHit != null) {
services.Selection.SetSelectedComponents(new DesignItem[] { result.ModelHit }, SelectionTypes.Auto);
}
}

27
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ViewService.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
// <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.Designer.Services
{
sealed class DefaultViewService : ViewService
{
readonly DesignContext context;
public DefaultViewService(DesignContext context)
{
this.context = context;
}
public override DesignItem GetModel(System.Windows.DependencyObject view)
{
// In the WPF designer, we do not support having a different view for a component
return context.Services.Component.GetDesignItem(view);
}
}
}

69
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/VisualDesignService.cs

@ -1,69 +0,0 @@ @@ -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.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ICSharpCode.WpfDesign.Designer.Services
{
sealed class DefaultVisualDesignService : IVisualDesignService
{
public UIElement CreateWrapper(DesignItem site)
{
if (site == null)
throw new ArgumentNullException("site");
object obj = site.Component;
if (obj is UIElement)
return null;
else
return new FallbackObjectWrapper(site);
}
internal static UIElement CreateUIElementFor(DesignItem site)
{
IVisualDesignService service = site.Services.GetService<IVisualDesignService>();
if (service == null)
throw new ServiceRequiredException(typeof(IVisualDesignService));
UIElement element = service.CreateWrapper(site);
if (element != null) {
if (!(element is IVisualDesignObjectWrapper)) {
throw new DesignerException("IVisualDesignService.CreateWrapper must return null or UIElement implementing IVisualDesignObjectWrapper");
}
} else {
element = site.Component as UIElement;
if (element == null) {
throw new DesignerException("IVisualDesignService.CreateWrapper may not return null if site.Component is no UIElement");
}
}
return element;
}
}
sealed class FallbackObjectWrapper : ContentControl, IVisualDesignObjectWrapper
{
DesignItem _site;
public FallbackObjectWrapper(DesignItem site)
{
this._site = site;
this.BorderThickness = new Thickness(1);
this.BorderBrush = Brushes.Black;
this.Background = Brushes.White;
this.Foreground = Brushes.Black;
this.Content = site.Component;
}
public DesignItem WrappedSite {
get { return _site; }
}
}
}

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj

@ -68,6 +68,7 @@ @@ -68,6 +68,7 @@
<Compile Include="Controls\TypeEditors\BrushEditor.cs" />
<Compile Include="Controls\WindowClone.cs" />
<Compile Include="DesignPanel.cs" />
<Compile Include="Extensions\PanelInstanceFactory.cs" />
<Compile Include="Extensions\SelectedElementRectangleExtension.cs" />
<Compile Include="Extensions\TabItemClickableExtension.cs" />
<Compile Include="Extensions\TopLeftContainerDragHandle.cs" />
@ -77,7 +78,7 @@ @@ -77,7 +78,7 @@
<Compile Include="Services\SelectionService.cs" />
<Compile Include="Services\ToolService.cs" />
<Compile Include="Services\UndoService.cs" />
<Compile Include="Services\VisualDesignService.cs" />
<Compile Include="Services\ViewService.cs" />
<Compile Include="DesignSurface.cs" />
<Compile Include="Xaml\XamlComponentService.cs" />
<Compile Include="Xaml\XamlDesignContext.cs" />

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs

@ -35,10 +35,10 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml @@ -35,10 +35,10 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
if (xamlReader == null)
throw new ArgumentNullException("xamlReader");
this.Services.AddService(typeof(IVisualDesignService), new DefaultVisualDesignService());
this.Services.AddService(typeof(ISelectionService), new DefaultSelectionService());
this.Services.AddService(typeof(IToolService), new DefaultToolService());
this.Services.AddService(typeof(IToolService), new DefaultToolService(this));
this.Services.AddService(typeof(UndoService), new UndoService());
this.Services.AddService(typeof(ViewService), new DefaultViewService(this));
_componentService = new XamlComponentService(this);
this.Services.AddService(typeof(IComponentService), _componentService);

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs

@ -102,7 +102,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -102,7 +102,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
if (p.PropertyName == propertyName)
return p;
}
PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(elementType);
PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(instance);
PropertyDescriptor propertyInfo = propertyDescriptors[propertyName];
if (propertyInfo == null) {
throw new ArgumentException("The property '" + propertyName + "' doesn't exist on " + elementType.FullName, "propertyName");

27
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs

@ -256,17 +256,22 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -256,17 +256,22 @@ namespace ICSharpCode.WpfDesign.XamlDom
static XamlPropertyInfo GetDefaultProperty(Type elementType)
{
foreach (ContentPropertyAttribute cpa in elementType.GetCustomAttributes(typeof(ContentPropertyAttribute), true)) {
return FindProperty(elementType, cpa.Name);
return FindProperty(null, elementType, cpa.Name);
}
return null;
}
static XamlPropertyInfo FindProperty(Type elementType, string propertyName)
static XamlPropertyInfo FindProperty(object elementInstance, Type propertyType, string propertyName)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(elementType);
PropertyDescriptorCollection properties;
if (elementInstance != null) {
properties = TypeDescriptor.GetProperties(elementInstance);
} else {
properties = TypeDescriptor.GetProperties(propertyType);
}
PropertyDescriptor propertyInfo = properties[propertyName];
if (propertyInfo == null) {
XamlPropertyInfo pi = TryFindAttachedProperty(elementType, propertyName);
XamlPropertyInfo pi = TryFindAttachedProperty(propertyType, propertyName);
if (pi != null) {
return pi;
} else {
@ -299,22 +304,22 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -299,22 +304,22 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
XamlPropertyInfo GetPropertyInfo(Type elementType, XmlAttribute attribute)
XamlPropertyInfo GetPropertyInfo(object elementInstance, Type elementType, XmlAttribute attribute)
{
if (attribute.LocalName.Contains(".")) {
return GetPropertyInfo(elementType, GetAttributeNamespace(attribute), attribute.LocalName);
return GetPropertyInfo(elementInstance, elementType, GetAttributeNamespace(attribute), attribute.LocalName);
} else {
return FindProperty(elementType, attribute.LocalName);
return FindProperty(elementInstance, elementType, attribute.LocalName);
}
}
XamlPropertyInfo GetPropertyInfo(Type elementType, string xmlNamespace, string localName)
XamlPropertyInfo GetPropertyInfo(object elementInstance, Type elementType, string xmlNamespace, string localName)
{
string typeName, propertyName;
SplitQualifiedIdentifier(localName, out typeName, out propertyName);
Type propertyType = FindType(xmlNamespace, typeName);
if (elementType == propertyType || propertyType.IsAssignableFrom(elementType)) {
return FindProperty(propertyType, propertyName);
return FindProperty(elementInstance, propertyType, propertyName);
} else {
// This is an attached property
return FindAttachedProperty(propertyType, propertyName);
@ -331,7 +336,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -331,7 +336,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
void ParseObjectAttribute(XamlObject obj, XmlAttribute attribute)
{
XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.ElementType, attribute);
XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.Instance, obj.ElementType, attribute);
XamlTextValue textValue = new XamlTextValue(attribute);
propertyInfo.SetValue(obj.Instance, textValue.GetValueFor(propertyInfo));
obj.AddProperty(new XamlProperty(obj, propertyInfo, textValue));
@ -347,7 +352,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -347,7 +352,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
Debug.Assert(element.LocalName.Contains("."));
// this is a element property syntax
XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.ElementType, element.NamespaceURI, element.LocalName);
XamlPropertyInfo propertyInfo = GetPropertyInfo(obj.Instance, obj.ElementType, element.NamespaceURI, element.LocalName);
bool valueWasSet = false;
object collectionInstance = null;

61
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs

@ -53,15 +53,37 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -53,15 +53,37 @@ namespace ICSharpCode.WpfDesign.Adorners
#endregion
UIElement _adornedElement;
DesignItem _adornedDesignItem;
AdornerOrder _Order = AdornerOrder.Content;
/// <summary>
/// Gets/Sets the element adorned by this AdornerPanel.
/// Do not change this property after the panel was added to an AdornerLayer!
/// Gets the element adorned by this AdornerPanel.
/// </summary>
public UIElement AdornedElement {
get { return _adornedElement; }
set { _adornedElement = value; }
}
/// <summary>
/// Gets the design item adorned by this AdornerPanel.
/// </summary>
public DesignItem AdornedDesignItem {
get { return _adornedDesignItem; }
}
/// <summary>
/// Sets the AdornedElement and AdornedDesignItem properties.
/// This method can be called only once.
/// </summary>
public void SetAdornedElement(UIElement adornedElement, DesignItem adornedDesignItem)
{
if (adornedElement == null)
throw new ArgumentNullException("adornedElement");
if (_adornedElement != null)
throw new InvalidOperationException("AdornedElement is already set.");
_adornedElement = adornedElement;
_adornedDesignItem = adornedDesignItem;
}
/// <summary>
@ -113,7 +135,7 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -113,7 +135,7 @@ namespace ICSharpCode.WpfDesign.Adorners
/// <summary>
/// Describes where an Adorner is positioned on the Z-Layer.
/// </summary>
public struct AdornerOrder : IComparable<AdornerOrder>
public struct AdornerOrder : IComparable<AdornerOrder>, IEquatable<AdornerOrder>
{
/// <summary>
/// The adorner is in the background layer.
@ -137,6 +159,25 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -137,6 +159,25 @@ namespace ICSharpCode.WpfDesign.Adorners
this.i = i;
}
/// <summary/>
public override int GetHashCode()
{
return i.GetHashCode();
}
/// <summary/>
public override bool Equals(object obj)
{
if (!(obj is AdornerOrder)) return false;
return this == (AdornerOrder)obj;
}
/// <summary/>
public bool Equals(AdornerOrder other)
{
return i == other.i;
}
/// <summary>
/// Compares the <see cref="AdornerOrder"/> to another AdornerOrder.
/// </summary>
@ -144,5 +185,17 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -144,5 +185,17 @@ namespace ICSharpCode.WpfDesign.Adorners
{
return i.CompareTo(other.i);
}
/// <summary/>
public static bool operator ==(AdornerOrder leftHandSide, AdornerOrder rightHandSide)
{
return leftHandSide.i == rightHandSide.i;
}
/// <summary/>
public static bool operator !=(AdornerOrder leftHandSide, AdornerOrder rightHandSide)
{
return leftHandSide.i != rightHandSide.i;
}
}
}

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs

@ -142,7 +142,7 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -142,7 +142,7 @@ namespace ICSharpCode.WpfDesign.Adorners
{
if (!isVisible) return;
item.AdornedElement = this.ExtendedItem.View;
item.SetAdornedElement(this.ExtendedItem.View, this.ExtendedItem);;
IDesignPanel avs = Services.GetService<IDesignPanel>();
avs.Adorners.Add(item);

109
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignPanelHitTestResult.cs

@ -0,0 +1,109 @@ @@ -0,0 +1,109 @@
// <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.Windows.Media;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign
{
/// <summary>
/// Describes the result of a <see cref="IDesignPanel.HitTest"/> call.
/// </summary>
public struct DesignPanelHitTestResult : IEquatable<DesignPanelHitTestResult>
{
/// <summary>
/// Represents the result that nothing was hit.
/// </summary>
public static readonly DesignPanelHitTestResult NoHit = new DesignPanelHitTestResult();
readonly Visual _visualHit;
AdornerPanel _adornerHit;
DesignItem _modelHit;
/// <summary>
/// The actual visual that was hit.
/// </summary>
public Visual VisualHit {
get { return _visualHit; }
}
/// <summary>
/// The adorner panel containing the adorner that was hit.
/// </summary>
public AdornerPanel AdornerHit {
get { return _adornerHit; }
set { _adornerHit = value; }
}
/// <summary>
/// The model item that was hit.
/// </summary>
public DesignItem ModelHit {
get { return _modelHit; }
set { _modelHit = value; }
}
/// <summary>
/// Create a new DesignPanelHitTestResult instance.
/// </summary>
public DesignPanelHitTestResult(Visual visualHit)
{
this._visualHit = visualHit;
this._adornerHit = null;
this._modelHit = null;
}
#region Equals and GetHashCode implementation
// The code in this region is useful if you want to use this structure in collections.
// If you don't need it, you can just remove the region and the ": IEquatable<DesignPanelHitTestResult>" declaration.
/// <summary>
/// Tests if this hit test result equals the other result.
/// </summary>
public override bool Equals(object obj)
{
if (obj is DesignPanelHitTestResult)
return Equals((DesignPanelHitTestResult)obj); // use Equals method below
else
return false;
}
/// <summary>
/// Tests if this hit test result equals the other result.
/// </summary>
public bool Equals(DesignPanelHitTestResult other)
{
// add comparisions for all members here
return _visualHit == other._visualHit && _adornerHit == other._adornerHit && _modelHit == other._modelHit;
}
/// <summary>
/// Gets the hash code.
/// </summary>
public override int GetHashCode()
{
// combine the hash codes of all members here (e.g. with XOR operator ^)
return (_visualHit != null ? _visualHit.GetHashCode() : 0)
^ (_adornerHit != null ? _adornerHit.GetHashCode() : 0)
^ (_modelHit != null ? _modelHit.GetHashCode() : 0);
}
/// <summary/>
public static bool operator ==(DesignPanelHitTestResult lhs, DesignPanelHitTestResult rhs)
{
return lhs.Equals(rhs);
}
/// <summary/>
public static bool operator !=(DesignPanelHitTestResult lhs, DesignPanelHitTestResult rhs)
{
return !(lhs.Equals(rhs)); // use operator == and negate result
}
#endregion
}
}

8
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs

@ -95,13 +95,11 @@ namespace ICSharpCode.WpfDesign.Extensions @@ -95,13 +95,11 @@ namespace ICSharpCode.WpfDesign.Extensions
/// <summary>
/// Calls OnRemove() on the DefaultExtension.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public override void RemoveExtension(Extension extension)
{
Debug.Assert(extension != null);
Debug.Assert(extension is DefaultExtension);
((DefaultExtension)extension).CallOnRemove();
DefaultExtension defaultExtension = extension as DefaultExtension;
Debug.Assert(defaultExtension != null);
defaultExtension.CallOnRemove();
}
/// <summary>

23
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultInitializer.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
// <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.Extensions
{
/// <summary>
/// Base class for extensions that initialize new controls with default values.
/// </summary>
[ExtensionServer(typeof(NeverApplyExtensionsExtensionServer))]
public abstract class DefaultInitializer : Extension
{
/// <summary>
/// Initializes the design item to default values.
/// </summary>
public abstract void InitializeDefaults(DesignItem item);
}
}

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.WpfDesign.Extensions @@ -24,7 +24,7 @@ namespace ICSharpCode.WpfDesign.Extensions
Debug.Assert(context != null);
this._context = context;
context.Services.Subscribe<IComponentService>(
context.Services.RunWhenAvailable<IComponentService>(
delegate(IComponentService componentService) {
componentService.ComponentRegistered += OnComponentRegistered;
});

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs

@ -61,6 +61,9 @@ namespace ICSharpCode.WpfDesign.PropertyEditor @@ -61,6 +61,9 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
/// </summary>
public static Type GetFallbackEditorType(IPropertyEditorDataProperty property)
{
if (property == null)
throw new ArgumentNullException("property");
Type returnType = property.ReturnType;
if (returnType.IsEnum) {
return typeof(StandardValuesComboBoxEditor);

24
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs

@ -19,6 +19,30 @@ namespace ICSharpCode.WpfDesign.PropertyEditor @@ -19,6 +19,30 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
/// </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");
editor.Loaded += delegate {
dataProperty.ValueChanged += handler;
};
editor.Unloaded += delegate {
dataProperty.ValueChanged -= handler;
};
if (editor.IsLoaded) {
dataProperty.ValueChanged += handler;
}
}
/// <summary>
/// Binds editor.property to dataProperty.Value.
/// </summary>

12
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs

@ -69,7 +69,7 @@ namespace ICSharpCode.WpfDesign @@ -69,7 +69,7 @@ namespace ICSharpCode.WpfDesign
/// serviceAvailableAction will be called after the service gets available. If the service is already available,
/// the action will be called immediately.
/// </summary>
public void Subscribe<T>(Action<T> serviceAvailableAction) where T : class
public void RunWhenAvailable<T>(Action<T> serviceAvailableAction) where T : class
{
T service = GetService<T>();
if (service != null) {
@ -124,6 +124,16 @@ namespace ICSharpCode.WpfDesign @@ -124,6 +124,16 @@ namespace ICSharpCode.WpfDesign
}
}
/// <summary>
/// Gets the <see cref="ViewService"/>.
/// Throws an exception if the service is not found.
/// </summary>
public ViewService View {
get {
return GetServiceOrThrowException<ViewService>();
}
}
/// <summary>
/// Gets the <see cref="ExtensionManager"/>.
/// Throws an exception if the service is not found.

55
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs

@ -11,36 +11,6 @@ using System.Windows; @@ -11,36 +11,6 @@ using System.Windows;
namespace ICSharpCode.WpfDesign
{
#region IVisualDesignService
/// <summary>
/// A service that can visualize non-UIElement objects on a design surface.
/// </summary>
public interface IVisualDesignService
{
/// <summary>
/// Create an UIElement for visualizing the object specified by the design site.
/// </summary>
/// <returns>
/// Returns either an UIElement instance that also implements
/// <see cref="IVisualDesignObjectWrapper"/>,
/// or returns null to use the component itself as UIElement.
/// </returns>
UIElement CreateWrapper(DesignItem site);
}
/// <summary>
/// Interface used by the <see cref="IVisualDesignService"/> for UIElements that
/// are inside the design surfaced but used only to represent a non-UIElement entity.
/// </summary>
public interface IVisualDesignObjectWrapper
{
/// <summary>
/// Gets the design site this object was wrapping.
/// </summary>
DesignItem WrappedSite { get; }
}
#endregion
#region ISelectionService
/// <summary>
/// Defines the type how a selection can be changed.
@ -151,4 +121,29 @@ namespace ICSharpCode.WpfDesign @@ -151,4 +121,29 @@ namespace ICSharpCode.WpfDesign
event EventHandler<DesignItemEventArgs> ComponentUnregistered;
}
#endregion
#region IViewService
/// <summary>
/// Service for getting the view for a model or the model for a view.
/// </summary>
public abstract class ViewService
{
/// <summary>
/// Gets the model represented by the specified view element.
/// </summary>
public abstract DesignItem GetModel(DependencyObject view);
/// <summary>
/// Gets the view for the specified model item.
/// This is equivalent to using <c>model.View</c>.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
public DependencyObject GetView(DesignItem model)
{
if (model == null)
throw new ArgumentNullException("model");
return model.View;
}
}
#endregion
}

85
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs

@ -7,57 +7,15 @@ @@ -7,57 +7,15 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign
{
/// <summary>
/// Describes the layer of input handling.
/// When multiple actions are possible, that with the highest layer will be used.
/// </summary>
public enum InputHandlingLayer
{
/// <summary>
/// No layer specified. This layer is lower than all other layers.
/// </summary>
None,
/// <summary>
/// Layer used for passing the input to the component.
/// Normally never receives actions because there is always a <see cref="Tool"/>.
/// </summary>
Component,
/// <summary>
/// Layer used for tools.
/// </summary>
Tool,
/// <summary>
/// Layer used for certain components that should get input, for example scroll thumbs
/// in user-defined ScrollViewers and the headers inside a TabControl.
/// </summary>
ComponentHigh,
/// <summary>
/// This value is used for mouse input on the adorner layer.
/// </summary>
Adorners,
/// <summary>
/// This layer is higher than all other layers.
/// </summary>
Highest
}
/// <summary>
/// Interface for behavior extensions that specifies the input layer of the extended component.
/// </summary>
public interface IProvideComponentInputHandlingLayer
{
/// <summary>
/// Gets the input handling layer of the component.
/// </summary>
InputHandlingLayer InputLayer { get; }
}
/// <summary>
/// Describes a tool that can handle input on the design surface.
/// Modelled after the description on http://urbanpotato.net/Default.aspx/document/2300
@ -65,19 +23,19 @@ namespace ICSharpCode.WpfDesign @@ -65,19 +23,19 @@ namespace ICSharpCode.WpfDesign
public interface ITool
{
/// <summary>
/// Gets the input handling layer of the tool.
/// Gets the cursor used by the tool.
/// </summary>
InputHandlingLayer InputLayer { get; }
Cursor Cursor { get; }
/// <summary>
/// Gets the cursor used by the tool.
/// Activates the tool, attaching its event handlers to the design panel.
/// </summary>
Cursor Cursor { get; }
void Activate(IDesignPanel designPanel);
/// <summary>
/// Notifies the tool of the MouseDown event.
/// Deactivates the tool, detaching its event handlers from the design panel.
/// </summary>
void OnMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e);
void Deactivate(IDesignPanel designPanel);
}
/// <summary>
@ -109,35 +67,32 @@ namespace ICSharpCode.WpfDesign @@ -109,35 +67,32 @@ namespace ICSharpCode.WpfDesign
DesignContext Context { get; }
/// <summary>
/// Starts an input action. This prevents components and tools from getting input events,
/// leaving input handling to event handlers attached to the design panel.
/// Gets/Sets if the design content is visible for hit-testing purposes.
/// </summary>
void StartInputAction();
bool IsContentHitTestVisible { get; set; }
/// <summary>
/// Stops an input action. This reenables input handling of
/// Gets/Sets if the adorner layer is visible for hit-testing purposes.
/// </summary>
void StopInputAction();
/// <summary>
/// Finds the designed element for the specified original source.
/// </summary>
DesignItem FindDesignedElementForOriginalSource(object originalSource);
bool IsAdornerLayerHitTestVisible { get; set; }
/// <summary>
/// Gets the list of adorners displayed on the design panel.
/// </summary>
ICollection<AdornerPanel> Adorners { get; }
/*
/// <summary>
/// A canvas that is on top of the design surface and all adorners.
/// Used for temporary drawings that are not attached to any element, e.g. the selection frame.
/// </summary>
Canvas MarkerCanvas { get; }
*/
// The following members were missing in <see cref="IInputElement"/>, but of course
/// <summary>
/// Performs a hit test on the design surface.
/// </summary>
DesignPanelHitTestResult HitTest(MouseEventArgs e, bool testAdorners, bool testDesignSurface);
// The following members were missing in <see cref="IInputElement"/>, but
// are supported on the DesignPanel:
/// <summary>

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

@ -64,12 +64,14 @@ @@ -64,12 +64,14 @@
<Compile Include="ChangeGroup.cs" />
<Compile Include="DesignContext.cs" />
<Compile Include="DesignItemProperty.cs" />
<Compile Include="DesignPanelHitTestResult.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="DesignerException.cs" />
<Compile Include="Extensions\BehaviorExtension.cs" />
<Compile Include="Extensions\CustomInstanceFactory.cs" />
<Compile Include="Extensions\DefaultExtension.cs" />
<Compile Include="Extensions\DefaultInitializer.cs" />
<Compile Include="Extensions\Extension.cs" />
<Compile Include="Extensions\ExtensionForAttribute.cs" />
<Compile Include="Extensions\ExtensionManager.cs" />

Loading…
Cancel
Save