インフラジスティックス・ジャパン株式会社Blog

インフラジスティックス・ジャパン株式会社のチームメンバーが技術トレンド、製品Tips、サポート情報からライセンス、日々の業務から感じることなど、さまざまなトピックについてお伝えするBlogです。

AI と一緒に IG 製品使って WPF アプリ開発して寝てる間に仕事終わってる夢を叶えたい

メリークリスマス! よいお年を! ハッピーニューイヤー! & ゲッツ!

インフラジスティックスの Mori です!

この時期はもうやること多くてほんと大変ですよね!物理的に!せめて仕事くらいはなんとか簡単に済ませちゃいたい、楽をしたい、なんなら寝ている間に終わっててほしい。

そんな願いを叶えてくれるのが、

「AI」

そう AI 様 ですね!

ということで、今回は AI 様がどれくらい僕の願いを叶えてくれるのか、どこまでわがままに付き合ってくれるのか、ほんとうに AI 様の時代がきているのか、確かめるべく、タイトルのとおり IG のライブラリを使った WPF アプリを一緒に作ってみることにしました!

基本的には僕が求めている丸投げスタイルで進めていきたいと思います!(仕事しろ!!)

はじめに:AIにアプリ開発を頼んでみた

正直なところ、最初は半信半疑でした。「AIにアプリ開発を手伝ってもらう」なんて、本当にうまくいくのか? どうせいつまでも同じ修正とエラーを出して迷宮入りさせてさよならポイなんだろ。。と。

でも、実際にやってみたら…想像以上にスムーズに開発が進みました!(素敵だ!)

この記事では、Infragistics の Ignite UI for WPF を使った写真デコレーションアプリを、AIと協力して作った体験談を共有します。エラーとの格闘、試行錯誤、そして「おお、できた!」という瞬間まで、すべてお見せします。


作りたかったアプリ

PhotoShapeDecorator(写真シェイプデコレーター)

(AI 様はアプリ名も考えてくださる)

シンプルなコンセプト:

  • 写真を背景に選んで
  • 左側からシェイプ(〇)をドラッグ&ドロップして配置
  • 配置したシェイプは自由に動かせる
  • いらないシェイプはゴミ箱にドラッグして削除
  • 完成した画像を保存

最初に用意したイメージデザイン


利用した AI エージェント

  • AI プラットフォーム: Notion AI
  • AI モデル: Claude Sonnet 4.5

今回のブログ作成用のアプリ作成では、Notion AI を活用して開発を進めました。

Notion AI はお願いすればページにログをきれいに残してくれるので重宝してます。

期待してるよん!

最初の一歩:AI への依頼。そして AI 様へ。

最初のプロンプト

Infragistics の Ignite UI for WPF のドラッグアンドドロップ機能を使って、
以下の機能を持つプロジェクトを作成しようと思います。

画面構成(添付のイメージも参照してください。)
- シェイプエリア:写真エリアへドラッグアンドドロップで移動する図形を配置
- 写真エリア:シェイプを配置できるエリア。背景画像を選択可能
- ゴミ箱エリア:シェイプをドロップして削除
- 背景を選ぶボタン:画像選択
- 画像保存ボタン:写真エリアを画像として保存

これらを順を追って作成していきたいので手伝ってください。
まずは、写真エリアと背景を選ぶボタンの実装から始めたいです。

AI からの返答:ステップ1の提案

AI は即座にプロジェクト構成を提案してくれました:

  1. プロジェクト名:PhotoShapeDecorator
  2. NuGetパッケージ:Infragistics.WPF.DragDropInfragistics.WPF
  3. MainWindow.xaml の実装コード
  4. MainWindow.xaml.cs の実装コード

実行してみた結果

一回目でこれが動いた!

しかも、[背景を選ぶ] ボタンを押すとすでに背景を選択することも、、

背景画像も正しく表示された

一回目でこれはすごい!

背景画像の選択とCanvas表示が、最初の提案コードで完璧に動作しました。この時点で「もしかしてこれ、本当にいけるかも?」という期待が生まれました。

そして、あいつ的だった AI は、大好きなあのお方的な AI 様へと格上げされたのです。


ステップ2:ドラッグ&ドロップ機能 〜最初の壁〜

やり取り:

  • AI:「それでは最初にシェイプエリアから写真エリアへドラッグアンドドロップで図形を配置する機能を進めます。」
  • 私:「よろしく!」(最初に伝えたとおり順番に合わせて進めてくれてる!やったー!すぐ終わりそうやん!)

