2012年10月31日水曜日

STAThread属性って何?

前々から気になっていた「STAThread属性」。
これって、いったい何なのか?

気になってしょうがないので少し調べてみました。

STAThreadAttribute クラス(MSDN)には、次のように書いてあります。

アプリケーションの COM スレッド モデルがシングルスレッド アパートメント (STA: Single-Threaded Apartment) であることを示します。
はい、言っている意味がまったく分かりません。


そんでもって、Windows フォームのエントリ ポイントを STAThread でマークします(MSDN)には、次のように書いてあります。

STAThreadAttribute は、アプリケーションの COM スレッド処理モデルがシングルスレッド アパートメントであることを示します。この属性は、Windows フォームを使用するすべてのアプリケーションのエントリ ポイントに指定する必要があります。省略すると、Windows コンポーネントが正常に機能しないことがあります。属性がない場合、アプリケーションではマルチスレッドのアパートメント モデルを使用します。このモデルは、Windows フォームでサポートされていません。
ほう、Windows フォームを使用するすべてのアプリケーションのエントリ ポイントには「STAThread属性」を必ず指定する必要があるんですね。

「STAThread属性」を指定しないと、Windows フォームではサポートされていない「マルチスレッドのアパートメント モデル」を使用することになり、正常に機能しなくなると。

なるほど!!
「シングルスレッド アパートメント」や「マルチスレッド アパートメント」に関しては、まったく分かりませんが、今のところは、Windows フォームで作るアプリケーションには「STAThread属性」を必ず指定する必要がある。ということが分かれば十分です。

名前空間(namespace)に関する疑問

C#の名前空間で、気になっていたことを調べたので、その記録。


C#って「グローバル名前空間」ってあるのか?

どうやらC#にも「グローバル名前空間」はあるみたい。
C++を勉強したときに「名前空間」はグローバルスコープを分けるものだと理解しているので、C#でも「グローバル名前空間」があるのは当たり前か。


C#にもグローバル名前空間があるってことは、「グローバル名前空間で変数を宣言できるのか?

調べてみたら、C#の名前空間で宣言できる型は次の6つ。
  • 名前空間
  • class
  • interface
  • struct
  • enum
  • delegate
