Browse Source

Add In-place editor, can edit any text in the designer which is wrapped under a TextBlock in the visual tree for example Window.Title, Button.Content, Label etc.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/wpfdesigner@5914 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Kumar Devvrat 16 years ago
parent
commit
e89cfde038
  1. 21
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/ControlStyles.xaml
  2. 131
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/InPlaceEditor.cs
  3. 176
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/InPlaceEditorExtension.cs
  4. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj

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

@ -469,5 +469,24 @@
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
<Style TargetType="{x:Type Controls:InPlaceEditor}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Controls:InPlaceEditor}">
<TextBox Name="editor"
SnapsToDevicePixels="True"
Padding="{Binding Path=Padding}"
FontSize="{Binding Path=FontSize}"
FontFamily="{Binding Path=FontFamily}"
FontStyle="{Binding Path=FontStyle}"
FontStretch="{Binding Path=FontStretch}"
FontWeight="{Binding Path=FontWight}"
Text="{Binding Path=Bind, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
AcceptsReturn="True"
MaxHeight="{Binding Path=Height, UpdateSourceTrigger=PropertyChanged}"
MaxWidth="{Binding Path=Width, UpdateSourceTrigger=PropertyChanged}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary> </ResourceDictionary>

131
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/InPlaceEditor.cs

@ -0,0 +1,131 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Kumar Devvrat"/>
// <version>$Revision: $</version>
// </file>
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
{
/// <summary>
/// Supports editing Text in the Designer
/// </summary>
public class InPlaceEditor : TextBox
{
static InPlaceEditor()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (InPlaceEditor), new FrameworkPropertyMetadata(typeof (InPlaceEditor)));
}
/// <summary>
/// This property is binded to the Text Property of the editor.
/// </summary>
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;
/// <summary>
/// This is the name of the property that is being edited for example Window.Title, Button.Content .
/// </summary>
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);
}
/// <summary>
/// Binds the Text Property of the element extended with <see cref="Bind"/>.
/// </summary>
/// <param name="textBlock"></param>
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);
}
/// <summary>
/// Returns the property that is being edited in the element for example editing Window Title returns "Title",
/// Button text as "Content".
/// </summary>
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);
}
/// <summary>
/// Change is committed if the user releases the Escape Key.
/// </summary>
/// <param name="e"></param>
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;
}
}
}
}

176
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/InPlaceEditorExtension.cs

@ -0,0 +1,176 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Kumar Devvrat"/>
// <version>$Revision: $</version>
// </file>
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
{
/// <summary>
/// Extends In-Place editor to edit any text in the designer which is wrapped in the Visual tree under TexBlock
/// </summary>
[ExtensionFor(typeof(FrameworkElement))]
public class InPlaceEditorExtension : PrimarySelectionAdornerProvider
{
AdornerPanel adornerPanel;
RelativePlacement placement;
InPlaceEditor editor;
/// <summary> Is the element in the Visual tree of the extended element which is being edited. </summary>
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<IDesignPanel>() 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;
}
/// <summary>
/// Checks whether heigth/width have changed and updates the position of editor
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
}
/// <summary>
/// Places the handle from a calculated offset using Mouse Positon
/// </summary>
/// <param name="text"></param>
/// <param name="e"></param>
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();
}
}
}

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

@ -92,6 +92,7 @@
<DependentUpon>GridUnitSelector.xaml</DependentUpon> <DependentUpon>GridUnitSelector.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Controls\InPlaceEditor.cs" />
<Compile Include="Controls\MarginHandle.cs" /> <Compile Include="Controls\MarginHandle.cs" />
<Compile Include="Controls\PanelMoveAdorner.cs" /> <Compile Include="Controls\PanelMoveAdorner.cs" />
<Compile Include="Controls\SelectionFrame.cs" /> <Compile Include="Controls\SelectionFrame.cs" />
@ -119,6 +120,7 @@
</Compile> </Compile>
<Compile Include="Extensions\GridAdornerProvider.cs" /> <Compile Include="Extensions\GridAdornerProvider.cs" />
<Compile Include="Extensions\GridPlacementSupport.cs" /> <Compile Include="Extensions\GridPlacementSupport.cs" />
<Compile Include="Extensions\InPlaceEditorExtension.cs" />
<Compile Include="Extensions\MarginHandleExtension.cs" /> <Compile Include="Extensions\MarginHandleExtension.cs" />
<Compile Include="Extensions\SizeDisplayExtension.cs" /> <Compile Include="Extensions\SizeDisplayExtension.cs" />
<Compile Include="Extensions\SnaplinePlacementBehavior.cs"> <Compile Include="Extensions\SnaplinePlacementBehavior.cs">

Loading…
Cancel
Save