さっそく取り掛かってくれる AI ちゃん。イェイ!頼んだぜ!

最初のエラー:DragChannel の設定

AI 様が提案したXAMLコードを実装したところ、エラーが発生:

DragChannel は存在しないとの警告

<!-- ❌ エラーが発生 -->
<ig:DragSource.DragChannels>
    <ig:DragChannel ChannelName="ShapeChannel"/>
</ig:DragSource.DragChannels>

プロンプト:Infragisticsのドキュメントリンクを提示

ドキュメントを確認すると、DragChannels は文字列プロパティだとわかったので、そのリンクをAI 様に渡しました。(内心、これくらい探して来てよ。と思ってました。楽をすることに執着した人間はどこまでも求めるようになる生き物なのです。無念)

※ より正確に作業できるように、可能な範囲で参照するドキュメントなどは先に教えてあげましょう!

AI 様の修正提案

<!-- ✅ 正しい記法 -->
<ig:DragSource IsDraggable="True" DragChannels="ShapeChannel"/>

ポイント: XAMLでは文字列プロパティ、コードビハインドでは ObservableCollection<string> という違いをAI 様が説明してくれました。

次のエラー:Drop イベントの設定場所

'DragDropManager' に 'AddDropListener' の定義がありません

やり取り:

  • 私:「AddDropListener メソッドが存在しないエラーが出ています」
  • AI 様:「Drop イベントは XAML で直接設定します」

しかし、DropTarget に Drop を設定してもエラー。

さらに指摘:

  • 私:「ドキュメントによると、Drop イベントは DragSource 側に設定する必要があるようです」
  • AI 様:「ご指摘の通り!」
<!-- ✅ 正しい実装 -->
<ig:DragSource IsDraggable="True" 
               DragChannels="ShapeChannel"
               Drop="DragSource_Drop"/>

最後のエラー:OperationResult

'DropEventArgs' に 'OperationResult' の定義が含まれていません

AI 様の対応:

「この行は Infragistics のフレームワークでは不要です。削除しましょう。」

// e.OperationResult.DropOperationPerformed = true; // 削除

ステップ2完成!

感想: エラーは出たものの、ドキュメントを示したり、エラーメッセージを伝えるだけで、AI 様が適切な修正案を出してくれました。こんなに賢い AI 様も僕の手助けが必要な場面もあり、自信が持てるようになりました。少しだけ仕事をする意欲が湧いてきました。(なにかの更生企画ですっけ?)


ステップ3:画像保存機能

このステップはスムーズでした。

プロンプト:

「次は画像保存機能を実装したいです」

AIの提案:

  • RenderTargetBitmap でCanvasを画像化
  • BitmapEncoder でPNG/JPEG/BMP対応
  • SaveFileDialog でファイル保存

一発で動作しました!🎉

保存した画像データ


ステップ4:配置したシェイプの再ドラッグ 〜試行錯誤の連続〜

ここが一番苦労したポイントです。画像エリアに配置したシェイプを再度移動させるためにドラッグをするところまではできたのです。そしてドラッグを開始したら元の位置にあるシェイプは消えてほしかったのですが、、、

問題:ドラッグ中に元のシェイプが残ってしまう

ドラッグ移動中はドラッグしているシェイプだけ表示したい
ドラッグ移動中はドラッグしているシェイプだけ表示したい

試した解決策:

  1. Visibility.Collapsed を使う → エラー発生(サイズが0になってしまう)
  2. Opacity = 0 を使う → ドラッグ中のシェイプも透明になってしまう
  3. Canvas から削除 → ドラッグプレビューの位置がずれる
  4. Opacity = 0.01 → まだドラッグ中のシェイプが薄くなる
  5. Visibility.Hidden → 同じ問題

こちらから提案!ゴースト要素にしてみる

なんだか同じ修正と対策のループに陥ってきたので、こちらから別の案を提案して打開策となるか聞いてみました。ゴースト要素ってぱっとでてくるところもすごいけど、伝わる AI 様もなかなか素敵やん?

私の提案:

「Opacity ではなく、ドラッグ中に別のゴースト要素を表示する方法は使えないでしょうか?」

AI 様の反応:

「それは良いアイデアです!」

ゴースト要素アプローチ

// ドラッグ開始時
- 元の要素を Visibility.Hidden
- 半透明のゴースト要素(Opacity=0.6)を作成
- Window の MouseMove イベントでゴーストをカーソルに追従

// ドロップ時
- ゴースト要素を削除
- 元の要素を新しい位置に移動・再表示

