OSDN Git Service

発言詳細部の更新時に TableLayoutPanel1 及び子コントロールの再描画を抑制
authorKimura Youichi <kim.upsilon@bucyou.net>
Mon, 16 Jun 2014 16:19:58 +0000 (01:19 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Mon, 16 Jun 2014 16:33:47 +0000 (01:33 +0900)
OpenTween/ControlTransaction.cs
OpenTween/Tween.cs
OpenTween/Win32Api.cs

index 99f37a4..068201a 100644 (file)
@@ -53,6 +53,15 @@ namespace OpenTween
             return new Transaction<TreeView>(control, x => x.BeginUpdate(), x => x.EndUpdate());
         }
 
+        public static IDisposable Update(Control control)
+        {
+            // Begin/EndUpdate メソッドを持たないコントロールに対しては、
+            // WM_SETREDRAW メッセージを直接コントロールに送信する。
+            return new Transaction<Control>(control,
+                x => Win32Api.SetRedrawState(x, false),
+                x => { Win32Api.SetRedrawState(x, true); x.Invalidate(true); });
+        }
+
         public static IDisposable Layout(Control control)
         {
             return Layout(control, performLayout: true);
index b998b28..fe20eed 100644 (file)
@@ -6069,139 +6069,142 @@ namespace OpenTween
             displayItem = (ImageListViewItem)_curList.Items[_curList.SelectedIndices[0]];
             displayItem.ImageDownloaded += this.DisplayItemImage_Downloaded;
 
-            var sourceText = "";
-            string sourceUrl = null;
-            if (!_curPost.IsDm)
+            using (ControlTransaction.Update(this.TableLayoutPanel1))
             {
-                var mc = Regex.Match(_curPost.SourceHtml, "<a href=\"(?<sourceurl>.+?)\"");
-                if (mc.Success)
+                var sourceText = "";
+                string sourceUrl = null;
+                if (!_curPost.IsDm)
                 {
-                    var src = mc.Groups["sourceurl"].Value;
-                    if (Regex.IsMatch(src, "^https?://"))
-                        sourceUrl = src;
-                    else
-                        sourceUrl = "https://twitter.com/" + src;
-                }
-
-                if (_curPost.Source != null)
-                    sourceText = _curPost.Source;
-            }
-            SourceLinkLabel.Text = sourceText;
-            SourceLinkLabel.Tag = sourceUrl;
-            SourceLinkLabel.TabStop = false; // Text を更新すると勝手に true にされる
-
-            string nameText;
-            if (_curPost.IsDm)
-            {
-                if (_curPost.IsOwl)
-                    nameText = "DM FROM <- ";
-                else
-                    nameText = "DM TO -> ";
-            }
-            else
-            {
-                nameText = "";
-            }
-            nameText += _curPost.ScreenName + "/" + _curPost.Nickname;
-            if (_curPost.RetweetedId != null)
-                nameText += " (RT:" + _curPost.RetweetedBy + ")";
-
-            NameLabel.Text = nameText;
-            NameLabel.Tag = _curPost.ScreenName;
-
-            var nameForeColor = SystemColors.ControlText;
-            if (_curPost.IsOwl && (this.SettingDialog.OneWayLove || _curPost.IsDm))
-                nameForeColor = this._clOWL;
-            if (_curPost.RetweetedId != null)
-                nameForeColor = this._clRetweet;
-            if (_curPost.IsFav)
-                nameForeColor = this._clFav;
-            NameLabel.ForeColor = nameForeColor;
+                    var mc = Regex.Match(_curPost.SourceHtml, "<a href=\"(?<sourceurl>.+?)\"");
+                    if (mc.Success)
+                    {
+                        var src = mc.Groups["sourceurl"].Value;
+                        if (Regex.IsMatch(src, "^https?://"))
+                            sourceUrl = src;
+                        else
+                            sourceUrl = "https://twitter.com/" + src;
+                    }
 
-            this.ClearUserPicture();
+                    if (_curPost.Source != null)
+                        sourceText = _curPost.Source;
+                }
+                SourceLinkLabel.Text = sourceText;
+                SourceLinkLabel.Tag = sourceUrl;
+                SourceLinkLabel.TabStop = false; // Text を更新すると勝手に true にされる
 
