PageRenderTime 31ms CodeModel.GetById 17ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Application/GUI/Controls/EditableTextBlock.xaml.cs

http://yet-another-music-application.googlecode.com/
C# | 465 lines | 237 code | 67 blank | 161 comment | 20 complexity | 5e818c240ad0d4ee8f522b976979650c MD5 | raw file
  1/**
  2 * EditableTextBlock.xaml.cs
  3 * 
  4 * A custom textblock that can be turned into a textbox for
  5 * editing. This code was originally written by Jesper Borgstrup
  6 * and can be found at
  7 * http://www.codeproject.com/KB/WPF/editabletextblock.aspx
  8 * 
  9 * * * * * * * * *
 10 * 
 11 * This code is part of the Stoffi Music Player Project.
 12 * Visit our website at: stoffiplayer.com
 13 *
 14 * This program is free software; you can redistribute it and/or
 15 * modify it under the terms of the GNU General Public License
 16 * as published by the Free Software Foundation; either version
 17 * 3 of the License, or (at your option) any later version.
 18 * 
 19 * See stoffiplayer.com/license for more information.
 20 **/
 21
 22using System;
 23using System.Collections.Generic;
 24using System.ComponentModel;
 25using System.Linq;
 26using System.Text;
 27using System.Windows;
 28using System.Windows.Controls;
 29using System.Windows.Data;
 30using System.Windows.Documents;
 31using System.Windows.Input;
 32using System.Windows.Media;
 33using System.Windows.Media.Imaging;
 34using System.Windows.Navigation;
 35using System.Windows.Shapes;
 36using System.Windows.Threading;
 37
 38namespace Stoffi
 39{
 40	/// <summary>
 41	/// 
 42	/// </summary>
 43	public partial class EditableTextBlock : UserControl, INotifyPropertyChanged
 44	{
 45
 46		#region Members
 47
 48		// We keep the old text when we go into editmode
 49		// in case the user aborts with the escape key
 50		private string oldText;
 51
 52		private bool clickToEdit = false;
 53
 54		#endregion
 55
 56		#region Properties
 57
 58		/// <summary>
 59		/// Gets current text of the text box
 60		/// </summary>
 61		public string CurrentText { get; private set; }
 62
 63		/// <summary>
 64		/// Gets or sets the text value
 65		/// </summary>
 66		public string Text
 67		{
 68			get { return (string)GetValue(TextProperty); }
 69			set { SetValue(TextProperty, value); OnPropertyChanged("Text"); OnPropertyChanged("FormattedText"); }
 70		}
 71
 72		/// <summary>
 73		/// The text property of the control
 74		/// </summary>
 75		public static readonly DependencyProperty TextProperty =
 76			DependencyProperty.Register(
 77			"Text",
 78			typeof(string),
 79			typeof(EditableTextBlock),
 80			new PropertyMetadata(""));
 81
 82		/// <summary>
 83		/// Gets or sets whether the control is editable
 84		/// </summary>
 85		public bool IsEditable
 86		{
 87			get { return (bool)GetValue(IsEditableProperty); }
 88			set { SetValue(IsEditableProperty, value); }
 89		}
 90
 91		/// <summary>
 92		/// The property describing whether the control is editable
 93		/// </summary>
 94		public static readonly DependencyProperty IsEditableProperty =
 95			DependencyProperty.Register(
 96			"IsEditable",
 97			typeof(bool),
 98			typeof(EditableTextBlock),
 99			new PropertyMetadata(true));
100
101		/// <summary>
102		/// Gets or sets whether the control is in edit mode
103		/// Note: Must be editable for this to take effect
104		/// </summary>
105		public bool IsInEditMode
106		{
107			get
108			{
109				if (IsEditable)
110					return (bool)GetValue(IsInEditModeProperty);
111				else
112					return false;
113			}
114			set
115			{
116				if (IsEditable)
117				{
118					if (value)
119					{
120						oldText = Text;
121						DispatchEnteredEditMode();
122					}
123					U.ListenForShortcut = !value;
124					SetValue(IsInEditModeProperty, value);
125				}
126			}
127		}
128
129		/// <summary>
130		/// The property describing whether the control is in edit mode
131		/// </summary>
132		public static readonly DependencyProperty IsInEditModeProperty =
133			DependencyProperty.Register(
134			"IsInEditMode",
135			typeof(bool),
136			typeof(EditableTextBlock),
137			new PropertyMetadata(false));
138
139		/// <summary>
140		/// Gets or sets the format of the text
141		/// </summary>
142		public string TextFormat
143		{
144			get { return (string)GetValue(TextFormatProperty); }
145			set
146			{
147				if (value == "") value = "{0}";
148				SetValue(TextFormatProperty, value);
149			}
150		}
151
152		/// <summary>
153		/// The property describing the format of the text value
154		/// </summary>
155		public static readonly DependencyProperty TextFormatProperty =
156			DependencyProperty.Register(
157			"TextFormat",
158			typeof(string),
159			typeof(EditableTextBlock),
160			new PropertyMetadata("{0}"));
161
162		/// <summary>
163		/// Gets the formatted text value
164		/// </summary>
165		public string FormattedText
166		{
167			get { return String.Format(TextFormat, Text); }
168		}
169
170		/// <summary>
171		/// Gets or sets whether the user can initiate
172		/// edit mode by clicking on the text.
173		/// </summary>
174		public bool ClickToEdit
175		{
176			get { return clickToEdit; }
177			set { clickToEdit = value; }
178		}
179
180		/// <summary>
181		/// Gets or sets whether the hover effect is a simple black
182		/// line (true) or if it looks similar to a textbox (false).
183		/// </summary>
184		public bool SimpleHover { get; set; }
185
186		#endregion PropertiesWindow
187
188		#region Constructor
189
190		/// <summary>
191		/// Creates an editable text block
192		/// </summary>
193		public EditableTextBlock()
194		{
195			ClickToEdit = false;
196			SimpleHover = true;
197			InitializeComponent();
198			base.Focusable = true;
199			base.FocusVisualStyle = null;
200		}
201
202		#endregion Constructor
203
204		#region Methods
205
206		#region Public
207
208		/// <summary>
209		/// Cancels the edit
210		/// </summary>
211		public void Cancel()
212		{
213			Text = oldText;
214			this.IsInEditMode = false;
215			DispatchCanceledEvent();
216		}
217
218		/// <summary>
219		/// Ends the edit successfully
220		/// </summary>
221		public void Done()
222		{
223			this.IsInEditMode = false;
224			DispatchEditedEvent(CurrentText, oldText);
225		}
226
227		#endregion
228
229		#region Event handlers
230
231		/// <summary>
232		/// Invoked when we enter edit mode.
233		/// </summary>
234		/// <param name="sender">The sender of the event</param>
235		/// <param name="e">The event data</param>
236		private void TextBox_Loaded(object sender, RoutedEventArgs e)
237		{		
238			TextBox txt = sender as TextBox;
239			txt.Text = Text;
240			CurrentText = Text;
241
242			// Give the TextBox input focus
243			txt.Focus();
244
245			txt.SelectAll();
246		}
247
248		/// <summary>
249		///  Invoked when we exit edit mode.
250		/// </summary>
251		/// <param name="sender">The sender of the event</param>
252		/// <param name="e">The event data</param>
253		private void TextBox_LostFocus(object sender, RoutedEventArgs e)
254		{
255			if (this.IsInEditMode)
256				Done();
257		}
258
259		/// <summary>
260		/// Invoked when the user edits the annotation.
261		/// </summary>
262		/// <param name="sender">The sender of the event</param>
263		/// <param name="e">The event data</param>
264		private void TextBox_KeyUp(object sender, KeyEventArgs e)
265		{
266			if (e.Key == Key.Enter)
267			{
268				Done();
269				e.Handled = true;
270			}
271			else if (e.Key == Key.Escape)
272			{
273				Cancel();
274				e.Handled = true;
275			}
276			else
277			{
278				TextBox txt = sender as TextBox;
279				CurrentText = txt.Text;
280			}
281		}
282
283		/// <summary>
284		/// Invoked when the user clicks on the control.
285		/// Will enter edit mode if ClickToEdit is true.
286		/// </summary>
287		/// <param name="sender">The sender of the event</param>
288		/// <param name="e">The event data</param>
289		private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
290		{
291			IsInEditMode = (!IsInEditMode && ClickToEdit);
292		}
293
294		#endregion Event Handlers
295
296		#endregion
297
298		#region Events
299
300		/// <summary>
301		/// Occurs when the control is edited succesfully
302		/// </summary>
303		public event EditableTextBlockDelegate Edited;
304		
305		/// <summary>
306		/// Occurs when the edit is canceled
307		/// </summary>
308		public event EditableTextBlockCanceledDelegate Canceled;
309
310		/// <summary>
311		/// Occurs when the control enters edit mode
312		/// </summary>
313		public event EventHandler EnteredEditMode;
314
315		/// <summary>
316		/// The dispatcher for the EnteredEditMode event
317		/// </summary>
318		private void DispatchEnteredEditMode()
319		{
320			if (EnteredEditMode != null)
321			{
322				EnteredEditMode(this, null);
323			}
324		}
325
326		/// <summary>
327		/// The subscriber for the edited event
328		/// </summary>
329		/// <param name="eventHandler">The event handler</param>
330		private void SubscribeEdited(EditableTextBlockDelegate eventHandler)
331		{
332			Edited += eventHandler;
333		}
334
335		/// <summary>
336		/// The unsubscriber for the edited event
337		/// </summary>
338		/// <param name="eventHandler">The event handler</param>
339		private void UnsubsribeEdited(EditableTextBlockDelegate eventHandler)
340		{
341			Edited -= eventHandler;
342		}
343
344		/// <summary>
345		/// The dispatcher for the edit event
346		/// </summary>
347		/// <param name="ntxt">The new text value</param>
348		/// <param name="otxt">The old text value</param>
349		private void DispatchEditedEvent(string ntxt, string otxt)
350		{
351			if (Edited != null)
352			{
353				Edited(this, new EditableTextBlockEventArgs(ntxt,otxt));
354			}
355		}
356
357		/// <summary>
358		/// The subscriber for the canceled event
359		/// </summary>
360		/// <param name="eventHandler">The event handler</param>
361		private void SubscribeCanceled(EditableTextBlockDelegate eventHandler)
362		{
363			Edited += eventHandler;
364		}
365
366		/// <summary>
367		/// The unsubscriber for the canceled event
368		/// </summary>
369		/// <param name="eventHandler">The event handler</param>
370		private void UnsubsribeCanceled(EditableTextBlockDelegate eventHandler)
371		{
372			Edited -= eventHandler;
373		}
374
375		/// <summary>
376		/// The dispatcher for the canceled event
377		/// </summary>
378		private void DispatchCanceledEvent()
379		{
380			if (Canceled != null)
381			{
382				Canceled(new EventArgs());
383			}
384		}
385
386		#endregion
387
388		#region INotifyPropertyChanged Members
389
390		/// <summary>
391		/// 
392		/// </summary>
393		public event PropertyChangedEventHandler PropertyChanged;
394
395		/// <summary>
396		/// 
397		/// </summary>
398		/// <param name="name"></param>
399		public void OnPropertyChanged(string name)
400		{
401			if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
402		}
403
404		#endregion
405	}
406
407	/// <summary>
408	/// Provides data for the <see cref="EditableTextBlock.Edited"/> event
409	/// </summary>
410	public class EditableTextBlockEventArgs : EventArgs
411	{
412		#region Members
413
414		private string newText;
415		private string oldText;
416
417		#endregion
418
419		#region Properties
420
421		/// <summary>
422		/// The new text value
423		/// </summary>
424		public string NewText { get { return newText; } }
425		
426		/// <summary>
427		/// The old text value
428		/// </summary>
429		public string OldText { get { return oldText; } }
430
431		#endregion
432
433		#region Constructor
434
435		/// <summary>
436		/// Initializes a new instance of the <see cref="EditableTextBlockEventArgs"/> class
437		/// </summary>
438		/// <param name="ntxt">The new text value</param>
439		/// <param name="otxt">The old text value</param>
440		public EditableTextBlockEventArgs(string ntxt, string otxt)
441		{
442			newText = ntxt;
443			oldText = otxt;
444		}
445
446		#endregion
447	}
448
449	#region Events
450
451	/// <summary>
452	/// Represents the method that will handle the <see cref="EditableTextBlock.Edited"/> event.
453	/// </summary>
454	/// <param name="e">The event arguments</param>
455	/// <param name="sender">The sender of the event</param>
456	public delegate void EditableTextBlockDelegate(object sender, EditableTextBlockEventArgs e);
457
458	/// <summary>
459	/// Represents the method that will handle the <see cref="EditableTextBlock.Canceled"/> event.
460	/// </summary>
461	/// <param name="e">The event arguments</param>
462	public delegate void EditableTextBlockCanceledDelegate(EventArgs e);
463
464	#endregion
465}