/Application/GUI/Controls/EditableTextBlock.xaml.cs
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}