カテゴリー : C#

Siki.Configure #0

今書いてるソースを上げてみる。
連想配列(のようなもの)<->XML を簡単に行うためのクラスです。詳細はいずれ。
作りかけなので、全く整理してないです。

GlobalConfigure.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace Siki.Configure {

    /// <summary>
    /// アプリケーションの設定を管理するクラス
    /// </summary>
    public class GlobalConfigure {

        #region フィールド

        /// <summary>ファイルのパス</summary>
        private string m_fullpath = "";

        /// <summary>現在のアプリケーション設定を表すDOM</summary>
        private XmlDocument m_dom = null;

        #endregion フィールド



        #region イベント
        /// <summary>DOMが初期化されたときに発生するイベント</summary>
        public event EventHandler<ConfigureEventArgs> Initialized;

        /// <summary>ファイルから読み込まれたときに発生するイベント</summary>
        public event EventHandler<ConfigureEventArgs> Loaded;

        /// <summary>ファイルに保存されたときに発生するイベント</summary>
        public event EventHandler<ConfigureEventArgs> Saved;
        #endregion イベント



        #region プロパティ

        /// <summary>
        /// 設定ファイルのフルパスを取得する.
        /// </summary>
        public string FullPath {
            get {
                return m_fullpath;
            }
            protected set {
                m_fullpath = value;
            }
        }

        /// <summary>
        /// XmlDocumentを取得する
        /// </summary>
        protected XmlDocument Dom {
            get {
                return m_dom;
            }
        }

        public ConfigureNode this[string name] {
            get {
                foreach (XmlNode node in Dom.DocumentElement.ChildNodes) {
                    if (node.Name == name && node is XmlElement) {
                        // 見つかった場合
                        return new ConfigureNode(node as XmlElement);
                    }
                }
                // 見つからなかった場合
                // 要素を作成
                XmlElement element = Dom.CreateElement(name);
                // 要素を追加
                Dom.DocumentElement.AppendChild(element);
                //
                return new ConfigureNode(element);
            }
        }
       
        #endregion プロパティ



        #region コンストラクタ

        /// <summary>
        /// デフォルトコンストラクタ.
        /// 設定ファイルをデフォルトのパスに指定する.
        /// </summary>
        public GlobalConfigure()
            : this("conf.xml") {

        }

        #endregion コンストラクタ



        /// <summary>
        /// コンストラクタ.
        /// 設定ファイルをデフォルトのフォルダの @a filename に指定する.
        /// </summary>
        /// <param name="filename">設定ファイル名</param>
        public GlobalConfigure(string filename)
            : this(Application.UserAppDataPath, filename) {

        }

        /// <summary>
        /// コンストラクタ.
        /// 設定ファイルを @a dir フォルダの @a filename に指定する.
        /// </summary>
        /// <param name="dir">設定ファイルのフォルダ</param>
        /// <param name="filename">設定ファイル名</param>
        public GlobalConfigure(string dir, string filename) {
            FullPath = (dir.EndsWith("\\") ? dir : dir + "\\") + filename;
            m_dom = new XmlDocument();
            Load();
        }

        /// <summary>
        /// 設定ファイルを読み込む.
        /// ファイルが存在しない場合は新規に作成する.
        /// </summary>
        /// <returns>XMLの読み込みor作成に成功したか.</returns>
        public virtual bool Load() {
            try {
                if (File.Exists(FullPath)) {
                    // 設定ファイルが存在するとき
                    // ファイルを読み込む
                    Dom.Load(FullPath);
                } else {
                    // 設定ファイルが存在しないとき
                    Dom.AppendChild(Dom.CreateXmlDeclaration("1.0", "UTF-8", "yes"));
                    Dom.AppendChild(Dom.CreateElement("alert"));
                    Save();
                }
            } catch (XmlException) {
                // XMLに関する例外
                throw;
            } catch (Exception) {
                // その他の例外
                return false;
            }
            return true;
        }

        /// <summary>
        /// Initializedイベントを発行する.
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnInitialized(ConfigureEventArgs e) {
            if (Initialized != null) {
                Initialized(this, e);
            }
        }

        /// <summary>
        /// Loadedイベントを発行する.
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnLoaded(ConfigureEventArgs e) {
            if (Loaded != null) {
                Loaded(this, e);
            }
        }

        /// <summary>
        /// 現在のDOMの状態を設定ファイルに書き込む.
        /// </summary>
        /// <returns></returns>
        public virtual bool Save() {
            try {
                Dom.Save(FullPath);
                OnSaved(new ConfigureEventArgs(FullPath));
            } catch (XmlException) {
                // XMLに関する例外
                throw;
            } catch {
                // その他の例外
                return false;
            }
            return true;
        }

        /// <summary>
        /// Savedイベントを発行する.
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnSaved(ConfigureEventArgs e) {
            if(Saved != null){
                Saved(this, e);
            }
        }

        /// <summary>
        /// @a groupname で指定された名前のグループを取得する.
        /// </summary>
        /// <param name="groupname"></param>
        /// <returns></returns>
        public ConfigureNode GetGroup(string groupname){
            foreach (XmlNode node in Dom.DocumentElement.ChildNodes) {
                if (node.Name == groupname && node is XmlElement) {
                    return new ConfigureNode(node as XmlElement);
                }
            }
            XmlElement element = Dom.CreateElement(groupname);
            Dom.DocumentElement.AppendChild(element);
            return new ConfigureNode(element);
        }
    }
}