-            if (!string.IsNullOrEmpty(_curPost.ImageUrl))
-            {
-                var image = IconCache.TryGetFromCache(_curPost.ImageUrl);
-                try
+                string nameText;
+                if (_curPost.IsDm)
                 {
-                    UserPicture.Image = image != null ? image.Clone() : null;
+                    if (_curPost.IsOwl)
+                        nameText = "DM FROM <- ";
+                    else
+                        nameText = "DM TO -> ";
                 }
-                catch (Exception)
+                else
                 {
-                    UserPicture.ShowErrorImage();
+                    nameText = "";
                 }
-            }
+                nameText += _curPost.ScreenName + "/" + _curPost.Nickname;
+                if (_curPost.RetweetedId != null)
+                    nameText += " (RT:" + _curPost.RetweetedBy + ")";
 
-            DateTimeLabel.Text = _curPost.CreatedAt.ToString();
+                NameLabel.Text = nameText;
+                NameLabel.Tag = _curPost.ScreenName;
 
-            if (DumpPostClassToolStripMenuItem.Checked)
-            {
-                StringBuilder sb = new StringBuilder(512);
+                var nameForeColor = SystemColors.ControlText;
+                if (_curPost.IsOwl && (this.SettingDialog.OneWayLove || _curPost.IsDm))
+                    nameForeColor = this._clOWL;
+                if (_curPost.RetweetedId != null)
+                    nameForeColor = this._clRetweet;
+                if (_curPost.IsFav)
+                    nameForeColor = this._clFav;
+                NameLabel.ForeColor = nameForeColor;
 
-                sb.Append("-----Start PostClass Dump<br>");
-                sb.AppendFormat("TextFromApi           : {0}<br>", _curPost.TextFromApi);
-                sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.TextFromApi);
-                sb.AppendFormat("StatusId             : {0}<br>", _curPost.StatusId.ToString());
-                //sb.AppendFormat("ImageIndex     : {0}<br>", _curPost.ImageIndex.ToString());
-                sb.AppendFormat("ImageUrl       : {0}<br>", _curPost.ImageUrl);
-                sb.AppendFormat("InReplyToStatusId    : {0}<br>", _curPost.InReplyToStatusId.ToString());
-                sb.AppendFormat("InReplyToUser  : {0}<br>", _curPost.InReplyToUser);
-                sb.AppendFormat("IsDM           : {0}<br>", _curPost.IsDm.ToString());
-                sb.AppendFormat("IsFav          : {0}<br>", _curPost.IsFav.ToString());
-                sb.AppendFormat("IsMark         : {0}<br>", _curPost.IsMark.ToString());
-                sb.AppendFormat("IsMe           : {0}<br>", _curPost.IsMe.ToString());
-                sb.AppendFormat("IsOwl          : {0}<br>", _curPost.IsOwl.ToString());
-                sb.AppendFormat("IsProtect      : {0}<br>", _curPost.IsProtect.ToString());
-                sb.AppendFormat("IsRead         : {0}<br>", _curPost.IsRead.ToString());
-                sb.AppendFormat("IsReply        : {0}<br>", _curPost.IsReply.ToString());
+                this.ClearUserPicture();
 
-                foreach (string nm in _curPost.ReplyToList)
+                if (!string.IsNullOrEmpty(_curPost.ImageUrl))
                 {
-                    sb.AppendFormat("ReplyToList    : {0}<br>", nm);
+                    var image = IconCache.TryGetFromCache(_curPost.ImageUrl);
+                    try
+                    {
+                        UserPicture.Image = image != null ? image.Clone() : null;
+                    }
+                    catch (Exception)
+                    {
+                        UserPicture.ShowErrorImage();
+                    }
                 }
 
