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 f4bf3ef69d..0bf159a3fb 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml @@ -469,5 +469,24 @@ - + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/InPlaceEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/InPlaceEditor.cs new file mode 100644 index 0000000000..2b819a068c --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/InPlaceEditor.cs @@ -0,0 +1,131 @@ +// +// +// +// +// $Revision: $ +// + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup.Primitives; +using System.Windows.Controls; +using System.Windows.Input; + +namespace ICSharpCode.WpfDesign.Designer.Controls +{ + /// + /// Supports editing Text in the Designer + /// + public class InPlaceEditor : TextBox + { + static InPlaceEditor() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof (InPlaceEditor), new FrameworkPropertyMetadata(typeof (InPlaceEditor))); + } + + /// + /// This property is binded to the Text Property of the editor. + /// + public static readonly DependencyProperty BindProperty = + DependencyProperty.Register("Bind", typeof (string), typeof (InPlaceEditor), new FrameworkPropertyMetadata()); + + public string Bind{ + get { return (string) GetValue(BindProperty); } + set { SetValue(BindProperty, value); } + } + + readonly DesignItem designItem; + ChangeGroup changeGroup; + TextBlock textBlock; + TextBox editor; + + /// + /// This is the name of the property that is being edited for example Window.Title, Button.Content . + /// + string property; + + public InPlaceEditor(DesignItem designItem) + { + this.designItem=designItem; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + editor = new TextBox(); + editor = Template.FindName("editor", this) as TextBox; // Gets the TextBox-editor from the Template + Debug.Assert(editor != null); + } + + /// + /// Binds the Text Property of the element extended with . + /// + /// + public void SetBinding(TextBlock textBlock) + { + Debug.Assert(textBlock!=null); + this.textBlock = textBlock; + Binding binding = new Binding("Text"); + binding.Source = this.textBlock; + binding.Mode = BindingMode.TwoWay; + SetBinding(BindProperty, binding); + property=PropertyUpdated(textBlock); + } + + /// + /// Returns the property that is being edited in the element for example editing Window Title returns "Title", + /// Button text as "Content". + /// + private string PropertyUpdated(TextBlock text) + { + MarkupObject obj = MarkupWriter.GetMarkupObjectFor(designItem.Component); + foreach (MarkupProperty property in obj.Properties) { + if (property.DependencyProperty != null && property.StringValue == textBlock.Text) + return property.Name; + } + return null; + } + + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + base.OnGotKeyboardFocus(e); + changeGroup = designItem.OpenGroup("Change Text"); + editor.Focus(); + } + + protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + if (changeGroup != null) + changeGroup.Abort(); + base.OnLostKeyboardFocus(e); + } + + /// + /// Change is committed if the user releases the Escape Key. + /// + /// + protected override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + if (e.Key == Key.Escape) { + // Commit the changes to the DOM + if(property!=null) + designItem.Properties[property].SetValue(Bind); + designItem.Properties[Control.FontFamilyProperty].SetValue(editor.FontFamily); + designItem.Properties[Control.FontSizeProperty].SetValue(editor.FontSize); + designItem.Properties[Control.FontStretchProperty].SetValue(editor.FontStretch); + designItem.Properties[Control.FontStyleProperty].SetValue(editor.FontStyle); + designItem.Properties[Control.FontWeightProperty].SetValue(editor.FontWeight); + + if (changeGroup != null) + changeGroup.Commit(); + changeGroup = null; + this.Visibility = Visibility.Hidden; + textBlock.Visibility = Visibility.Visible; + } + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/InPlaceEditorExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/InPlaceEditorExtension.cs new file mode 100644 index 0000000000..e9c2bf1cdb --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/InPlaceEditorExtension.cs @@ -0,0 +1,176 @@ +// +// +// +// +// $Revision: $ +// + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Media; +using System.Windows.Input; +using System.Windows.Controls; + +using ICSharpCode.WpfDesign.Adorners; +using ICSharpCode.WpfDesign.Extensions; +using ICSharpCode.WpfDesign.Designer.Controls; + +namespace ICSharpCode.WpfDesign.Designer.Extensions +{ + /// + /// Extends In-Place editor to edit any text in the designer which is wrapped in the Visual tree under TexBlock + /// + [ExtensionFor(typeof(FrameworkElement))] + public class InPlaceEditorExtension : PrimarySelectionAdornerProvider + { + AdornerPanel adornerPanel; + RelativePlacement placement; + InPlaceEditor editor; + /// Is the element in the Visual tree of the extended element which is being edited. + TextBlock textBlock; + FrameworkElement element; + DesignPanel designPanel; + + bool isGettingDragged; // Flag to get/set whether the extended element is dragged. + bool isMouseDown; // Flag to get/set whether left-button is down on the element. + int numClicks; // No of left-button clicks on the element. + + public InPlaceEditorExtension() + { + adornerPanel=new AdornerPanel(); + isGettingDragged=false; + isMouseDown=Mouse.LeftButton==MouseButtonState.Pressed ? true : false; + numClicks=0; + } + + protected override void OnInitialized() + { + base.OnInitialized(); + element = ExtendedItem.Component as FrameworkElement; + editor = new InPlaceEditor(ExtendedItem); + editor.DataContext = element; + editor.Visibility = Visibility.Hidden; // Hide the editor first, It's visibility is governed by mouse events. + + placement = new RelativePlacement(HorizontalAlignment.Left, VerticalAlignment.Top); + adornerPanel.Children.Add(editor); + Adorners.Add(adornerPanel); + + designPanel = ExtendedItem.Services.GetService() as DesignPanel; + Debug.Assert(designPanel!=null); + + /* Add mouse event handlers */ + designPanel.PreviewMouseLeftButtonDown += MouseDown; + designPanel.PreviewMouseLeftButtonUp += MouseUp; + designPanel.PreviewMouseMove += MouseMove; + + /* To update the position of Editor in case of resize operation */ + ExtendedItem.PropertyChanged += PropertyChanged; + } + + /// + /// Checks whether heigth/width have changed and updates the position of editor + /// + /// + /// + void PropertyChanged(object sender,PropertyChangedEventArgs e) + { + if (textBlock != null) { + if (e.PropertyName == "Width") + placement.XOffset = Mouse.GetPosition((IInputElement) element).X - Mouse.GetPosition(textBlock).X; + if (e.PropertyName == "Height") + placement.YOffset = Mouse.GetPosition((IInputElement) element).Y - Mouse.GetPosition(textBlock).Y; + AdornerPanel.SetPlacement(editor, placement); + } + } + + /// + /// Places the handle from a calculated offset using Mouse Positon + /// + /// + /// + void PlaceEditor(Visual text,MouseEventArgs e) + { + textBlock = text as TextBlock; + Debug.Assert(textBlock!=null); + + /* Gets the offset between the top-left corners of the element and the editor*/ + placement.XOffset = e.GetPosition(element).X - e.GetPosition(textBlock).X; + placement.YOffset = e.GetPosition(element).Y - e.GetPosition(textBlock).Y; + placement.XRelativeToAdornerWidth = 0; + placement.XRelativeToContentWidth = 0; + placement.YRelativeToAdornerHeight = 0; + placement.YRelativeToContentHeight = 0; + editor.SetBinding(textBlock); + + /* Change data context of the editor to the TextBlock */ + editor.DataContext=textBlock; + + /* Hides the TextBlock in control because of some minor offset in placement, overlaping makes text look fuzzy */ + textBlock.Visibility = Visibility.Hidden; // + AdornerPanel.SetPlacement(editor, placement); + } + + #region MouseEvents + DesignPanelHitTestResult result; + Point Current; + Point Start; + + void MouseDown(object sender,MouseEventArgs e) + { + result = designPanel.HitTest(e.GetPosition(designPanel), false, true); + if(result.ModelHit==ExtendedItem && result.VisualHit is TextBlock) { + Start = Mouse.GetPosition(null); + Current = Start; + isMouseDown = true; + } + numClicks++; + } + + void MouseMove(object sender, MouseEventArgs e) + { + Current += e.GetPosition(null) - Start; + result = designPanel.HitTest(e.GetPosition(designPanel), false, true); + if (result.ModelHit == ExtendedItem && result.VisualHit is TextBlock) { + if (numClicks > 0) { + if (isMouseDown && + ((Current-Start).X > SystemParameters.MinimumHorizontalDragDistance + || (Current-Start).Y > SystemParameters.MinimumVerticalDragDistance)) { + + isGettingDragged = true; + editor.Focus(); + } + } + } + } + + void MouseUp(object sender,MouseEventArgs e) + { + result = designPanel.HitTest(e.GetPosition(designPanel), false, true); + if (result.ModelHit == ExtendedItem && result.VisualHit is TextBlock && numClicks>0){ + if (!isGettingDragged) { + PlaceEditor(result.VisualHit, e); + editor.Visibility = Visibility.Visible; + } + }else{ // Clicked outside the Text - > hide the editor and make the actualt text visible again + editor.Visibility = Visibility.Hidden; + if (textBlock != null) textBlock.Visibility = Visibility.Visible; + } + + isMouseDown = false; + isGettingDragged = false; + } + + #endregion + + protected override void OnRemove() + { + ExtendedItem.PropertyChanged -= PropertyChanged; + designPanel.PreviewMouseLeftButtonDown -= MouseDown; + designPanel.PreviewMouseMove -= MouseMove; + designPanel.PreviewMouseLeftButtonUp -= MouseUp; + base.OnRemove(); + } + } +} 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 6e82103add..98dce7957b 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj @@ -92,6 +92,7 @@ GridUnitSelector.xaml Code + @@ -119,6 +120,7 @@ +