ConfigureNode.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Siki.Configure {

    /// <summary>
    /// 設定ノード.
    /// </summary>
    public class ConfigureNode {

        /// <summary>
        /// 対応するXmlElementを取得する.
        /// </summary>
        public XmlElement Element {
            get;
            private set;
        }

        /// <summary>
        /// 最初のXmlTextを取得する.
        /// </summary>
        private XmlText Text {
            get {
                foreach (XmlNode node in Element.ChildNodes) {
                    if (node is XmlText) {
                        return node as XmlText;
                    }
                }
                return null;
            }
        }

        /// <summary>
        /// 子ノードを名前で取得するインデクサ.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ConfigureNode this[string name] {
            get {
                foreach (XmlNode node in Element.ChildNodes) {
                    if(node.Name == name && node is XmlElement){
                        // 見つかった場合
                        return new ConfigureNode(node as XmlElement);
                    }
                }
                // 見つからなかった場合
                XmlDocument xmldoc = Element.OwnerDocument;
                // 要素を作成
                XmlElement element = xmldoc.CreateElement(name);
                // 要素を追加
                Element.AppendChild(element);
                //
                return new ConfigureNode(element);

            }
        }

        /// <summary>
        /// このノードの名前を取得する.
        /// </summary>
        public string Name {
            get {
                return Element.Name;
            }
        }

        /// <summary>
        /// このノードの値を取得、設定する
        /// </summary>
        public string Value {
            get {
                XmlText text = Text;
                return text != null ? text.Value : "";
            }
            set {
                XmlDocument doc = Element.OwnerDocument;
                XmlText text = Text;

                if (text != null) {
                    text.Value = value;
                } else {
                    text = doc.CreateTextNode(value);
                    Element.AppendChild(text);
                }
            }
        }


        /// <summary>
        /// コンストラクタ.
        /// </summary>
        /// <param name="element">対応するXmlElement</param>
        public ConfigureNode(XmlElement element) {
            Element = element;
        }

        /// <summary>
        /// ノードの値を取得する.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static implicit operator string(ConfigureNode node) {
            return node.Element.Value;
        }

        /// <summary>
        /// このノードが値を持っているか調べる.
        /// </summary>
        /// <returns>値を持っていれば真.</returns>
        public bool HasValue() {
            return Text != null;
        }

    }
}

ConfigureEventArgs.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Siki.Configure {

    /// <summary>
    ///
    /// </summary>
    public class ConfigureEventArgs : EventArgs{
        private string m_path;

        public string Path {
            get {
                return m_path;
            }
        }

        public ConfigureEventArgs(string path){
            m_path = path;
        }
    }
}

Visual Studio 2010 Beta2

試しに入れてみました。
いろいろ試そうと思ったんですが、あまりにもっさりとしていたので諦めました。
マシンのスペックが足りないようです。
なのでスクリーンショットだけ。普段の配置です。
091122desktop_thumb

2008と同時に起動して同じソリューションを読み込んだときの使用メモリ量。2倍以上使用してます。
091122vsres

2010年3月22日発売予定だそうです。正直あまり期待できないなぁ。

Graphvizを使ってみる

http://www.graphviz.org/

1.ダウンロード&インストール
http://www.graphviz.org/から。
「C:\Program Files (x86)\doxygen」にインストールしたみた。