さらなる問題:MouseMove が途中で止まる

MouseMove が途中で止まる

問題: Canvas の MouseMove イベントがドラッグ中に発火しなくなる

原因: Infragistics のライブラリがマウスキャプチャを取得するため

解決策: Window の MouseMove イベントを使う

// Canvas ではなく Window の MouseMove を使用
this.MouseMove += Window_MouseMove;

これで完璧に動作!✨

まったく機能しない場合よりも、こういった動作不良のようなシチュエーションは個人で調査、検証してもなかなか解消せず大変なイメージですが、 AI 様はネット上で似たような事象があれば拾ってきてくれるので、自分で探し当てるよりだいぶ早いですね。

ステップ5:ゴミ箱機能 〜最大の難関〜

最初の実装:ゴミ箱判定

AI 様の提案:

Dropイベント内で、ドロップ位置がゴミ箱エリア内かを判定:

Point dropPosition = e.GetPosition(this);
Point trashPosition = TrashArea.TransformToAncestor(this).Transform(new Point(0, 0));
Rect trashRect = new Rect(trashPosition, new Size(TrashArea.ActualWidth, TrashArea.ActualHeight));

if (trashRect.Contains(dropPosition))
{
    // ゴミ箱にドロップ → 削除
    PhotoCanvas.Children.Remove(draggedCircle);
}

削除機能は動作!でも…

問題1:ゴーストがゴミ箱まで追従しない

ゴーストが写真エリアで止まってしまう

原因: Window_MouseMove でCanvas範囲チェックをしていた

解決: 範囲チェックを削除

// Canvas の範囲チェックを削除
Canvas.SetLeft(ghostCircle, currentPosition.X - ghostCircle.Width / 2);
Canvas.SetTop(ghostCircle, currentPosition.Y - ghostCircle.Height / 2);

ゴーストがゴミ箱まで追従するようになった!

問題2:ゴーストがゴミ箱の背後に隠れる

ゴーストがゴミ箱の下に表示されてしまう

不思議な現象:

  • シェイプエリアから直接ゴミ箱にドラッグ → 正常に前面表示
  • 写真エリアからゴミ箱にドラッグ → 背後に表示

原因の分析(AI 様と一緒に):

  • シェイプエリアからのドラッグ: Infragisticsのドラッグプレビューを使用 → Windowレベルで表示
  • 写真エリアからのドラッグ: ゴースト要素を使用 → PhotoCanvasの子要素として追加
  • Panel.SetZIndex はPhotoCanvas内の順序しか制御できない。ゴミ箱はPhotoCanvasの外なので、Z-order問題が発生。

試行錯誤1:Panel.SetZIndex

Panel.SetZIndex(ghostCircle, 9999);

→ 効果なし(PhotoCanvas内のZ-orderしか制御できない)

試行錯誤2:RootGrid に配置

RootGrid.Children.Add(ghostCircle);

→ 座標がおかしくなる(Canvas.SetLeft/Top が Grid では機能しない)

解決策:専用のオーバーレイCanvas!

AI 様の提案:

「Window全体を覆う専用の透明なCanvasレイヤーを追加しましょう」

<Grid x:Name="RootGrid">
    <!-- 既存の要素 -->

    <!-- ゴースト表示用オーバーレイ(最前面) -->
    <Canvas x:Name="GhostOverlay" 
            IsHitTestVisible="False" 
            Background="Transparent"
            Panel.ZIndex="10000"/>
</Grid>

利点:

  • Canvasなので Canvas.SetLeft/Top が機能
  • Window全体を覆うので、すべての要素の前面に表示
  • IsHitTestVisible="False" で下のUI操作を妨げない

座標変換エラーが発生

System.InvalidOperationException
Message=指定された Visual は、この Visual の先祖ではありません。

原因: PhotoCanvasGhostOverlay は兄弟関係なのに、TransformToAncestor(GhostOverlay) を使っていた

解決: 共通の先祖 RootGrid を経由

Point canvasTopLeft = PhotoCanvas.TransformToAncestor(RootGrid).Transform(new Point(0, 0));

ついに完成!🎉

ゴーストがゴミ箱の前面に表示され、すべての機能が正常に動作するようになりました!


リファクタリング前の完成版コード

すべての機能が動作する状態のコードです。

MainWindow.xaml(完成版)

github.com

MainWindow.xaml.cs(完成版)

github.com


リファクタリング:コードをきれいに

機能は完成しましたが、コードがちらかっていたので、試しに AI 様にリファクタリングを依頼してみました。

