今更ながらWPFに置き換えてみる(7)


遅い原因は単にCanvasのChildrenをClearしていなかっただけの模様。
修正したところ何とか違和感ないレベルになりました。
とはいえWindowトランジションの際はメキメキパフォーマンスが落ちるのでいったん不要なコントロールは非表示に。

NotifyIconの動的な生成・更新

NotifyIconに左上のCanvasのBitmapイメージを突っ込んでいます。
左に同じようなアイコンがもう一つありますが、そちらはForms+VB版のアイコン。同じようにGDIで描画したものを動的に入れてますが16ピクセル固定のイメージをそのまま入れているので当ノートPC(125%)のスケーリングにより20ピクセルサイズになっているため、ボケ度合いが激しいです。

拡大するとより分かりやすい。

NotifyIconのもとになるCanvasのサイズを16ピクセルではなく20ピクセルで作ってるので、きれいに表示されています。16のサイズで作っちゃうと
Froms版と大して変わりません

NotifyIconへのセット手順としては
①Canvas上に作成した時計のイメージを
②CanvasごとRenderTargetBitmapにして
③RenderTargetBitmapをCopyPixelsで普通のBitmap(System.Drawing)にして
④IconHandleをとって
⑤アイコン化してセット
という流れ。

       private void MainLoop(object sender, EventArgs e)
        {
            //毎秒処理
            if (G.DispIcon != 0)
            { 
                DrawClock2(this.aCanvas);

                aCanvas.Arrange(new Rect(aCanvas.RenderSize));
                aCanvas.Measure(aCanvas.RenderSize);
                var bounds = VisualTreeHelper.GetDescendantBounds(aCanvas);
                var RTbitmap = new RenderTargetBitmap((int)bounds.Width, (int)bounds.Height, 96.0d,96.0d,PixelFormats.Pbgra32);
                var dv = new DrawingVisual();
                using (var dc = dv.RenderOpen())
                {
                    var vb = new VisualBrush(aCanvas);
                    dc.DrawRectangle(vb, null, bounds);
                }
                RTbitmap.Render(dv);
                RTbitmap.Freeze();

                //RenderTargetBitmap => bitmap
                var bitmap = new System.Drawing.Bitmap((int)bounds.Width, (int)bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
                var bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(System.Drawing.Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
                RTbitmap.CopyPixels(Int32Rect.Empty, bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);

                //bitmap => bitmapHandler => ImageSource(参考)
                IntPtr Hbitmap = bitmap.GetHbitmap();
                var ImageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(Hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                this.image.Source = ImageSource;

                //bitmap =>iconHandler => icon
                bitmap.UnlockBits(bitmapData);
                IntPtr Hicon = bitmap.GetHicon();
                System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(Hicon);
                this.NotifyIcon.Icon = icon;

                bitmap.Dispose();
                DestroyIcon(icon.Handle);

            }
       }

変換が多くて非常に手間がかるやり方なんですが、stream使うのも、なんかなあという気がしてこのような手順で行くことに。きっともっとうまい方法があるに違いない。