2.Doxygenの設定
doxywizardを使う場合はExpertタブ内でDotに関する項目を変更するだけです。
最低限「HAVE_DOT」にチェックを入れ、「DOT_PATH」にdot.exeの存在するディレクトリを指定すれば動作します。

3.備考
Doxygen単体での使用と違いgraphvizは画像を生成するので多少時間がかかります。
GRAPHICAL_HIERARCHYのチェックが入っていなければ2回目以降は早くなると思います。

C# × Doxygen [2]

C#では標準のXMLドキュメントを書いておけばDoxygenの方でうまく認識してくれるようです。VC#のエディタならクラスやメソッドの前で「///」と打てばテンプレートを作ってくれるので殆ど覚えることはないです。
Microsoftの推奨タグ

C# × Doxygen [1]

0.はじめに
どうやらC#でもDoxygenが使えるようなので試しに使ってみる。
ここで書いている内容はほんの一例です。
今回はソリューションディレクトリに設定ファイルを置き、その下位の「docs」にドキュメントを作成します。

1.ダウンロード
http://www.doxygen.jp/からダウンロード。
(doxygen-1.6.1-setup.exe)

2.インストール
適当なディレクトリにインストール。自分の場合は「C:\Program Files (x86)\doxygen」。

3.設定ファイルの作成
doxywizard.exeを実行。メニュー「File」→「Save as」でデフォルトの設定ファイルを作成する。ファイル名はデフォルトのDoxyfile。

4.基本設定
Expertタブより。基本的な項目のみ記載。
DOXYFILE_ENCODING : UTF-8
PROJECT_NAME : プロジェクト名 ※今回はソリューション名
OUTPUT_DIRECTORY : ドキュメントを作成するフォルダ
OPTIMIZE_OUTPUT_JAVA : チェック ※C#はJAVAと同じ扱いらしい
INPUT : 解析するディレクトリ ※今回はソリューションディレクトリ
INPUT_ENCODING : UTF-8 ※実際のソースのエンコード
FILE_PATTERNS : 「*.cs」を追加
RECURSIVE : チェック
他は試行錯誤で。だいたい感覚で分かると思います。

5.GUIフロントエンドから実行してみる
Runタブより、「Run doxygen」をクリックするだけ。
「Show HTML output」でそれっぽいページが表示されればとりあえず成功。

6.Visual Studioから実行してみる
メニューの「ツール」→「外部ツール」→「追加」
タイトル : Doxygen(&Y)
コマンド : 2.でインストールした先にあるdoxygen.exe
引数 : Doxyfile
初期ディレクトリ : $(SolutionDir)
「出力ウィンドウを使用」にチェック
以上でメニューから実行できるようになります。

7.ビルド時に実行されるようにする
任意のプロジェクトの「プロパティ」→「ビルドイベント」→「ビルド後に実行するコマンドライン」に以下のように記述する。
cd /d “$(SolutionDir)
“C:\Program Files (x86)\doxygen\bin\doxygen.exe” Doxyfile

「ビルドが成功したとき」にしておけばソリューションのビルド時に一度だけDoxygenが実行される。
今回はソリューション全体を対象としているので、1つのプロジェクトのビルドイベントに記述すれば良い。

ListViewのダブルバッファ

.NetのListViewを使っていてまず気づくのが、項目の追加時やスクロール時に妙にちらつくこと。どうやらデフォルトでダブルバッファがOffになっているらしい。
DoubleBufferdプロパティをtrueに設定すれば良い・・・ということは予想できるが、このプロパティはprotectedになっている。何故publicじゃないんだろう?
解決策は以下のコード。SetListViewDoubleBuffered()にリストビューオブジェクトを渡せばOK。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace Siki {

    [ComVisibleAttribute(false)]
    public class Styles {
        private const int LVM_FIRST = 0x1000;
        private const int LVM_SETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 54);
        private const int LVM_GETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 55);
        private const int LVS_EX_DOUBLEBUFFER = 0x00010000;

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);

        public static void SetListViewDoubleBuffered(ListView listview) {
            int styles = (int)SendMessage(listview.Handle, (int)LVM_GETEXTENDEDLISTVIEWSTYLE, 0, (IntPtr)0);
            styles |= LVS_EX_DOUBLEBUFFER;
            SendMessage(listview.Handle, (int)LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (IntPtr)styles);
        }
    }
}

SendMessage()でウィンドウスタイルを直接変更してます。
64bitアプリケーションでも問題ないようです。

TOP

INFORMATION

未来の自分のためのメモ
管理者:rei