1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
26 using System.Windows.Forms;
27 using System.ComponentModel;
29 using System.Threading.Tasks;
30 using System.Threading;
36 public class OTPictureBox : PictureBox
39 public new Image Image
41 get { return base.Image; }
45 this.SizeMode = this._SizeMode;
46 if (this.memoryImage != null)
48 this.memoryImage.Dispose();
49 this.memoryImage = null;
55 public new string ImageLocation
57 get { return this._ImageLocation; }
65 this.LoadAsync(value);
68 private string _ImageLocation;
71 /// 画像に応じた SizeMode を取得・設定する
74 /// ErrorImage と InitialImage は SizeMode の値に依らず中央等倍に表示する必要があるため、
75 /// 画像に応じて SizeMode の状態を弄る
77 public new PictureBoxSizeMode SizeMode
79 get { return this._SizeMode; }
82 this._SizeMode = value;
83 if (base.Image == null || (base.Image != base.ErrorImage && base.Image != base.InitialImage))
85 base.SizeMode = value;
89 base.SizeMode = PictureBoxSizeMode.CenterImage;
93 private PictureBoxSizeMode _SizeMode;
96 /// ImageLocation によりロードされた画像
98 private MemoryImage memoryImage = null;
100 private Task loadAsyncTask = null;
101 private CancellationTokenSource loadAsyncCancelTokenSource = null;
103 public new Task LoadAsync(string url)
105 this._ImageLocation = url;
107 if (this.loadAsyncTask != null && !this.loadAsyncTask.IsCompleted)
110 this.Image = base.InitialImage;
117 catch (UriFormatException)
119 uri = new Uri(Path.GetFullPath(url));
122 var client = new OTWebClient();
124 client.DownloadProgressChanged += (s, e) =>
126 this.OnLoadProgressChanged(new ProgressChangedEventArgs(e.ProgressPercentage, e.UserState));
129 this.loadAsyncCancelTokenSource = new CancellationTokenSource();
130 var cancelToken = this.loadAsyncCancelTokenSource.Token;
131 var loadImageTask = client.DownloadDataAsync(uri, cancelToken);
133 // UnobservedTaskException イベントを発生させないようにする
134 loadImageTask.ContinueWith(t => { var ignore = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted);
136 var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
138 return loadImageTask.ContinueWith(t => {
141 if (t.IsFaulted) throw t.Exception;
143 return MemoryImage.CopyFromBytes(t.Result);
151 this.Image = base.ErrorImage;
155 this.Image = t.Result.Image;
156 this.memoryImage = t.Result;
160 var exp = t.Exception != null ? t.Exception.Flatten() : null;
161 this.OnLoadCompleted(new AsyncCompletedEventArgs(exp, t.IsCanceled, null));
165 public new void CancelAsync()
167 if (this.loadAsyncTask == null || this.loadAsyncTask.IsCompleted)
170 this.loadAsyncCancelTokenSource.Cancel();
174 this.loadAsyncTask.Wait();
176 catch (AggregateException ae)
180 if (e is OperationCanceledException)
182 if (e is WebException)
190 protected override void Dispose(bool disposing)
192 base.Dispose(disposing);
194 if (this.memoryImage != null)
195 this.memoryImage.Dispose();
197 if (this.loadAsyncCancelTokenSource != null)
198 this.loadAsyncCancelTokenSource.Dispose();