プロンプト:

「コードのリファクタリング提案をください。前後比較で見せてもらえると嬉しいです。」

AIからの5つの提案

  1. 定数の抽出 - マジックナンバーを排除
  2. ゴースト処理のメソッド化 - 重複コード削除
  3. シェイプ作成のメソッド化 - 統一された処理
  4. ゴミ箱判定のメソッド化 - 判定ロジックの独立
  5. 全体構造の改善 - セクション分けとコメント

リファクタリング後の完成版コード

MainWindow.xaml(リファクタリング後)

github.com

MainWindow.xaml.cs(リファクタリング後)

github.com

実行画面

右がリファクタリング後。僕のラフ寄りだった見た目をしれっと良くしやがりました。


まとめ:AIと協力開発してわかったこと

良かったこと

  1. 初期実装のスピード - 最初のステップが一発で動いた驚き。その後もアイデアがあれば実装はとにかく早いですね!さすが!
  2. エラー解決 - エラー箇所とエラーメッセージ内容を伝えると大半はエラーを解消してくれました。やはりエラーとして検知されるものは世の中に情報がたくさんあるのでしょう。これもさすが!
  3. 提案 - ざっくりと画面イメージと簡単な操作仕様を伝えていましたが、それに対してちゃんと提案してくれました。実装を進めるとなかなかうまくいかないところも出てきますが、都度別の案を提案してくれるし、辛抱強く付き合ってくれます。好きです!
  4. ペアプログラミング感覚 - 一緒に考えて解決していく感じがしていいですね。今回は基本的に全部任せようと目論んでいましたが、最初の段階でこちらの技術知識をアップデートしたい目的などと伝えて開始したらどうなるのか、試してみたいです。

難しかったこと

  1. ドキュメントとの不一致 - これはタイミングにもよるのかもしれませんが、かならずしも適切な情報を探してくれるわけではありませんでした。こちらで違和感を見つけて提案しないと迷宮入りするパターンは実は結構ありました。
  2. 複雑な問題の試行錯誤 - いきあたりばったりの依頼ばかりをしたので仕方ない部分ですかね。ユーザー主導で取り組んでいけば AI 様の知識との相乗効果でどんどん効率よくできそうだと感じました。真面目なときはそうします。(いつだ)
  3. コンテキストの伝達 - 時間が経つと過去のコードをうまく参照しなくなってしまいました。僕の使い方も悪かったんだと思いますが、再開するときは一度プロンプトで過去の情報を少しおさらいさせるといいのかもしれません。とはいえ僕も週末挟めば全部忘れますし、気になりません。(気にしようぜ)

※ 今回はブログ作成が目的だったため、 AI が出力してくれたコードやメッセージをログとして残す目的もあり、Notion AI を活用して Notion ページにログを残して進めていました。結果的に AI に参照させたいログが膨大になりすぎたため、AI がログを要約解釈した可能性も考えられました。

コツ

  1. 段階的に進める - 一度に全部ではなく、ステップバイステップで進めたのはよかったです。先にプロンプトで全容を伝えるのは大変ですがやりましょう。
  2. ドキュメントを活用 - 公式ドキュメントのURLを渡すと認識してくれるので、これも先に伝えておけたらよかったなと思いました。

※参照情報が多くなりすぎない工夫が必要です。今回の場合、ステップごとに Notion ページも分けて、必要毎に参照ページや情報を示してあげるとよかったかもしれません。(やさしくあれ)

総括

半信半疑でしたが、最後には「これは使える!」と確信しました。

AI は完璧ではないけれど、パートナーだったりアドバイザーとして一緒に開発を進められました。特に、初期実装やエラー解決、リファクタリングなど、時間のかかる作業を大幅にスピードアップすることができます。

言われたことをこなしてくれますし、パッと出来上がってしまうので、細かいズレは目をつむる必要があるし、そういう状態に慣れてしまう可能性もちょっと怖いですね。最終的にそのズレは潰さなくてはなりません。今回のように丸投げしてしまうと、このズレを見つけることも難しくなると思います。AI と仕事をしてスピードについていくのがやっとな状態になるよりも、今の仕事の一部を細かく切り出して効率を上げていくのが結果的に早く仕事を終わらせて、仲間や家族、大切な人と過ごす時間をつくりだせるんじゃないかナ? (え、なんて?こいつは置いてさっさと帰ろう)

AI に聞いてみてもうまくいかない!合っているのか判断がつかない!そんなときもどうぞ私たちにご相談ください!