「名前空間」は型とは言えないだろうけど、含めてます。
詳しくは、MSDNの「namespace (C# リファレンス)」を参照してください。
(こちらにも、似たようなことが書かれていました「C# プログラムの一般構造」)

ちなみに、名前空間で変数を宣言すると、コンパイラに怒られます!


グローバル名前空間から指定するには “global::”を使います。
“::”は「名前空間エイリアス修飾子」といいます。

System.Console.WriteLineメソッドをグローバル名前空間から指定すると次のようになる。


これを実行すると、こんな感じ。


普通に「System.Console.WriteLineメソッド」が呼ばれます。
この例では、何のために「global::」を使うのかが分かりづらいとおもいますが、グローバル名前空間の指定は「曖昧さの解決(名前解決)」に使うためのものだと思います。おそらく、あまり使う機会はなさそうです。

最後に「グローバル名前空間」について参考になったページを紹介。

これすごく分かりやすい。
↓ ↓ ↓



2012年10月29日月曜日

windows ストア アプリのHelloWorld その2(c#)

前回の「windows ストア アプリのHelloWorld その1(c#)」のつづきです。

以下の内容は「"Hello, world" アプリを作成する(手順 3: スタート ページの変更)」を自分で作成した時の記録です。

MainPage.xamlを開き、XAMLデザイナーで "My Application" をクリック。



プロパティパネルの名前の欄に「pageTitle」、種類の欄に「TextBlock」と表示されているのを確認し、共通のTextプロパティの右側にあるボタンをクリック。



値の欄に「Hello, world!」と入力しOKボタンをクリック。
これで、Textプロパティが参照しているリソース(AppName)の編集が完了。



編集した結果は、すぐコードに反映される。



以下のコードをxamlに追加し、要素を追加する。
↓ ↓ ↓
<StackPanel Grid.Row="1" Margin="120,30,0,0">
<TextBlock Text="What's your name?"/>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
<Button Content="Say &quot;Hello&quot;"/>
</StackPanel>
<TextBlock x:Name="greetingOutput"/>
</StackPanel>


ビルドして実行すると、こんな感じになる。



windows ストア アプリのHelloWorld その1(c#)

今日ついにWindows8が発売されましたね。
さっそくWindows8へアップグレード!!タッチパネル操作はできませんが・・・


Visual Studio Express 2012 for Windows 8をインストールしたので、
windowsストアアプリの作り方の勉強開始!!



この記事で紹介している"HelloWorldアプリ"は、「パート 1: "Hello, world" アプリを作成する (C#/VB と XAML を使った Metro スタイル アプリ)」の内容をそのまま試したものです。

ただ、一部説明がわかりづらい部分があったので、作業手順を記録しておきます。


それでは、windows ストア アプリでHelloWorldを作成します!

「Visual Studio Express 2012 for Windows 8」を起動し、メニューから[ファイル] → [新しいプロジェクト]の順にクリック。


つぎのような画面が表示されるので、[インストール済み] → [Windowsストア] → [新しいアプリケーション]の順に選択します。つづけて[名前]の欄に「HelloWorld」と入力して[OK]ボタンをクリックします。


これで、プロジェクトの作成は完了!!
[新しいアプリケーション]テンプレートは、「最小限のwindowsストア アプリ」を作成するためのものだそうです。ここまでの作業で次のように表示されます。



プロジェクトを作成すると自動でいくつかのファイルが作成されます。作成されたファイルはソリューションエクスプローラで確認できます(下の画像)。

なお、「新しいアプリケーションテンプレート」以外の「グリッドアプリケーションテンプレート」や「分割アプリケーションテンプレート」を使用してプロジェクトを作成すると、「~Page.xaml」ファイルの数が増えます。「新しいアプリケーションプロジェクト」で作成した場合は、「MainPage.xaml」ファイルが一つだけ作成されます(下の画像)。

ファイル数の違いからも「新しいアプリケーションテンプレート」は、「最小限のwindowsストア アプリ」を作成するためのものだと確認できます。ほかのテンプレートでプロジェクトを作成したファイルの違いを比べてみてください。



それでは、HelloWorldアプリの作成をつづけます。
パート 1: "Hello, world" アプリを作成する (C#/VB と XAML を使った Metro スタイル アプリ)」のやりかたでは、「MainPage.xaml」を削除して、もう一度「MainPage.xaml」を作成します。

正直、ここが少しわかりづらかった・・・。なんで削除して作り直すの?って感じでした。どうやら、単純なHelloWorldアプリを作るなら削除する必要はなさそう。

では何で作り直すか?というと。「パート 1: "Hello, world" アプリを作成する (C#/VB と XAML を使った Metro スタイル アプリ)」で作成する “HelloWorldアプリ” が単純なつくりではないから。

Windows ストア用のアプリを作成するために必要な知識をつけるための「HelloWorldアプリ」!みたいな感じだど思います。自動作成されるものよりも多機能なクラスを使ってアプリをつくるために、一度削除して作り直します。

それでは、「MainPage.xaml」を削除します。
MainPage.xamlを右クリックして、削除をクリックします。


削除メッセージが表示されたら、OKをクリックしいます。


「MainPage.xaml」を作成します。
メニューから[プロジェクト] → [新しい項目の追加] の順にクリック。


[windowsストア] → [基本ページ] の順にクリックします。
名前に「MainPage」と入力し追加ボタンをクリックします。


[はい]をクリックしいます。
[はい]をクリックすると、ソリューションエクスプローラの「Commonフォルダ」に不足しているファイルが追加されます。


「MainPage.xaml」を作成すると、「デザインビューを更新するには、プロジェクトをビルドしてください」と表示されるので、ビルドします。


エラーがでなければ、HelloWorldアプリの最初のステップは完了です。
デバッグを開始して確認します。


デバッグを開始すると、最初にスプラッシュ画面が表示されます。ここに表示される画像は、ソリューションエクスプローラーのAssetsフォルダにある「SplashScreen.png」です。


スプラッシュ画面が消えると、アプリの画面が表示されます。


ここまでが、HelloWorldアプリの最初のステップです。
パート 1: "Hello, world" アプリを作成する (C#/VB と XAML を使った Metro スタイル アプリ)」をもとに作成しているので、こちらも確認してください。

そうそう、Amezonで「Windows8ストアアプリ開発入門 」という本を発見したので、さっそく予約しました!

2012年8月16日木曜日

c#でファイルのコピー(Fileクラス,FileInfoクラス、FileStreamクラス)

今回はファイルのコピー方法を確認。

ファイルをコピーする方法はいくつかあるようで、FileクラスとFileInfoクラスを使ってコピーするのが一般的なのでしょうか?

ネットで探すと大体このふたつの記事に行き着きますね。
そこで、このふたつのクラスを使ったファイルのコピー方法と、
FileStreamを使ったコピー方法のまとめ。

FileStreamを使ってコピーすることは、あまりないのかもしれません。
あくまで、FileStreamの使い方の勉強ってことで。


■ファイルのコピー(Fileクラス)

FileクラスのCopyメソッドを利用したコピー方法は、パラメータで
「コピー元のファイル/コピー先のファイル/上書き可or不可」を指定する。

static void Main(string[] args)
{
    string sourceFileName = @"e:\sample.txt";
    string destFileName = @"e:\sample_copy.txt";
    bool overwrite = true;

    File.Copy(sourceFileName, destFileName, overwrite);
}



■ファイルのコピー(FileInfoクラス)

Fileクラスでのコピー方法と違う部分は、一度インスタンスを生成してからメソッドを利用する点。
コンストラクタのパラメータで「コピー元のファイル」を指定し、
CopyTOメソッドのパラメータで「コピー先ファイル」と「ファイルの上書き可or不可」を指定する。

ちなみに、msdnでFileInfoクラスの解説部分を読むと、
「オブジェクトを使いまわす場合はFileクラスの静的メソッドのかわりにFileInfoのインスタンスメソッドを使用することを検討してください。」と書いてある。

理由は、FileInfoのインスタンスメソッドを使用すると、必ずしもセキュリティチェックが必要でなくなるから。だそうです。

ということは、Fileクラスを利用する場合は毎回チェックされるということなのかな?
処理が重くなるのか?不明です。

static void Main(string[] args)
{
    string sourceFileName = @"e:\sample.txt";            
    string destFileName = @"e:\sample_copy.txt";
    bool overwrite = true;

    FileInfo fileInfo = new FileInfo(sourceFileName);
    fileInfo.CopyTo(destFileName, overwrite);
}


■ファイルのコピー(FileStreamクラス)

最後にFileStreamでコピーする方法。上の二つを見たら、これを使うことはないでしょうね。

ちなみに、msdnでFileStream.Read メソッドのページを見ると。
戻り値の部分の説明文では、「ストリームの末尾に到達した場合は 0 になることがあります。」とあいまいな感じなのに、解説の部分では、「ストリームの末尾に到達した後に必ず 0 を返します。」とキッパリ言ってる。どっちなの?

ちゃんと英語読めるようになれってことですね(笑)

static void Main(string[] args)
{
    string sourceFileName = @"e:\sample.txt";
    string destFileName = @"e:\sample_copy.txt";
    byte[] buffer = new byte[256];
    int readCount = 0;

    using (FileStream fsSource = new FileStream(sourceFileName, FileMode.Open))
    {
        using (FileStream fsDest = new FileStream(destFileName, FileMode.Create))
        {
            while((readCount = fsSource.Read(buffer, 0, buffer.Length)) != 0)
            {
                fsDest.Write(buffer, 0, readCount);
            }
        }
    }
}


2012年8月11日土曜日

C# DataGridViewコントロールにデータを追加する


C#の勉強をはじめて、1カ月くらいになりますがDataGridViewコントロールがいまいちわからない。
なので、少しずつ勉強。





まずは、簡単にデータグリッドを使う方法から勉強。
具体的には、IDEをつかってデータグリッドビューに列を追加し、コードで行データを追加する方法の確認。


DataGridViewコントロールをフォームに追加する。



追加したDataGridViewをクリックすると右上に小さなボタンが表示されるので、これをクリック。

列の編集をクリック。



列の編集ダイアログが表示されるので、[追加]ボタンをクリック。



データグリッドビューに直接(プログラムから)データを追加する場合は「非バインド列」を選択し
「名前」、「型」、「ヘッダーテキスト」を入力して[追加]ボタンをクリックする。
(この作業を追加する列のかず繰り返す)

「名前」はデータグリッドビューの特定の列の値を取得するときにプログラムで利用する「列名」。
「型」は作成する列に追加するデータの型を指定する。
「ヘッダーテキスト」はデータグリッドビューに表示される「列名」。


列の編集ダイアログにもどると作成した列が左側に表示される。


これで、データグリッドビューに列を追加が完了。
つづけて、プログラムから行を追加する。

行の追加は、
DataGridViewRowCollection.Addメソッド」を利用する
(下図の赤丸部分)



実行すると次のようになる。

2012年8月10日金曜日

C# TreeViewコントロールの項目にアイコンを追加する

今回は、TreeViewコントロールの項目にアイコンを追加する方法を勉強。



利用するコントロールは
・TreeView
・ImageList
の2つ



まず、ツリービューで表示したいアイコンをImageListコントロールのインスタンスに追加します。
imageList1をクリックし、プロパティウィンドウのImagesプロパティをクリックします。すると[...]ボタンが表示されるので、これをクリック。

イメージコレクションエディターが表示されるので、[追加]ボタンをクリックし、使用するアイコンを選択します。


指定したアイコンが表示されます。この作業を利用したいアイコンの数くりかえします。



利用するアイコンをすべて追加したら、コードを編集します。

■コード
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //リストビューに表示するアイコンのリストを設定する
            treeView1.ImageList = this.imageList1;

            //リストビュー全体で利用するアイコンの設定
            treeView1.ImageIndex = 0;
            treeView1.SelectedImageIndex = 0;

            TreeNode n1 = new TreeNode("項目1");
            TreeNode n2 = new TreeNode("項目2");

            //ノードごとに個別のアイコンを設定する
            n1.Nodes.Add(new TreeNode("項目1-1", 1, 1));
            n1.Nodes.Add(new TreeNode("項目1-2", 1, 1));

            treeView1.Nodes.Add(n1);
            treeView1.Nodes.Add(n2);
        }
    }
}

treeView1.ImageList = this.imageList1;の部分が
imageList1に追加したアイコンをリストビューに表示するアイコンとして設定している部分。
。この設定でimageList1に追加したアイコンがツリービューでも利用できるようになる。

treeView1.ImageIndex = 0;
treeView1.SelectedImageIndex = 0;の部分がリストビューの全項目で表示するアイコンを指定する部分。ImageIndexが通常時のアイコンの指定で、SelectedImageIndexが選択中の項目で表示するアイコンの指定。インデックスで指定する数値は、アイコンの登録時に表示されていた数値です。

なお、項目ごとに違うアイコンを表示させたい場合は、

「new TreeNode("項目1-1", 1, 1)」のようにTreeNodeクラスのインスタンス生成時の第二引数と第三引数で指定する。