diff --git a/src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml b/src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml index 893096a26b..d0aa4321eb 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml +++ b/src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml @@ -20,7 +20,7 @@ Title="WindowTitle" BorderThickness="10" Width="400" Height="300"> - + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml index dcff320dd7..3abe1bd6b4 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml @@ -21,6 +21,9 @@ + + + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs index 0ff5e90265..e8c9e299fe 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs @@ -22,14 +22,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors [TypeEditor(typeof(Brush))] public sealed class BrushEditor : Border { + readonly IPropertyEditorDataProperty property; + /// /// Creates a new BooleanEditor instance. /// 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; + } } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs index d112667aa7..3381fb27d7 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs @@ -21,6 +21,7 @@ namespace ICSharpCode.WpfDesign.Designer { sealed class DesignPanel : Decorator, IDesignPanel { + #region Hit Testing /// /// this element is always hit (unless HitTestVisible is set to false) /// @@ -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; + + /// + /// Performs a custom hit testing lookup for the specified mouse event args. + /// + 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 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 + + /// + /// Gets/Sets the design context. + /// + public DesignContext Context { + get { return _context; } + set { _context = value; } + } + + public ICollection Adorners { + get { + return _adornerLayer.Adorners; + } + } + + public Canvas MarkerCanvas { + get { return _markerCanvas; } + } + + /// + /// Gets/Sets if the design content is visible for hit-testing purposes. + /// + public bool IsContentHitTestVisible { + get { return !_eatAllHitTestRequests.IsHitTestVisible; } + set { _eatAllHitTestRequests.IsHitTestVisible = !value; } + } + + /// + /// Gets/Sets if the adorner layer is visible for hit-testing purposes. + /// + 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 } #endregion - /// - /// Gets/Sets the design context. - /// - 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(); - 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); - } - - /// - /// prevent designed controls from getting the keyboard focus - /// - 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 Adorners { - get { - return _adornerLayer.Adorners; - } - } - - public Canvas MarkerCanvas { - get { return _markerCanvas; } - } } - - internal delegate void Action(); } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs index 05a2a9ce1b..0df8ca341f 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs @@ -43,15 +43,6 @@ namespace ICSharpCode.WpfDesign.Designer get { return _designContext; } } - /// - /// Gets the designed element. - /// - public UIElement DesignedElement { - get { - return _designPanel.Child; - } - } - /// /// Initializes the designer content from the specified XmlReader. /// @@ -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; } /// @@ -87,6 +81,7 @@ namespace ICSharpCode.WpfDesign.Designer _designPanel.Context = null; _designPanel.Child = null; _designPanel.Adorners.Clear(); + _designPanel.MarkerCanvas.Children.Clear(); } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelInstanceFactory.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelInstanceFactory.cs new file mode 100644 index 0000000000..cd1a915bcb --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/PanelInstanceFactory.cs @@ -0,0 +1,159 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.ComponentModel; +using System.Windows.Media; +using System.Windows.Controls; +using ICSharpCode.WpfDesign.Extensions; + +namespace ICSharpCode.WpfDesign.Designer.Extensions +{ + /// + /// 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. + /// + [ExtensionFor(typeof(Panel))] + public class PanelInstanceFactory : CustomInstanceFactory + { + Brush _transparentBrush = new SolidColorBrush(Colors.Transparent); + + /// + /// Creates an instance of the specified type, passing the specified arguments to its constructor. + /// + 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; + } + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs index 664c9cb97f..5d84a548b9 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs @@ -15,18 +15,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions /// Makes TabItems clickable. /// [ExtensionFor(typeof(TabItem))] - public sealed class TabItemClickableExtension : BehaviorExtension, IProvideComponentInputHandlingLayer + [ExtensionServer(typeof(PrimarySelectionExtensionServer))] + public sealed class TabItemClickableExtension : DefaultExtension { /// 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(); } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs index cc8c18fdf3..36828f068a 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs @@ -6,6 +6,7 @@ // using System; +using System.ComponentModel; using System.Collections.Generic; 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; + } + /// /// Returns a sorted copy of the collection. /// diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs index fa4d87d6cb..2eea4409a3 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs @@ -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( + delegate(IDesignPanel designPanel) { + _designPanel = designPanel; + _currentTool.Activate(designPanel); + }); } public ITool PointerTool { @@ -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 { + /// + /// Checks if is the only button that is currently pressed. + /// + 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 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 isStarted = false; designPanel.ReleaseMouseCapture(); UnRegisterEvents(); - designPanel.StopInputAction(); + designPanel.IsAdornerLayerHitTestVisible = true; OnStopped(); } @@ -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); } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ViewService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ViewService.cs new file mode 100644 index 0000000000..7c729048a8 --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ViewService.cs @@ -0,0 +1,27 @@ +// +// +// +// +// $Revision$ +// + +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); + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/VisualDesignService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/VisualDesignService.cs deleted file mode 100644 index da3b5a4d2e..0000000000 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/VisualDesignService.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// -// -// -// $Revision$ -// - -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(); - 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; } - } - } -} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj index f010cc2f57..7900cd5d2c 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj @@ -68,6 +68,7 @@ + @@ -77,7 +78,7 @@ - + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs index c4f1151bdd..75b7c480f0 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs @@ -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); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs index a467dcffd6..9e00068366 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs @@ -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"); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs index 303f78024b..ee847446f5 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs @@ -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 } } - 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 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 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; diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs index 56921893dc..0e1f64d2a7 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs @@ -53,15 +53,37 @@ namespace ICSharpCode.WpfDesign.Adorners #endregion UIElement _adornedElement; + DesignItem _adornedDesignItem; AdornerOrder _Order = AdornerOrder.Content; + /// - /// 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. /// public UIElement AdornedElement { get { return _adornedElement; } - set { _adornedElement = value; } + } + + /// + /// Gets the design item adorned by this AdornerPanel. + /// + public DesignItem AdornedDesignItem { + get { return _adornedDesignItem; } + } + + /// + /// Sets the AdornedElement and AdornedDesignItem properties. + /// This method can be called only once. + /// + 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; } /// @@ -113,7 +135,7 @@ namespace ICSharpCode.WpfDesign.Adorners /// /// Describes where an Adorner is positioned on the Z-Layer. /// - public struct AdornerOrder : IComparable + public struct AdornerOrder : IComparable, IEquatable { /// /// The adorner is in the background layer. @@ -137,6 +159,25 @@ namespace ICSharpCode.WpfDesign.Adorners this.i = i; } + /// + public override int GetHashCode() + { + return i.GetHashCode(); + } + + /// + public override bool Equals(object obj) + { + if (!(obj is AdornerOrder)) return false; + return this == (AdornerOrder)obj; + } + + /// + public bool Equals(AdornerOrder other) + { + return i == other.i; + } + /// /// Compares the to another AdornerOrder. /// @@ -144,5 +185,17 @@ namespace ICSharpCode.WpfDesign.Adorners { return i.CompareTo(other.i); } + + /// + public static bool operator ==(AdornerOrder leftHandSide, AdornerOrder rightHandSide) + { + return leftHandSide.i == rightHandSide.i; + } + + /// + public static bool operator !=(AdornerOrder leftHandSide, AdornerOrder rightHandSide) + { + return leftHandSide.i != rightHandSide.i; + } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs index 21cf2ee181..a0f6cfde57 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs @@ -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(); avs.Adorners.Add(item); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignPanelHitTestResult.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignPanelHitTestResult.cs new file mode 100644 index 0000000000..c90c888ae1 --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignPanelHitTestResult.cs @@ -0,0 +1,109 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows.Media; +using ICSharpCode.WpfDesign.Adorners; + +namespace ICSharpCode.WpfDesign +{ + /// + /// Describes the result of a call. + /// + public struct DesignPanelHitTestResult : IEquatable + { + /// + /// Represents the result that nothing was hit. + /// + public static readonly DesignPanelHitTestResult NoHit = new DesignPanelHitTestResult(); + + readonly Visual _visualHit; + AdornerPanel _adornerHit; + DesignItem _modelHit; + + /// + /// The actual visual that was hit. + /// + public Visual VisualHit { + get { return _visualHit; } + } + + /// + /// The adorner panel containing the adorner that was hit. + /// + public AdornerPanel AdornerHit { + get { return _adornerHit; } + set { _adornerHit = value; } + } + + /// + /// The model item that was hit. + /// + public DesignItem ModelHit { + get { return _modelHit; } + set { _modelHit = value; } + } + + /// + /// Create a new DesignPanelHitTestResult instance. + /// + 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" declaration. + + /// + /// Tests if this hit test result equals the other result. + /// + public override bool Equals(object obj) + { + if (obj is DesignPanelHitTestResult) + return Equals((DesignPanelHitTestResult)obj); // use Equals method below + else + return false; + } + + /// + /// Tests if this hit test result equals the other result. + /// + public bool Equals(DesignPanelHitTestResult other) + { + // add comparisions for all members here + return _visualHit == other._visualHit && _adornerHit == other._adornerHit && _modelHit == other._modelHit; + } + + /// + /// Gets the hash code. + /// + 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); + } + + /// + public static bool operator ==(DesignPanelHitTestResult lhs, DesignPanelHitTestResult rhs) + { + return lhs.Equals(rhs); + } + + /// + public static bool operator !=(DesignPanelHitTestResult lhs, DesignPanelHitTestResult rhs) + { + return !(lhs.Equals(rhs)); // use operator == and negate result + } + #endregion + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs index b5890bad23..bed11c3355 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs @@ -95,13 +95,11 @@ namespace ICSharpCode.WpfDesign.Extensions /// /// Calls OnRemove() on the DefaultExtension. /// - [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(); } /// diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultInitializer.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultInitializer.cs new file mode 100644 index 0000000000..8c4d14092e --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultInitializer.cs @@ -0,0 +1,23 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace ICSharpCode.WpfDesign.Extensions +{ + /// + /// Base class for extensions that initialize new controls with default values. + /// + [ExtensionServer(typeof(NeverApplyExtensionsExtensionServer))] + public abstract class DefaultInitializer : Extension + { + /// + /// Initializes the design item to default values. + /// + public abstract void InitializeDefaults(DesignItem item); + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs index 0a0a49fedc..45d32cc198 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.WpfDesign.Extensions Debug.Assert(context != null); this._context = context; - context.Services.Subscribe( + context.Services.RunWhenAvailable( delegate(IComponentService componentService) { componentService.ComponentRegistered += OnComponentRegistered; }); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs index dcd8bec79e..ffed8a3a2c 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs @@ -61,6 +61,9 @@ namespace ICSharpCode.WpfDesign.PropertyEditor /// public static Type GetFallbackEditorType(IPropertyEditorDataProperty property) { + if (property == null) + throw new ArgumentNullException("property"); + Type returnType = property.ReturnType; if (returnType.IsEnum) { return typeof(StandardValuesComboBoxEditor); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs index a8274b6b56..9790eb8b18 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs @@ -19,6 +19,30 @@ namespace ICSharpCode.WpfDesign.PropertyEditor /// public static class PropertyEditorBindingHelper { + /// + /// Registers a value changed event handler for the data property that gets unregistered when the + /// editor FrameworkElement is unloaded. + /// + 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; + } + } + /// /// Binds editor.property to dataProperty.Value. /// diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs index 715f64a8be..fea166c141 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs @@ -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. /// - public void Subscribe(Action serviceAvailableAction) where T : class + public void RunWhenAvailable(Action serviceAvailableAction) where T : class { T service = GetService(); if (service != null) { @@ -124,6 +124,16 @@ namespace ICSharpCode.WpfDesign } } + /// + /// Gets the . + /// Throws an exception if the service is not found. + /// + public ViewService View { + get { + return GetServiceOrThrowException(); + } + } + /// /// Gets the . /// Throws an exception if the service is not found. diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs index c6f916327f..4ebf3511dc 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs @@ -11,36 +11,6 @@ using System.Windows; namespace ICSharpCode.WpfDesign { - #region IVisualDesignService - /// - /// A service that can visualize non-UIElement objects on a design surface. - /// - public interface IVisualDesignService - { - /// - /// Create an UIElement for visualizing the object specified by the design site. - /// - /// - /// Returns either an UIElement instance that also implements - /// , - /// or returns null to use the component itself as UIElement. - /// - UIElement CreateWrapper(DesignItem site); - } - - /// - /// Interface used by the for UIElements that - /// are inside the design surfaced but used only to represent a non-UIElement entity. - /// - public interface IVisualDesignObjectWrapper - { - /// - /// Gets the design site this object was wrapping. - /// - DesignItem WrappedSite { get; } - } - #endregion - #region ISelectionService /// /// Defines the type how a selection can be changed. @@ -151,4 +121,29 @@ namespace ICSharpCode.WpfDesign event EventHandler ComponentUnregistered; } #endregion + + #region IViewService + /// + /// Service for getting the view for a model or the model for a view. + /// + public abstract class ViewService + { + /// + /// Gets the model represented by the specified view element. + /// + public abstract DesignItem GetModel(DependencyObject view); + + /// + /// Gets the view for the specified model item. + /// This is equivalent to using model.View. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + public DependencyObject GetView(DesignItem model) + { + if (model == null) + throw new ArgumentNullException("model"); + return model.View; + } + } + #endregion } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs index d998a3597c..ee11ad506b 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs @@ -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 { - /// - /// Describes the layer of input handling. - /// When multiple actions are possible, that with the highest layer will be used. - /// - public enum InputHandlingLayer - { - /// - /// No layer specified. This layer is lower than all other layers. - /// - None, - /// - /// Layer used for passing the input to the component. - /// Normally never receives actions because there is always a . - /// - Component, - /// - /// Layer used for tools. - /// - Tool, - /// - /// Layer used for certain components that should get input, for example scroll thumbs - /// in user-defined ScrollViewers and the headers inside a TabControl. - /// - ComponentHigh, - /// - /// This value is used for mouse input on the adorner layer. - /// - Adorners, - /// - /// This layer is higher than all other layers. - /// - Highest - } - - /// - /// Interface for behavior extensions that specifies the input layer of the extended component. - /// - public interface IProvideComponentInputHandlingLayer - { - /// - /// Gets the input handling layer of the component. - /// - InputHandlingLayer InputLayer { get; } - } - /// /// 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 public interface ITool { /// - /// Gets the input handling layer of the tool. + /// Gets the cursor used by the tool. /// - InputHandlingLayer InputLayer { get; } + Cursor Cursor { get; } /// - /// Gets the cursor used by the tool. + /// Activates the tool, attaching its event handlers to the design panel. /// - Cursor Cursor { get; } + void Activate(IDesignPanel designPanel); /// - /// Notifies the tool of the MouseDown event. + /// Deactivates the tool, detaching its event handlers from the design panel. /// - void OnMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e); + void Deactivate(IDesignPanel designPanel); } /// @@ -109,35 +67,32 @@ namespace ICSharpCode.WpfDesign DesignContext Context { get; } /// - /// 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. /// - void StartInputAction(); + bool IsContentHitTestVisible { get; set; } /// - /// Stops an input action. This reenables input handling of + /// Gets/Sets if the adorner layer is visible for hit-testing purposes. /// - void StopInputAction(); - - /// - /// Finds the designed element for the specified original source. - /// - DesignItem FindDesignedElementForOriginalSource(object originalSource); + bool IsAdornerLayerHitTestVisible { get; set; } /// /// Gets the list of adorners displayed on the design panel. /// ICollection Adorners { get; } - /* /// /// 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. /// Canvas MarkerCanvas { get; } - */ - // The following members were missing in , but of course + /// + /// Performs a hit test on the design surface. + /// + DesignPanelHitTestResult HitTest(MouseEventArgs e, bool testAdorners, bool testDesignSurface); + + // The following members were missing in , but // are supported on the DesignPanel: /// diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj index 4442b43b5a..f5e22f8be8 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj @@ -64,12 +64,14 @@ + +