1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
29 using System.ComponentModel;
30 using System.ComponentModel.Design;
32 using System.Drawing.Imaging;
33 using System.Runtime.InteropServices;
37 namespace System.Windows.Forms {
38 [DefaultProperty("Image")]
39 [Designer("System.Windows.Forms.Design.PictureBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
40 [Docking (DockingBehavior.Ask)]
41 [ClassInterface (ClassInterfaceType.AutoDispatch)]
43 [DefaultBindingProperty ("Image")]
44 public class PictureBox : Control, ISupportInitialize
48 private PictureBoxSizeMode size_mode;
49 private Image error_image;
50 private string image_location;
51 private Image initial_image;
52 private bool wait_on_load;
53 private WebClient image_download;
54 private bool image_from_url;
55 private int no_update;
58 private EventHandler frame_handler;
60 #region Public Constructor
66 SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
67 SetStyle (ControlStyles.Opaque, false);
68 SetStyle (ControlStyles.Selectable, false);
69 SetStyle (ControlStyles.SupportsTransparentBackColor, true);
70 HandleCreated += new EventHandler(PictureBox_HandleCreated);
71 initial_image = ResourceImageLoader.Get ("image-x-generic.png");
72 error_image = ResourceImageLoader.Get ("image-missing.png");
74 #endregion // Public Constructor
76 #region Public Properties
77 [DefaultValue(PictureBoxSizeMode.Normal)]
79 [RefreshProperties(RefreshProperties.Repaint)]
80 public PictureBoxSizeMode SizeMode {
81 get { return size_mode; }
83 if (size_mode == value)
87 if (size_mode == PictureBoxSizeMode.AutoSize) {
89 SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
92 SetAutoSizeMode (AutoSizeMode.GrowOnly);
100 OnSizeModeChanged (EventArgs.Empty);
107 get { return image; }
108 set { ChangeImage (value, false); }
111 [DefaultValue(BorderStyle.None)]
113 public BorderStyle BorderStyle {
114 get { return InternalBorderStyle; }
115 set { InternalBorderStyle = value; }
119 [EditorBrowsable(EditorBrowsableState.Never)]
120 public new bool CausesValidation {
121 get { return base.CausesValidation; }
122 set { base.CausesValidation = value; }
126 [RefreshProperties (RefreshProperties.All)]
127 public Image ErrorImage {
128 get { return error_image; }
129 set { error_image = value; }
132 [RefreshProperties (RefreshProperties.All)]
134 public Image InitialImage {
135 get { return initial_image; }
136 set { initial_image = value; }
140 [DefaultValue (null)]
141 [RefreshProperties (RefreshProperties.All)]
142 public string ImageLocation {
143 get { return image_location; }
145 image_location = value;
147 if (!string.IsNullOrEmpty (value)) {
152 } else if (image_from_url)
153 ChangeImage (null, true);
158 [DefaultValue (false)]
159 public bool WaitOnLoad {
160 get { return wait_on_load; }
161 set { wait_on_load = value; }
165 [EditorBrowsable(EditorBrowsableState.Never)]
166 public new ImeMode ImeMode {
167 get { return base.ImeMode; }
168 set { base.ImeMode = value; }
172 [EditorBrowsable(EditorBrowsableState.Never)]
173 public override RightToLeft RightToLeft {
174 get { return base.RightToLeft; }
175 set { base.RightToLeft = value; }
179 [EditorBrowsable(EditorBrowsableState.Never)]
180 public new int TabIndex {
181 get { return base.TabIndex; }
182 set { base.TabIndex = value; }
186 [EditorBrowsable(EditorBrowsableState.Never)]
187 public new bool TabStop {
188 get { return base.TabStop; }
189 set { base.TabStop = value; }
194 [EditorBrowsable(EditorBrowsableState.Never)]
195 public override string Text {
196 get { return base.Text; }
197 set { base.Text = value; }
200 protected override CreateParams CreateParams {
202 return base.CreateParams;
206 protected override ImeMode DefaultImeMode {
207 get { return base.DefaultImeMode; }
211 [EditorBrowsable(EditorBrowsableState.Never)]
212 public override Font Font {
213 get { return base.Font; }
214 set { base.Font = value; }
218 [EditorBrowsable(EditorBrowsableState.Never)]
219 public override Color ForeColor {
220 get { return base.ForeColor; }
221 set { base.ForeColor = value; }
225 [EditorBrowsable(EditorBrowsableState.Never)]
226 public override bool AllowDrop {
227 get { return base.AllowDrop; }
228 set { base.AllowDrop = value; }
230 #endregion // Public Properties
232 #region Protected Instance Methods
233 protected override Size DefaultSize {
234 get { return ThemeEngine.Current.PictureBoxDefaultSize; }
237 protected override void Dispose (bool disposing)
243 initial_image = null;
245 base.Dispose (disposing);
248 protected override void OnPaint (PaintEventArgs pe)
250 ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
254 protected override void OnVisibleChanged (EventArgs e)
256 base.OnVisibleChanged (e);
259 protected virtual void OnSizeModeChanged (EventArgs e)
261 EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]);
266 protected override void OnEnabledChanged (EventArgs e)
268 base.OnEnabledChanged (e);
271 [EditorBrowsable (EditorBrowsableState.Advanced)]
272 protected override void OnHandleCreated (EventArgs e)
274 base.OnHandleCreated (e);
277 [EditorBrowsable (EditorBrowsableState.Advanced)]
278 protected override void OnHandleDestroyed (EventArgs e)
280 base.OnHandleDestroyed (e);
283 protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e)
285 AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]);
290 protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e)
292 ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]);
297 protected override void OnParentChanged (EventArgs e)
299 base.OnParentChanged (e);
302 protected override void OnResize (EventArgs e)
309 internal override Size GetPreferredSizeCore (Size proposedSize)
312 return base.GetPreferredSizeCore (proposedSize);
316 #endregion // Protected Instance Methods
318 #region ISupportInitialize Interface
319 void System.ComponentModel.ISupportInitialize.BeginInit() {
323 void System.ComponentModel.ISupportInitialize.EndInit() {
327 if (no_update == 0) {
331 #endregion // ISupportInitialize Interface
333 #region Private Properties
334 private WebClient ImageDownload {
336 if (image_download == null)
337 image_download = new WebClient ();
339 return image_download;
344 #region Private Methods
346 private void ChangeImage (Image value, bool from_url)
350 image_from_url = from_url;
353 if (IsHandleCreated) {
355 if (image != null && ImageAnimator.CanAnimate (image)) {
356 frame_handler = new EventHandler (OnAnimateImage);
357 ImageAnimator.Animate (image, frame_handler);
359 if (no_update == 0) {
365 private void StopAnimation ()
367 if (frame_handler == null)
369 ImageAnimator.StopAnimate (image, frame_handler);
370 frame_handler = null;
373 private void UpdateSize ()
379 Parent.PerformLayout (this, "AutoSize");
382 private void OnAnimateImage (object sender, EventArgs e)
384 // This is called from a worker thread,BeginInvoke is used
385 // so the control is updated from the correct thread
387 // Check if we have a handle again, since it may have gotten
388 // destroyed since the last time we checked.
389 if (!IsHandleCreated)
392 BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e });
395 private void UpdateAnimatedImage (object sender, EventArgs e)
397 // Check if we have a handle again, since it may have gotten
398 // destroyed since the last time we checked.
399 if (!IsHandleCreated)
402 ImageAnimator.UpdateFrames (image);
406 private void PictureBox_HandleCreated(object sender, EventArgs e) {
408 if (image != null && ImageAnimator.CanAnimate (image)) {
409 frame_handler = new EventHandler (OnAnimateImage);
410 ImageAnimator.Animate (image, frame_handler);
412 if (no_update == 0) {
417 void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e)
419 if (e.Error != null && !e.Cancelled)
421 else if (e.Error == null && !e.Cancelled)
422 using (MemoryStream ms = new MemoryStream (e.Result))
423 Image = Image.FromStream (ms);
425 ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
426 ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
427 image_download = null;
432 private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e)
434 OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState));
436 #endregion // Private Methods
438 #region Public Instance Methods
439 public void CancelAsync ()
441 if (image_download != null)
442 image_download.CancelAsync ();
447 Load (image_location);
450 public void Load (string url)
452 if (string.IsNullOrEmpty (url))
453 throw new InvalidOperationException ("ImageLocation not specified.");
455 image_location = url;
457 if (url.Contains ("://"))
458 using (Stream s = ImageDownload.OpenRead (url))
459 ChangeImage (Image.FromStream (s), true);
461 ChangeImage (Image.FromFile (url), true);
464 public void LoadAsync ()
466 LoadAsync (image_location);
469 public void LoadAsync (string url)
471 // If WaitOnLoad is true, do not do async
477 if (string.IsNullOrEmpty (url))
478 throw new InvalidOperationException ("ImageLocation not specified.");
480 image_location = url;
481 ChangeImage (InitialImage, true);
483 if (ImageDownload.IsBusy)
484 ImageDownload.CancelAsync ();
489 } catch (UriFormatException) {
490 uri = new Uri (Path.GetFullPath (url));
493 ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
494 ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
495 ImageDownload.DownloadDataAsync (uri);
498 public override string ToString() {
499 return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode);
505 [EditorBrowsable(EditorBrowsableState.Never)]
506 public new event EventHandler CausesValidationChanged {
507 add { base.CausesValidationChanged += value; }
508 remove { base.CausesValidationChanged -= value; }
512 [EditorBrowsable(EditorBrowsableState.Never)]
513 public new event EventHandler Enter {
514 add { base.Enter += value; }
515 remove { base.Enter -= value; }
519 [EditorBrowsable(EditorBrowsableState.Never)]
520 public new event EventHandler FontChanged {
521 add { base.FontChanged += value; }
522 remove { base.FontChanged -= value; }
526 [EditorBrowsable(EditorBrowsableState.Never)]
527 public new event EventHandler ForeColorChanged {
528 add { base.ForeColorChanged += value; }
529 remove { base.ForeColorChanged -= value; }
533 [EditorBrowsable(EditorBrowsableState.Never)]
534 public new event EventHandler ImeModeChanged {
535 add { base.ImeModeChanged += value; }
536 remove { base.ImeModeChanged -= value; }
540 [EditorBrowsable(EditorBrowsableState.Never)]
541 public new event KeyEventHandler KeyDown {
542 add { base.KeyDown += value; }
543 remove { base.KeyDown -= value; }
547 [EditorBrowsable(EditorBrowsableState.Never)]
548 public new event KeyPressEventHandler KeyPress {
549 add { base.KeyPress += value; }
550 remove { base.KeyPress -= value; }
554 [EditorBrowsable(EditorBrowsableState.Never)]
555 public new event KeyEventHandler KeyUp {
556 add { base.KeyUp += value; }
557 remove { base.KeyUp -= value; }
561 [EditorBrowsable(EditorBrowsableState.Never)]
562 public new event EventHandler Leave {
563 add { base.Leave += value; }
564 remove { base.Leave -= value; }
567 static object LoadCompletedEvent = new object ();
568 static object LoadProgressChangedEvent = new object ();
570 public event AsyncCompletedEventHandler LoadCompleted {
571 add { Events.AddHandler (LoadCompletedEvent, value); }
572 remove { Events.RemoveHandler (LoadCompletedEvent, value); }
575 public event ProgressChangedEventHandler LoadProgressChanged {
576 add { Events.AddHandler (LoadProgressChangedEvent, value); }
577 remove { Events.RemoveHandler (LoadProgressChangedEvent, value); }
581 [EditorBrowsable(EditorBrowsableState.Never)]
582 public new event EventHandler RightToLeftChanged {
583 add { base.RightToLeftChanged += value; }
584 remove { base.RightToLeftChanged -= value; }
588 [EditorBrowsable(EditorBrowsableState.Never)]
589 public new event EventHandler TabIndexChanged {
590 add { base.TabIndexChanged += value; }
591 remove { base.TabIndexChanged -= value; }
595 [EditorBrowsable(EditorBrowsableState.Never)]
596 public new event EventHandler TabStopChanged {
597 add { base.TabStopChanged += value; }
598 remove { base.TabStopChanged -= value; }
602 [EditorBrowsable(EditorBrowsableState.Never)]
603 public new event EventHandler TextChanged {
604 add { base.TextChanged += value; }
605 remove { base.TextChanged -= value; }
608 static object SizeModeChangedEvent = new object ();
609 public event EventHandler SizeModeChanged {
610 add { Events.AddHandler (SizeModeChangedEvent, value); }
611 remove { Events.RemoveHandler (SizeModeChangedEvent, value); }