none
VisualStudio2013 C# で、タスクバーに表示されているアイコンの背景をプログレスバーとして機能させる方法を教えて下さい。 RRS feed

  • 質問

  • 開発環境
     Windows 8.1 Pro
     VisualStudio 2013 Pro
     開発言語:VC#
     対象フレーム:.NET Framework 4.5

    「タスクバーに表示されているアイコンの背景をプログレスバーとして機能させる方法」をネットで調べていましたら、「Windows API Code Pack」をダウンロードして「Microsoft.WindowsAPICodePack.Shell.dll を使用する」という事が書かれていましたので、早速ダウンロードが出来るというサイト(http://archive.msdn.microsoft.com/)を開いたのですが、「Windows API Code Pack」がどこにも見あたりませんでした。

    この機能は、「Windows 7」から使えるようになった様なことが、ネット上のサイトに書かれていました。
    私は、Windows XP Pro から Windows 8.1 Pro のユーザになりましたので、それまでの経緯(Windows Vista、Windows 7)に関しては、さっぱり分かりません。
    もしかしたら、Windows 8 から「Windows API Code Pack」を必要としなくなったのではないのか?などど勝手に想像しています。

    少し話が脱線しますが、「タスクバーに表示されているアイコンの背景をプログレスバーとして機能させる方法」に興味を持ったのは、現在使用しているセキュリティ・ソフトが、その機能を使っていました。
    ウイルス検査をさせると、タスクバーのアイコンがプログレスバーの様な動作をしていました。
    そこで思いついたのは、もし上記の機能を実現させるのに「Windows API Code Pack」の「Microsoft.WindowsAPICodePack.Shell.dll」が必要なら、セキュリティ・ソフトでも「Microsoft.WindowsAPICodePack.Shell.dll」を使用しているのではと考えて、システムディスクの中を検索しましたが、発見できませんでした。結論としてセキュリティ・ソフトは、「Windows API Code Pack」を使っていないように思えます。

    そこで教えて頂きたいことが2つあります。
     Q1.「Windows API Code Pack」を使用せずに、上記の機能を実現する方法がありましたら、教えて下さい。
     Q2.「Windows API Code Pack」が必要な場合、どこから入手できるのか、また入手対象となるバージョンを教えて下さい。

    ※ 大変厚かましいお願いになるのですが、サンプルとしてソースコードを書いて頂けると助かります。

    何方かご親切な方、ご教授よろしくお願い致します。
    2014年9月6日 7:41

回答

  • アプリケーション開発に使っているAPIはWindows Forms(Windows フォーム アプリケーション)ですか? WPFですか?

    質問するときは.NET Frameworkのバージョンだけでなく、開発APIもきちんと書きましょう。

    WPF 4.0以降であれば、標準で用意されているSystem.Windows.WindowクラスのTaskbarItemInfoプロパティを使うことで簡単にプログレスinタスクバーボタンを実現できます(WPF 4.0にて、API Code Packの機能が晴れて正式に採用されました)。

    [C#] WPF 4 を使用して、Windows 7 のタスク バー ボタンに進行状況バー (progress bar) を表示する 言語: C#

    なお、個人的には新規開発でWindows Formsを使うのは推奨しません。
    • 編集済み sygh 2014年9月7日 5:01
    • 回答としてマーク Theia 2014年9月8日 9:21
    2014年9月7日 4:53
  • WPFに興味を持っていただけたことは大変うれしく思います。

    ではとりあえずイントロだけ説明します。

    Visual Studio 2013において、「WpfTaskbarInfoTest1」という名前で、WPFアプリケーションのプロジェクトを作成します。

    次に、下記2つのファイルを書き換えます。

    MainWindow.xaml

    <Window
        x:Class="WpfTaskbarInfoTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350"
        Loaded="Window_Loaded"
        Closed="Window_Closed"
        >
        <StackPanel Margin="10">
            <Button Name="buttonResetProgressValue" Content="Reset Progress Value in Taskbar" HorizontalAlignment="Center" Padding="10" Click="buttonResetProgressValue_Click"/>
            <Separator Height="10" Visibility="Hidden"/>
            <DockPanel>
                <Label Content="Progress State:" VerticalContentAlignment="Center"/>
                <ComboBox Name="comboProgressState" VerticalContentAlignment="Center" SelectionChanged="comboProgressState_SelectionChanged"/>
            </DockPanel>
        </StackPanel>
    </Window>

    MainWindow.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Shell;
    
    namespace WpfTaskbarInfoTest1
    {
    	/// <summary>
    	/// MainWindow.xaml の相互作用ロジック
    	/// </summary>
    	public partial class MainWindow : Window
    	{
    		System.Windows.Threading.DispatcherTimer _timer;
    
    		public MainWindow()
    		{
    			InitializeComponent();
    
    			// デフォルトで TaskbarItemInfo は null なので、コード ビハインドで作成するか、
    			// XAML コードでインスタンスを生成する必要がある。
    			this.TaskbarItemInfo = new System.Windows.Shell.TaskbarItemInfo();
    		}
    
    		private void Window_Loaded(object sender, RoutedEventArgs e)
    		{
    			this.comboProgressState.ItemsSource = Enum.GetValues(typeof(TaskbarItemProgressState));
    
    			this._timer = new System.Windows.Threading.DispatcherTimer();
    			this._timer.Interval = new TimeSpan(0, 0, 1);
    			this._timer.Tick += _timer_Tick;
    			this._timer.Start();
    		}
    
    		private void Window_Closed(object sender, EventArgs e)
    		{
    			if (this._timer != null)
    			{
    				this._timer.Stop();
    				this._timer = null;
    			}
    		}
    
    		void _timer_Tick(object sender, EventArgs e)
    		{
    			if (this.TaskbarItemInfo.ProgressState == TaskbarItemProgressState.Normal)
    			{
    				if (this.TaskbarItemInfo.ProgressValue < 1.0)
    				{
    					this.TaskbarItemInfo.ProgressValue += 0.1;
    				}
    				else
    				{
    					// ループする。
    					this.TaskbarItemInfo.ProgressValue = 0.0;
    				}
    			}
    		}
    
    		private void comboProgressState_SelectionChanged(object sender, SelectionChangedEventArgs e)
    		{
    			if (this.comboProgressState.SelectedItem is TaskbarItemProgressState)
    			{
    				this.TaskbarItemInfo.ProgressState = (TaskbarItemProgressState)this.comboProgressState.SelectedItem;
    			}
    		}
    
    		private void buttonResetProgressValue_Click(object sender, RoutedEventArgs e)
    		{
    			this.TaskbarItemInfo.ProgressValue = 0.0;
    		}
    	}
    }


    あとはビルドして実行し、[Progress State]のコンボボックスの選択肢を色々と変えてみてください。

    なお、今回は初心者向けに、主にコードビハインドを使ってWindows Formsライクに書きましたが、WPF特有の双方向データバインディングやMVVMといった概念を勉強すると、より簡潔で拡張性の高いコードを書けるようになります。

    また、前回投稿にて記載した、MSDNコードサンプルのリンク先も必ず読んでおいてください。

    私の提供するヒントはここまでです。1から10まで他人に教えてもらったことは結局身に付かないので、後は自分でWeb検索を駆使して苦労してみてください。

     

    ちなみに、Windows Formsよりも、WPFのほうがUI設計の柔軟性、特にレイアウトの柔軟性が高くなります。また、WPF/Silverlight/Windowsストアアプリでは、一貫してXAMLを使ってUIデザインを行なうことになるため、ほぼ同じ方法論で開発することができます。

    Windows FormsとWPFの細かな違いは自分で調べてください。

    Windowsフォームで大丈夫か?一番良いのを頼む。

    Windows Formsで作成した膨大なコード資産がある場合は、しばらくWindows Formsを使い続けてもよいとは思いますが、総合的な将来性や応用性があるのはWPFです。

    「Windows FormsにはあるけどWPFにはない機能」というのは確かに存在しますが、WPFベースのアプリケーションでWindows Formsのコンポーネント(カラーダイアログ、タスクトレイアイコンなど)を補助的に使うことは簡単にできます。

    一方で、「Windows FormsにはないけどWPFにはある機能」というのも存在しますが、Windows FormsベースのアプリケーションでWPFのコンポーネント(今回の拡張タスクバーや、マルチタッチ機能など)を使うのは手間がかかります。

    ただ、WPFはWindows Formsと比べて玄人向けの設計思想なので、最初のハードルを越えてWPFの良さが理解できるようになるまでは拒絶反応が出ると思います。とはいえ、これは何にでも当てはまることですが、自分で根気強く調べて試行錯誤できる能力がない場合は結局どちらを選んでも厳しいと思います。
    • 編集済み sygh 2014年9月7日 12:51
    • 回答としてマーク Theia 2014年9月8日 9:21
    2014年9月7日 8:53

すべての返信

  • Windows API Code Pack は NuGet と呼ばれる仕組みで配布されているはずなので、プロジェクトを開いている状態で、ツール - NuGet パッケージマネージャーから検索し、ダウンロード&インストールしてください。

    Windows API Code Pack は単に API などのラッパーに過ぎないので、その内部で使っている API、インターフェースを直接使えば、ライブラリに依存する必要はありません。
    以下の記事を理解し、自力で使えるのであればそちらも手かもしれません。(ただ、COM の知識などハードルは高いし、手間がかかるかと思われます)
    http://msdn.microsoft.com/ja-jp/magazine/dd942846.aspx

    2014年9月6日 8:34
    モデレータ
  • 現在、Windows 7 API Code PackはNuGetの形態で提供されています。NuGetの使い方は別途お調べください。
    2014年9月6日 8:35
  • アプリケーション開発に使っているAPIはWindows Forms(Windows フォーム アプリケーション)ですか? WPFですか?

    質問するときは.NET Frameworkのバージョンだけでなく、開発APIもきちんと書きましょう。

    WPF 4.0以降であれば、標準で用意されているSystem.Windows.WindowクラスのTaskbarItemInfoプロパティを使うことで簡単にプログレスinタスクバーボタンを実現できます(WPF 4.0にて、API Code Packの機能が晴れて正式に採用されました)。

    [C#] WPF 4 を使用して、Windows 7 のタスク バー ボタンに進行状況バー (progress bar) を表示する 言語: C#

    なお、個人的には新規開発でWindows Formsを使うのは推奨しません。
    • 編集済み sygh 2014年9月7日 5:01
    • 回答としてマーク Theia 2014年9月8日 9:21
    2014年9月7日 4:53
  • ご回答ありがとうございます。
    私が開発に使用しているのは、「Windows フォーム アプリケーション」です。
    恥ずかしい話ですが、プログラミングは駆け出しなもので「WPF アプリケーション」というものがあること自体知りませんでした。
    とは言え、質問のしかたに不備があった事をお詫び致します。

    sygh様が「Windows プログラミング」を熟知されていることは、この回答から直観的に理解できました。
    そこでご相談したいのですが、「WPF アプリケーション」は「Windows フォーム アプリケーション」の機能と同等もしくは、それ以上の機能を有しているのでしょうか?
    それとも、状況によって両者を使い分けする必要があるのでしょうか?
    大変大雑把な質問になってしまいましたが、私は「WPF アプリケーション」に関して、全く知識が無いのでご容赦下さい。

    ご回答の最後に「個人的には新規開発でWindows Formsを使うのは推奨しません。」とありましたが、この意味するところは「Windows フォーム アプリケーション」ではなく「WPF アプリケーション」で開発した方が良いと言う事でしょうか?

    実際に、「WPF アプリケーション」のプロジェクトを作成して、タスクバーのアイコンをプログレスバーにしようと試みましたが、「TaskbarItemInfoプロパティ」の使用方法や、どこにそのロジックを書けば良いのか分かりませんでした。
    やはり「WPF アプリケーション」の知識が無いままプログラミングを試みたのが間違いでした。「TaskbarItemInfoプロパティ」のリンク先のサイトの説明だけでは、今の私には理解できませんでした。

    恥を忍んでの、大変厚かましいお願いなのですが、WPF を使ったサンプルのソースコードを書いて頂けないでしょうか。要点だけでも構いません。ご面倒でしたら、参考になるサイトのURLを教えて頂ければ幸いです。
    何卒よろしくお願い致します。

    追伸
     「WPF アプリケーション」に大変興味を持ちましたので、今後勉強していくつもりです。貴重なご意見ありがとうどざいました。
    2014年9月7日 6:49
  • WPFに興味を持っていただけたことは大変うれしく思います。

    ではとりあえずイントロだけ説明します。

    Visual Studio 2013において、「WpfTaskbarInfoTest1」という名前で、WPFアプリケーションのプロジェクトを作成します。

    次に、下記2つのファイルを書き換えます。

    MainWindow.xaml

    <Window
        x:Class="WpfTaskbarInfoTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350"
        Loaded="Window_Loaded"
        Closed="Window_Closed"
        >
        <StackPanel Margin="10">
            <Button Name="buttonResetProgressValue" Content="Reset Progress Value in Taskbar" HorizontalAlignment="Center" Padding="10" Click="buttonResetProgressValue_Click"/>
            <Separator Height="10" Visibility="Hidden"/>
            <DockPanel>
                <Label Content="Progress State:" VerticalContentAlignment="Center"/>
                <ComboBox Name="comboProgressState" VerticalContentAlignment="Center" SelectionChanged="comboProgressState_SelectionChanged"/>
            </DockPanel>
        </StackPanel>
    </Window>

    MainWindow.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Shell;
    
    namespace WpfTaskbarInfoTest1
    {
    	/// <summary>
    	/// MainWindow.xaml の相互作用ロジック
    	/// </summary>
    	public partial class MainWindow : Window
    	{
    		System.Windows.Threading.DispatcherTimer _timer;
    
    		public MainWindow()
    		{
    			InitializeComponent();
    
    			// デフォルトで TaskbarItemInfo は null なので、コード ビハインドで作成するか、
    			// XAML コードでインスタンスを生成する必要がある。
    			this.TaskbarItemInfo = new System.Windows.Shell.TaskbarItemInfo();
    		}
    
    		private void Window_Loaded(object sender, RoutedEventArgs e)
    		{
    			this.comboProgressState.ItemsSource = Enum.GetValues(typeof(TaskbarItemProgressState));
    
    			this._timer = new System.Windows.Threading.DispatcherTimer();
    			this._timer.Interval = new TimeSpan(0, 0, 1);
    			this._timer.Tick += _timer_Tick;
    			this._timer.Start();
    		}
    
    		private void Window_Closed(object sender, EventArgs e)
    		{
    			if (this._timer != null)
    			{
    				this._timer.Stop();
    				this._timer = null;
    			}
    		}
    
    		void _timer_Tick(object sender, EventArgs e)
    		{
    			if (this.TaskbarItemInfo.ProgressState == TaskbarItemProgressState.Normal)
    			{
    				if (this.TaskbarItemInfo.ProgressValue < 1.0)
    				{
    					this.TaskbarItemInfo.ProgressValue += 0.1;
    				}
    				else
    				{
    					// ループする。
    					this.TaskbarItemInfo.ProgressValue = 0.0;
    				}
    			}
    		}
    
    		private void comboProgressState_SelectionChanged(object sender, SelectionChangedEventArgs e)
    		{
    			if (this.comboProgressState.SelectedItem is TaskbarItemProgressState)
    			{
    				this.TaskbarItemInfo.ProgressState = (TaskbarItemProgressState)this.comboProgressState.SelectedItem;
    			}
    		}
    
    		private void buttonResetProgressValue_Click(object sender, RoutedEventArgs e)
    		{
    			this.TaskbarItemInfo.ProgressValue = 0.0;
    		}
    	}
    }


    あとはビルドして実行し、[Progress State]のコンボボックスの選択肢を色々と変えてみてください。

    なお、今回は初心者向けに、主にコードビハインドを使ってWindows Formsライクに書きましたが、WPF特有の双方向データバインディングやMVVMといった概念を勉強すると、より簡潔で拡張性の高いコードを書けるようになります。

    また、前回投稿にて記載した、MSDNコードサンプルのリンク先も必ず読んでおいてください。

    私の提供するヒントはここまでです。1から10まで他人に教えてもらったことは結局身に付かないので、後は自分でWeb検索を駆使して苦労してみてください。

     

    ちなみに、Windows Formsよりも、WPFのほうがUI設計の柔軟性、特にレイアウトの柔軟性が高くなります。また、WPF/Silverlight/Windowsストアアプリでは、一貫してXAMLを使ってUIデザインを行なうことになるため、ほぼ同じ方法論で開発することができます。

    Windows FormsとWPFの細かな違いは自分で調べてください。

    Windowsフォームで大丈夫か?一番良いのを頼む。

    Windows Formsで作成した膨大なコード資産がある場合は、しばらくWindows Formsを使い続けてもよいとは思いますが、総合的な将来性や応用性があるのはWPFです。

    「Windows FormsにはあるけどWPFにはない機能」というのは確かに存在しますが、WPFベースのアプリケーションでWindows Formsのコンポーネント(カラーダイアログ、タスクトレイアイコンなど)を補助的に使うことは簡単にできます。

    一方で、「Windows FormsにはないけどWPFにはある機能」というのも存在しますが、Windows FormsベースのアプリケーションでWPFのコンポーネント(今回の拡張タスクバーや、マルチタッチ機能など)を使うのは手間がかかります。

    ただ、WPFはWindows Formsと比べて玄人向けの設計思想なので、最初のハードルを越えてWPFの良さが理解できるようになるまでは拒絶反応が出ると思います。とはいえ、これは何にでも当てはまることですが、自分で根気強く調べて試行錯誤できる能力がない場合は結局どちらを選んでも厳しいと思います。
    • 編集済み sygh 2014年9月7日 12:51
    • 回答としてマーク Theia 2014年9月8日 9:21
    2014年9月7日 8:53
  •  sygh様 ありがとうございます。

    今回返信下さったサンプルを早速実行しました。『感動の一言です。』

    このフォーラムに質問を投稿する前に、ネットで色んなサイトを見ましたが、「Windows フォーム アプリケーション」で「Windows API Code Pack」を使用する方法しか見つけることが出来ませんでした。
    「WPF アプリケーション」の情報を頂いた時は、正直半信半疑でしたが、実際サンプルが動作するのを見て感動したのと同時に、私がいかに無知だったか思い知った次第です。

    今回の件で、私の進む方向が見えた気がします。幸か不幸かアプリ開発初心者ですので、「Windows フォーム アプリケーション」で作成した資産と呼べるようなものはありません。なので今後は、「WPF アプリケーション」の習得に邁進する考えです。
    ご回答の内容の中に「WPFはWindows Formsと比べて玄人向けの設計思想」とありましたので、少し怖気づきましたが、何事もチャレンジする事が大切ですので、時間を掛けて高見を目指そうと決意した次第です。

    繰り返しになりますが、今回「WPF アプリケーション」の情報を下さった事、お忙しい中サンプルコードを書いて下さった事、開発に関して色々アドバイスして下さった事、本当にありがとうございました。
    2014年9月8日 9:21