/Application/GUI/Controls/Details.xaml.cs

http://yet-another-music-application.googlecode.com/ · C# · 492 lines · 300 code · 71 blank · 121 comment · 39 complexity · 06907485180f5c5b25de761e3dc6becd MD5 · raw file

  1. /**
  2. * Details.xaml.cs
  3. *
  4. * The details pane which shows an image, a title, a description
  5. * and a number of key-value fields.
  6. * It automatically hides fields that cannot be shown and supports
  7. * for in-place edit of certain fields.
  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. using System;
  22. using System.Collections.Generic;
  23. using System.Linq;
  24. using System.Text;
  25. using System.Windows;
  26. using System.Windows.Controls;
  27. using System.Windows.Data;
  28. using System.Windows.Documents;
  29. using System.Windows.Input;
  30. using System.Windows.Media;
  31. using System.Windows.Media.Imaging;
  32. using System.Windows.Navigation;
  33. using System.Windows.Shapes;
  34. using System.Windows.Controls.Primitives;
  35. namespace Stoffi
  36. {
  37. /// <summary>
  38. /// Details.xaml 的交互逻辑
  39. /// </summary>
  40. public partial class Details : StatusBar
  41. {
  42. #region Members
  43. private List<TextBlock> labels = new List<TextBlock>();
  44. private List<FrameworkElement> fields = new List<FrameworkElement>();
  45. private double cellWidth = 120;
  46. private double labelWidth = 80;
  47. private double cellHeight = 20;
  48. #endregion
  49. #region Properties
  50. /// <summary>
  51. /// The title of the item
  52. /// </summary>
  53. public string Title
  54. {
  55. get { return TitleBlock.Text; }
  56. set { TitleBlock.Text = value; }
  57. }
  58. /// <summary>
  59. /// A short description of the item
  60. /// </summary>
  61. public string Description
  62. {
  63. get { return DescrBlock.Text; }
  64. set { DescrBlock.Text = value; }
  65. }
  66. /// <summary>
  67. /// Sets the thumbnail image
  68. /// </summary>
  69. public ImageSource Image
  70. {
  71. get { return AlbumArt.Source; }
  72. set { AlbumArt.Source = value; }
  73. }
  74. #endregion
  75. #region Constructor
  76. /// <summary>
  77. /// Details Pane
  78. /// </summary>
  79. public Details()
  80. {
  81. U.L(LogLevel.Debug, "DETAILS", "Initialize");
  82. InitializeComponent();
  83. U.L(LogLevel.Debug, "DETAILS", "Initialized");
  84. FieldsGrid.RowDefinitions[0].Height = new GridLength(cellHeight);
  85. FieldsGrid.RowDefinitions[1].Height = new GridLength(cellHeight);
  86. FieldsGrid.ColumnDefinitions[0].Width = new GridLength(labelWidth);
  87. FieldsGrid.ColumnDefinitions[1].Width = new GridLength(cellWidth);
  88. if (System.Windows.Forms.VisualStyles.VisualStyleInformation.DisplayName == "")
  89. DescrBlock.Foreground = Brushes.Black;
  90. U.L(LogLevel.Debug, "DETAILS", "Created");
  91. }
  92. #endregion
  93. #region Methods
  94. #region Public
  95. /// <summary>
  96. /// Adds a text field
  97. /// </summary>
  98. /// <param name="name">The name of the field</param>
  99. /// <param name="value">The value of the field</param>
  100. /// <param name="editable">Whether the field can be edited</param>
  101. public void AddField(string name, string value, bool editable = false)
  102. {
  103. EditableTextBlock etb = new EditableTextBlock();
  104. etb.IsEditable = editable;
  105. etb.ClickToEdit = editable;
  106. etb.Text = value;
  107. etb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
  108. etb.Edited += new EditableTextBlockDelegate(Field_Edited);
  109. etb.EnteredEditMode += new EventHandler(Field_EnteredEditMode);
  110. AddField(name, etb);
  111. }
  112. /// <summary>
  113. /// Adds a rating field
  114. /// </summary>
  115. /// <param name="name">The name of the field</param>
  116. /// <param name="i">The rate value (0-10)</param>
  117. public void AddField(string name, int i)
  118. {
  119. // TODO: create rate control
  120. }
  121. /// <summary>
  122. /// Adds a field
  123. /// </summary>
  124. /// <param name="name">The name of the field</param>
  125. /// <param name="e">The object representing the value</param>
  126. public void AddField(string name, FrameworkElement e)
  127. {
  128. e.Tag = name;
  129. int col = (int)Math.Floor((double)fields.Count + 2) / FieldsGrid.RowDefinitions.Count;
  130. int row = fields.Count + 2 - col * FieldsGrid.RowDefinitions.Count;
  131. col *= 2;
  132. TextBlock label = new TextBlock();
  133. label.Text = name + ':';
  134. label.TextAlignment = TextAlignment.Right;
  135. label.VerticalAlignment = System.Windows.VerticalAlignment.Center;
  136. label.Margin = new Thickness(0, 0, 2, 0);
  137. label.Padding = new Thickness(0);
  138. if (System.Windows.Forms.VisualStyles.VisualStyleInformation.DisplayName != "")
  139. label.Foreground = new SolidColorBrush(Color.FromRgb(90, 103, 121));
  140. label.Tag = name;
  141. Grid.SetRow(label, row);
  142. Grid.SetColumn(label, col);
  143. e.Margin = new Thickness(2);
  144. e.Tag = name;
  145. Grid.SetRow(e, row);
  146. Grid.SetColumn(e, col + 1);
  147. if (col >= FieldsGrid.ColumnDefinitions.Count || row >= FieldsGrid.RowDefinitions.Count)
  148. {
  149. label.Visibility = System.Windows.Visibility.Collapsed;
  150. e.Visibility = System.Windows.Visibility.Collapsed;
  151. }
  152. FieldsGrid.Children.Add(label);
  153. labels.Add(label);
  154. FieldsGrid.Children.Add(e);
  155. fields.Add(e);
  156. RefreshGrid();
  157. }
  158. /// <summary>
  159. /// Removes a field
  160. /// </summary>
  161. /// <param name="name">The name of the field to remove</param>
  162. public void RemoveField(string name)
  163. {
  164. for (int i = 0; i < fields.Count; i++)
  165. {
  166. FrameworkElement e = fields[i];
  167. if ((string)e.Tag == name)
  168. {
  169. FieldsGrid.Children.Remove(e);
  170. fields.RemoveAt(i);
  171. i--;
  172. }
  173. }
  174. for (int i = 0; i < labels.Count; i++)
  175. {
  176. FrameworkElement e = fields[i];
  177. if ((string)e.Tag == name)
  178. {
  179. FieldsGrid.Children.Remove(e);
  180. labels.RemoveAt(i);
  181. i--;
  182. }
  183. }
  184. RefreshGrid();
  185. }
  186. /// <summary>
  187. /// Changes the value of a field
  188. /// </summary>
  189. /// <param name="name">The name of the field</param>
  190. /// <param name="value">The new value of the field</param>
  191. public void SetField(string name, string value)
  192. {
  193. foreach (FrameworkElement e in fields)
  194. {
  195. if (e.Tag as string == name && e is EditableTextBlock)
  196. (e as EditableTextBlock).Text = value;
  197. else if (e.Tag as string == name && e is TextBlock)
  198. (e as TextBlock).Text = value;
  199. }
  200. }
  201. /// <summary>
  202. /// Removes all fields and resets control
  203. /// </summary>
  204. public void Clear()
  205. {
  206. AlbumArt.Visibility = System.Windows.Visibility.Hidden;
  207. fields.Clear();
  208. labels.Clear();
  209. FieldsGrid.Children.Clear();
  210. Title = "";
  211. Description = "";
  212. FieldsGrid.Children.Add(TitleBlock);
  213. FieldsGrid.Children.Add(DescrBlock);
  214. RefreshGrid();
  215. }
  216. #endregion
  217. #region Private
  218. /// <summary>
  219. /// Refreshes the content inside the grid
  220. /// </summary>
  221. private void RefreshFields()
  222. {
  223. int i = 0;
  224. for (int col = 0; i < fields.Count && col < FieldsGrid.ColumnDefinitions.Count; col += 2) // double increase
  225. {
  226. for (int row = col == 0 ? 2 : 0; i < fields.Count && row < FieldsGrid.RowDefinitions.Count; row++, i++)
  227. {
  228. fields[i].Visibility = System.Windows.Visibility.Visible;
  229. labels[i].Visibility = System.Windows.Visibility.Visible;
  230. Grid.SetColumn(labels[i], col);
  231. Grid.SetRow(labels[i], row);
  232. Grid.SetColumn(fields[i], col + 1);
  233. Grid.SetRow(fields[i], row);
  234. }
  235. }
  236. while (i < fields.Count)
  237. {
  238. fields[i].Visibility = System.Windows.Visibility.Collapsed;
  239. labels[i].Visibility = System.Windows.Visibility.Collapsed;
  240. i++;
  241. }
  242. AlbumArt.Visibility = fields.Count > 0 ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden;
  243. }
  244. /// <summary>
  245. /// Refreshes the grids column and row configuration
  246. /// </summary>
  247. private void RefreshGrid()
  248. {
  249. #region Add columns
  250. int allowed = (int)Math.Floor(RightPart.RenderSize.Width / (cellWidth + labelWidth));
  251. int actual = FieldsGrid.ColumnDefinitions.Count / 2;
  252. if (allowed > actual)
  253. {
  254. int add = allowed - actual;
  255. for (int i = 0; i < add; i++)
  256. {
  257. FieldsGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(labelWidth) });
  258. FieldsGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(cellWidth) });
  259. RefreshFields();
  260. }
  261. }
  262. #endregion
  263. #region Remove columns
  264. if (actual > allowed)
  265. {
  266. int remove = actual - allowed;
  267. FieldsGrid.ColumnDefinitions.RemoveRange(
  268. FieldsGrid.ColumnDefinitions.Count - (remove*2), remove*2);
  269. }
  270. #endregion
  271. allowed = (int)Math.Floor(RightPart.RenderSize.Height / cellHeight);
  272. actual = FieldsGrid.RowDefinitions.Count;
  273. #region Add rows
  274. if (allowed > actual)
  275. {
  276. for (int i = 0; i < allowed - actual; i++)
  277. {
  278. int index = actual + i;
  279. double add = allowed;
  280. FieldsGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(cellHeight) });
  281. for (int j = 0; j < FieldsGrid.ColumnDefinitions.Count; j += 2)
  282. {
  283. TextBlock tb1 = new TextBlock()
  284. {
  285. Text = "Foo:",
  286. Background = Brushes.Blue,
  287. Margin = new Thickness(2),
  288. Width = labelWidth
  289. };
  290. TextBlock tb2 = new TextBlock()
  291. {
  292. Text = "Bar",
  293. Background = Brushes.Red,
  294. Margin = new Thickness(2),
  295. Width = cellWidth
  296. };
  297. Grid.SetColumn(tb1, j);
  298. Grid.SetColumn(tb2, j + 1);
  299. Grid.SetRow(tb1, FieldsGrid.RowDefinitions.Count - 1);
  300. Grid.SetRow(tb2, FieldsGrid.RowDefinitions.Count - 1);
  301. }
  302. }
  303. }
  304. #endregion
  305. #region Remove rows
  306. else if (allowed < actual)
  307. {
  308. int remove = actual - allowed;
  309. FieldsGrid.RowDefinitions.RemoveRange(
  310. FieldsGrid.RowDefinitions.Count - remove, remove);
  311. if (FieldsGrid.RowDefinitions.Count == 0)
  312. FieldsGrid.Children.Clear();
  313. }
  314. #endregion
  315. RefreshFields();
  316. }
  317. #endregion
  318. #region Event handlers
  319. /// <summary>
  320. /// Invoked when the size changes.
  321. /// Will add or remove rows or columns
  322. /// and call Refresh().
  323. /// </summary>
  324. /// <param name="sender">The sender of the event</param>
  325. /// <param name="e">The event data</param>
  326. private void Details_SizeChanged(object sender, SizeChangedEventArgs e)
  327. {
  328. RefreshGrid();
  329. }
  330. /// <summary>
  331. /// Invoked when a field has been edited
  332. /// </summary>
  333. /// <param name="sender">The sender of the event</param>
  334. /// <param name="e">The event data</param>
  335. private void Field_Edited(object sender, EditableTextBlockEventArgs e)
  336. {
  337. EditableTextBlock etb = sender as EditableTextBlock;
  338. OnFieldEdited(etb.Tag as string, e.NewText);
  339. }
  340. /// <summary>
  341. /// Invoked when a field enters edit mode
  342. /// </summary>
  343. /// <param name="sender">The sender of the event</param>
  344. /// <param name="e">The event data</param>
  345. private void Field_EnteredEditMode(object sender, EventArgs e)
  346. {
  347. OnEnteredEditMode(sender);
  348. }
  349. #endregion
  350. #region Dispatchers
  351. /// <summary>
  352. /// Dispatches the FieldEdited event
  353. /// </summary>
  354. /// <param name="name">The name of the field</param>
  355. /// <param name="value">The new value of the field</param>
  356. private void OnFieldEdited(string name, string value)
  357. {
  358. if (FieldEdited != null)
  359. FieldEdited(this, new FieldEditedEventArgs(name, value));
  360. }
  361. /// <summary>
  362. /// Dispatches the EnteredEditMode event
  363. /// </summary>
  364. /// <param name="etb">The object that sent the event</param>
  365. private void OnEnteredEditMode(object etb)
  366. {
  367. if (EnteredEditMode != null)
  368. EnteredEditMode(etb, new EventArgs());
  369. }
  370. #endregion
  371. #endregion
  372. #region Events
  373. /// <summary>
  374. /// Occurs when a field was edited
  375. /// </summary>
  376. public event FieldEditedEventHandler FieldEdited;
  377. /// <summary>
  378. /// Occurs when the control enters edit mode
  379. /// </summary>
  380. public event EventHandler EnteredEditMode;
  381. #endregion
  382. #region Delegates
  383. /// <summary>
  384. /// Represents the method that will handle the FieldEdited event.
  385. /// </summary>
  386. /// <param name="sender">The sender of the event</param>
  387. /// <param name="e">The event data</param>
  388. public delegate void FieldEditedEventHandler(object sender, FieldEditedEventArgs e);
  389. #endregion
  390. }
  391. #region Event arguments
  392. /// <summary>
  393. /// Provides data for the <see cref="Details.FieldEdited"/> event
  394. /// </summary>
  395. public class FieldEditedEventArgs : EventArgs
  396. {
  397. #region Properties
  398. /// <summary>
  399. /// Gets the name of the field
  400. /// </summary>
  401. public string Field { get; private set; }
  402. /// <summary>
  403. /// Gets the new value of the field
  404. /// </summary>
  405. public string Value { get; private set; }
  406. #endregion
  407. #region Constructor
  408. /// <summary>
  409. /// Initializes a new instance of the <see cref="FieldEditedEventArgs"/> class
  410. /// </summary>
  411. /// <param name="field">The name of the field</param>
  412. /// <param name="value">The new value of the field</param>
  413. public FieldEditedEventArgs(string field, string value)
  414. {
  415. Field = field;
  416. Value = value;
  417. }
  418. #endregion
  419. }
  420. #endregion
  421. }