-                sb.AppendFormat("ScreenName           : {0}<br>", _curPost.ScreenName);
-                sb.AppendFormat("NickName       : {0}<br>", _curPost.Nickname);
-                sb.AppendFormat("Text   : {0}<br>", _curPost.Text);
-                sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.Text);
-                sb.AppendFormat("CreatedAt          : {0}<br>", _curPost.CreatedAt.ToString());
-                sb.AppendFormat("Source         : {0}<br>", _curPost.Source);
-                sb.AppendFormat("UserId            : {0}<br>", _curPost.UserId);
-                sb.AppendFormat("FilterHit      : {0}<br>", _curPost.FilterHit);
-                sb.AppendFormat("RetweetedBy    : {0}<br>", _curPost.RetweetedBy);
-                sb.AppendFormat("RetweetedId    : {0}<br>", _curPost.RetweetedId);
-                sb.AppendFormat("SearchTabName  : {0}<br>", _curPost.RelTabName);
-                sb.Append("-----End PostClass Dump<br>");
+                DateTimeLabel.Text = _curPost.CreatedAt.ToString();
 
-                PostBrowser.DocumentText = detailHtmlFormatHeader + sb.ToString() + detailHtmlFormatFooter;
-            }
-            else
-            {
-                // 同じIDのツイートであれば WebBrowser とサムネイルの更新を行わない
-                // (同一ツイートの RT は文面が同じであるため同様に更新しない)
-                if (_curPost.StatusId != oldDisplayPost.StatusId)
+                if (DumpPostClassToolStripMenuItem.Checked)
                 {
-                    this.PostBrowser.DocumentText =
-                        this.createDetailHtml(_curPost.IsDeleted ? "(DELETED)" : _curPost.Text);
+                    StringBuilder sb = new StringBuilder(512);
 
-                    this.SplitContainer3.Panel2Collapsed = true;
+                    sb.Append("-----Start PostClass Dump<br>");
+                    sb.AppendFormat("TextFromApi           : {0}<br>", _curPost.TextFromApi);
+                    sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.TextFromApi);
+                    sb.AppendFormat("StatusId             : {0}<br>", _curPost.StatusId.ToString());
+                    //sb.AppendFormat("ImageIndex     : {0}<br>", _curPost.ImageIndex.ToString());
+                    sb.AppendFormat("ImageUrl       : {0}<br>", _curPost.ImageUrl);
+                    sb.AppendFormat("InReplyToStatusId    : {0}<br>", _curPost.InReplyToStatusId.ToString());
+                    sb.AppendFormat("InReplyToUser  : {0}<br>", _curPost.InReplyToUser);
+                    sb.AppendFormat("IsDM           : {0}<br>", _curPost.IsDm.ToString());
+                    sb.AppendFormat("IsFav          : {0}<br>", _curPost.IsFav.ToString());
+                    sb.AppendFormat("IsMark         : {0}<br>", _curPost.IsMark.ToString());
+                    sb.AppendFormat("IsMe           : {0}<br>", _curPost.IsMe.ToString());
+                    sb.AppendFormat("IsOwl          : {0}<br>", _curPost.IsOwl.ToString());
+                    sb.AppendFormat("IsProtect      : {0}<br>", _curPost.IsProtect.ToString());
+                    sb.AppendFormat("IsRead         : {0}<br>", _curPost.IsRead.ToString());
+                    sb.AppendFormat("IsReply        : {0}<br>", _curPost.IsReply.ToString());
 
-                    if (this.IsPreviewEnable)
+                    foreach (string nm in _curPost.ReplyToList)
                     {
-                        if (this.thumbnailTokenSource != null)
+                        sb.AppendFormat("ReplyToList    : {0}<br>", nm);
+                    }
+
+                    sb.AppendFormat("ScreenName           : {0}<br>", _curPost.ScreenName);
+                    sb.AppendFormat("NickName       : {0}<br>", _curPost.Nickname);
+                    sb.AppendFormat("Text   : {0}<br>", _curPost.Text);
+                    sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.Text);
+                    sb.AppendFormat("CreatedAt          : {0}<br>", _curPost.CreatedAt.ToString());
+                    sb.AppendFormat("Source         : {0}<br>", _curPost.Source);
+                    sb.AppendFormat("UserId            : {0}<br>", _curPost.UserId);
+                    sb.AppendFormat("FilterHit      : {0}<br>", _curPost.FilterHit);
+                    sb.AppendFormat("RetweetedBy    : {0}<br>", _curPost.RetweetedBy);
+                    sb.AppendFormat("RetweetedId    : {0}<br>", _curPost.RetweetedId);
+                    sb.AppendFormat("SearchTabName  : {0}<br>", _curPost.RelTabName);
+                    sb.Append("-----End PostClass Dump<br>");
+
+                    PostBrowser.DocumentText = detailHtmlFormatHeader + sb.ToString() + detailHtmlFormatFooter;
+                }
+                else
+                {
+                    // 同じIDのツイートであれば WebBrowser とサムネイルの更新を行わない
+                    // (同一ツイートの RT は文面が同じであるため同様に更新しない)
+                    if (_curPost.StatusId != oldDisplayPost.StatusId)
+                    {
+                        this.PostBrowser.DocumentText =
+                            this.createDetailHtml(_curPost.IsDeleted ? "(DELETED)" : _curPost.Text);
+
+                        this.SplitContainer3.Panel2Collapsed = true;
+
+                        if (this.IsPreviewEnable)
                         {
-                            var oldTokenSource = this.thumbnailTokenSource;
+                            if (this.thumbnailTokenSource != null)
+                            {
+                                var oldTokenSource = this.thumbnailTokenSource;
 
-                            oldTokenSource.Cancel();
+                                oldTokenSource.Cancel();
 
-                            this.thumbnailTask.ContinueWith(_ => oldTokenSource.Dispose());
-                        }
+                                this.thumbnailTask.ContinueWith(_ => oldTokenSource.Dispose());
+                            }
 
-                        this.thumbnailTokenSource = new CancellationTokenSource();
+                            this.thumbnailTokenSource = new CancellationTokenSource();
 
-                        var token = this.thumbnailTokenSource.Token;
-                        this.thumbnailTask = this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token);
+                            var token = this.thumbnailTokenSource.Token;
+                            this.thumbnailTask = this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token);
+                        }
                     }
                 }
             }
