ただ、プロジェクトのテンプレートは作成できてもソリューションのテンプレートは作成できないっぽいので、別の形を考えています。(複数プロジェクトを一つのテンプレートにすることはできるみたいですが、ソリューションフォルダの自由度が低いので。)
インストーラのウィンドウのハンドルさえ取得できれば、NativeWindow クラスを使って親子関係を持たせることもできるのですが、生憎取得できないようです。Process.MainWindowHandle で取得できるかとも思いましたが 0 が返ってきました。
そこで、ちょっと知恵を絞り出してみました。
internal static class MyMessageBox
{
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
using (Form dummy = MyMessageBox.ShowDummyForm(caption))
{
return MessageBox.Show(dummy, text, caption, buttons, icon, defaultButton);
}
}
private static Form ShowDummyForm(string caption)
{
Form dummy = new Form();
dummy.TopMost = true;
dummy.ShowInTaskbar = true;
dummy.Opacity = 0;
dummy.ControlBox = false;
dummy.Text = caption;
dummy.Show();
return dummy;
}
}
最前面に固定された透明のダミーウィンドウを表示し、それをメッセージボックスの親ウィンドウにしたわけです。
この方法だとメッセージボックスがタスクバーに表示されませんが、ControlBox プロパティと Text プロパティを変更することで、ダミーウィンドウがちょうど良い具合に代わりを果してくれます。
メッセージボックスが最前面に固定されてしまうという副作用はありますが、まぁ問題ないでしょう。
あと、インストーラのウィンドウとダミーウィンドウ及びメッセージボックスはあくまで無関係ですので、メッセージボックス表示中もインストールウィンドウの操作が従来通りできてしまうことには注意してください。
コマンドラインからビルドするにはどうすれば良いのか調べてみたところ、MSBuild を使ってビルドするようになっていました。
確かに、プロジェクトファイルのフォーマットが MSBuild のフォーマットになっていますし、拡張子も変わっています。
使用するビルド設定に "Release" を指定して "C:\Projects\Sample\Sample.shfbproj" にあるプロジェクトファイルをビルドするには次のコマンドを実行します。
%SystemRoot%\Microsoft.NET\Framework\v3.5\MSBuild.exe /p:Configuration=Release "C:\Projects\Sample\Sample.shfbproj"
MSBuild を使ったビルド方法の詳細は、Sandcastle Help File Builder Help の Building Projects Outside the GUI に記載されています。
イベント名は「コミュニティ勉強会に参加しよう」です。
仙台近辺の方々、是非ご検討頂ければと思います。
(コミュニティ勉強会に参加したことのない僕が宣伝するのもアレですが、ソレはソレということで是非^^;)
static class Program
{
static void Main()
{
Hoge h = null;
h.Safely().Fuga();
}
}
public class Hoge
{
static public readonly Hoge Null = new NullHoge();
public virtual void Fuga()
{
}
private class NullHoge : Hoge
{
}
}
static public class HogeExtension
{
static public Hoge Safely(this Hoge source)
{
return (source != null) ? source : Hoge.Null;
}
}
Imports System.Runtime.CompilerServices
Module Module1
Sub Main()
Dim h As Hoge = Nothing
h.Safely()
h.Fuga()
End Sub
End Module
Public Class Hoge
Public Shared ReadOnly Null As Hoge = New NullHoge()
Public Sub Fuga()
End Sub
Private Class NullHoge
Inherits Hoge
End Class
End Class
Public Module HogeExtension
<Extension()> _
Public Sub Safely(ByRef source As Hoge)
If (source Is Nothing) Then
source = Hoge.Null
End If
End Sub
End Module
Mokosh | VsCommands
ソリューションエクスプローラで、ファイルを複数選択して右クリック → [Group Items] をクリックすると選択したファイルがグループ化される。多段の入れ子にすることもできる。
ファイルの複数選択は Ctrl キー押しながらファイルをクリックしてけばオッケー。
ちなみに、ファイルを入れ子にするって指定は元々プロジェクトファイルがサポートしている機能 (DependentUpon 要素) なので、VSCommands をインストールしていない Visual Studio で開いてもちゃんと入れ子になって表示される。
よし、これでさっきここに書いた
├─ Hoge.cs
├─ Hoge.Test.cs
├─ HogeFactory.cs
└─ HogeFactory.Test.cs
ってのが
□─ Hoge.cs
└─ Hoge.Test.cs
□─ HogeFactory.cs
└─ HogeFactory.Test.cs
って具合に入れ子にできる (^ω^)
追記 (2008/10/17)
バージョン 1.2 がリリースされています。
嬉しい事に、Ctrl キーを押しながら Group Items をクリックすることで、ルートにしたいファイルを選択可能になっています。
また、ファイルを入れ子にする機能以外の機能がいくつか備わったようです。
それと、リンク先の URL が変更になったようなので貼り直しました。
一番の収穫はやはり LINQ to SQL。
つか、LINQ to SQL の場合、where 句のラムダ式が SQL の where 句に変換されるというのは、正直半信半疑だった。
で、帰宅して早速試してみた。
static void Main(string[] args)
{
DataContext context = new DataContext(Settings.Default.Database1ConnectionString);
var query =
from target in context.GetTable<Table1>()
where (target.Column1 == "a")
select target;
string queryText = query.ToString();
Console.WriteLine(queryText);
}
[Table(Name = "Table1")]
class Table1
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int PrimaryKey;
[Column]
public string Column1;
}
実行結果
SELECT [t0].[PrimaryKey], [t0].[Column1]
FROM [Table1] AS [t0]
WHERE [t0].[Column1] = @p0
Σ(゚д゚lll)ガーン
ホントに where 句が where 句に・・・!
そういや、LINQ to SQL のラムダ式はデリゲートではなく System.Linq.Expressions.Expression オブジェクトに変換されると言っていたな。
逆コンパイルしてみると、確かに・・・つーか結構複雑なことやってるな。target.Column1 == "a" というラムダ式から、target とか Column1 とか == 演算子なんかのメタデータを採取して、それを元に Expression オブジェクトを構築するようなコードへと変換されている。
なるほどなるほど。
でもまぁこんなクエリー式はさすがに無理だろ。
var query =
from target in context.GetTable<Table1>()
where (target.Column1[1].ToString() == "a")
where (target.Column1.IndexOf("b") <= 3)
select target;
実行結果
SELECT [t0].[PrimaryKey], [t0].[Column1]
FROM [Table1] AS [t0]
WHERE ((
(CASE
WHEN (DATALENGTH(@p0) / 2) = 0 THEN CONVERT(BigInt,0)
ELSE CONVERT(BigInt,(CONVERT(Int,CHARINDEX(@p0, [t0].[Column1]))) - 1)
END)) <= @p1) AND ((CONVERT(NVarChar(MAX),CONVERT(NChar(1),SUBSTRING([t0].[Column1], @p2 + 1, 1)))) = @p3)
( ゚Д゚ ) ・・・。
"(VS.80)" 有り
IConfigurationSectionHandler インターフェイス (System.Configuration)
"(VS.80)" 無し
IConfigurationSectionHandler インターフェイス (System.Configuration)
で、今度は ConfigurationSection クラスだと、"(VS.80)" が付いている方には「メモ : このクラスは、.NET Framework version 2.0 で新しく追加されたものです。」と書かれているのに "(VS.80)" が付いていない方には書かれていません。
"(VS.80)" 有り
ConfigurationSection クラス (System.Configuration)
"(VS.80)" 無し
ConfigurationSection クラス (System.Configuration)
しかも、よくよく眺めてみると、他にもちらほら違いがあります。
で、更によくよく見ると、"(VS.80)" が付いているページと付いていないページとでは、ページ階層も異なるようで、"(VS.80)" が付いているページは「以前のバージョン」というページの下の方にぶらさがっているようです。
まぁ、だからどうしたと言う訳でもなく、ただそれだけです。
ページによっては、URL から "(VS.80)" を除いたとしても勝手に補完される場合もあるようです。
// using System;
// using System.Drawing;
// using System.Drawing.Imaging;
// using System.IO;
static void Main()
{
Image page1 = new Bitmap("C:\\work\\page3.bmp");
Image page2 = new Bitmap("C:\\work\\page3.bmp");
Image page3 = new Bitmap("C:\\work\\page3.bmp");
// TIFF 形式のエンコーダ。
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
Predicate<ImageCodecInfo> tiffEncoderPredicate =
delegate(ImageCodecInfo input)
{
return (input.FormatID == ImageFormat.Tiff.Guid);
};
ImageCodecInfo tiffEncoder = Array.Find(imageEncoders, tiffEncoderPredicate);
// エンコーダのパラメータ。
EncoderParameters tiffEncoderParameters = new EncoderParameters(2);
tiffEncoderParameters.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
tiffEncoderParameters.Param[1] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionNone);
// 作業領域となるメモリストリーム。
MemoryStream tiffStream = new MemoryStream();
// Save メソッドによって、1ページ目が保存され、更に Image オブジェクトとメモリストリームが関連付けられる。
page1.Save(tiffStream, tiffEncoder, tiffEncoderParameters);
// 2ページ目, 3ページ目の保存に使用するエンコーダのパラメータ。
EncoderParameters pageEncoderParameters = new EncoderParameters(2);
pageEncoderParameters.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage);
pageEncoderParameters.Param[1] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionNone);
// 先ほどの Save メソッドで関連付けられたメモリストリームに対して保存される。
// この操作は page1 にフレームを追加するわけではない。
page1.SaveAdd(page2, pageEncoderParameters);
page1.SaveAdd(page3, pageEncoderParameters);
// メモリストリームの内容をファイルに保存する。
File.WriteAllBytes("C:\\work\\test.tif", tiffStream.ToArray());
}
EncoderParameter のインスタンスを生成する際、EncoderValue 列挙値を long にキャストして渡しています。これは int ではなく long にしなければいけません。でないと失敗します。
サンプルなんで Dispose メソッドは呼び出してません。Image, MemoryStream 以外にも、EncoderParameters や EncoderParameter も IDisposable を実装してます。
このブログの WCF の記事、全部日本語ページへのリンクに張り替えないと。。。