index 2f3caa5..c6b04ab 100644 (file)
@@ -47,6 +47,7 @@ namespace OpenTween
         // SendMessageで送信するメッセージ
         private enum SendMessageType : uint
         {
+            WM_SETREDRAW = 0x000B,               //再描画を許可するかを設定
             WM_USER = 0x400,                     //ユーザー定義メッセージ
 
             TCM_FIRST = 0x1300,                  //タブコントロールメッセージ
@@ -58,6 +59,18 @@ namespace OpenTween
         }
 
         /// <summary>
+        /// コントロールの再描画を許可するかを設定します
+        /// </summary>
+        /// <param name="control">対象となるコントロール</param>
+        /// <param name="redraw">再描画を許可する場合は true、抑制する場合は false</param>
+        /// <returns>このメッセージを処理する場合、アプリケーションは 0 を返します</returns>
+        public static int SetRedrawState(Control control, bool redraw)
+        {
+            var state = redraw ? new IntPtr(1) : IntPtr.Zero;
+            return (int)SendMessage(control.Handle, SendMessageType.WM_SETREDRAW, state, IntPtr.Zero);
+        }
+
+        /// <summary>
         /// タブコントロールのアイテムの最小幅を設定します
         /// </summary>
         /// <param name="tabControl">対象となるタブコントロール</param>