ページ

2011年12月26日月曜日

◆SharePoint2010クロール設定でのプロキシ

またまた、SharePointで嵌る。

SharePointではコンテンツを検索するためにクロール処理を行なっておく必要がある。
そのクロールの設定でプロキシサーバー設定も出来るのだが、こいつが摩訶不思議な動作をする。

デフォルトではプロキシサーバーは以下のような表示になっている。
image

しかーし、この「なし」には2つの意味があって、本当の「なし」を意味する時と「未設定」を意味するときがある。

「なし」を意味するときはプロキシサーバーを使わない。
「未設定」を意味するときはWinHttpのプロキシー設定を使う。

では、どういう時に「なし」でどういう時に「未設定」なのか。

それは、なななんと、一度も設定変更を行なっていない「なし」は「未設定」で一度でも変更した「なし」は「なし」なのだ。

では、それをどうやってそれを区別するのか。
なななんと、GUI的には確認するすべはない。

SharePoint恐るべし・・・。

 

ちなみに、PowerShellでは以下のコマンドレットでこの設定値を取ってくることができる。

>Get-SPEnterpriseSearchService | select proxytype

結果は、「Default/Proxy/Direct」のいずれかとなる。

しかし、3つの設定値のある項目を2つのGUIに纏めてしまう設計者とは一体どんな人なんでしょうね。

◆SQL Server PowerPivot for SharePointのインストール権限

私はMSのサーバーアプリケーションが大嫌いだ。

正確に言うとMSのサーバーアプリケーションを管理するのが大嫌いだ。

その昔、ProjectServerと格闘して以来嫌悪感さえ感じる。

不運にも、最近SharepointServerを管理する羽目になった。

予想に違わず、メタメタだ。

どこかWordを彷彿させる。

MS好きの私が、これだけ嫌なのだからMS嫌いの人はどれだけ嫌になることやら。
MS嫌いの人はもともとこんなの触らないか・・・。

 

SQL Server PowerPivot for SharePointというのをインストールしているのだがインストールアカウントにサーバーファーム管理者権限がないといってエラーになる。
image

ドメインのAdministratorでインストールしてこんなエラーが出るのは不可解だ。
サーバーファーム管理者にはデフォルトでBUILTIN\Administratorsが入っているのだから。
試しにドメインのAdministratorを明示的にファームAdministratorsに追加しても駄目。

SharePointをインストールした時のユーザーじゃないと駄目なのだろうか。

2011年12月22日木曜日

◆サクラエディタとキングソフト辞書の干渉

サクラエディタを使っていて、なぜか上書きコピー出来ない現象に嵌った。

インサート貼り付けは問題ない、キーボードから上書きも出来るのに上書き貼り付けだけが効かないのである。

サクラエディタの設定をいくら眺めても設定関係では無さそう。

かなり悩んで試行錯誤した所、上書き貼り付けができないのではなく、文字列を選択しただけでコピーされてしまうのだと判った。
上書きしようと対象文字列を選択した段階でその文字列がコピーされてしまうので結果的に同じ文字列が上書き貼付けされて、あたかも上書きできていないように見えてしまう。

なぜこんなことになってしまったのか。
それほど頻繁に使っているわけでは無いので、いつからおかしくなったのかも判らない。

あれやこれや試してみて、やっと判った。

どうもキングソフト辞書と干渉しているようである。
このソフトは「Ctrl」キーを押すとカーソル下の単語を翻訳、文字列選択するとその文章を翻訳してくれる。

良くは判らないのだが、このソフトの翻訳機能を一時的に無効にした所、今回の不思議な現象が止まった。

果たしてどちらが悪いのか・・・。

2011年12月20日火曜日

◆SharePoint2010はエクスプローラビューが無くなった

理由はよくわからないがSharePoint2010はエクスプローラビューが無くなった模様。(なんでですかねぇ・・・・)

しかし、WebDavはそのまま使えるようなので、「\\サーバー名\DavWWWRoot\sites\サイト名」を使えば良さげ。

2011年12月13日火曜日

◆なぜかGmailが遅い場合の対処方法(IE8)

娘に与えていたお下がりのLetsNoteがとうとうお亡くなりになって、(HDD交換すればまだ使えそうなのだが)、10年も使っているのでその後何年使えるかと考えつつ思案しながらAmazonを眺めていたらEeePCが2万程度で代えるのを見つけて衝動買い。(クリスマスプレゼントにしました)

娘はネットサーフィンしかしないので必要十分。
ノートPCが2万で買えるとは良い時代になったものだ。(LetsNoteは確か18万位で買ったような記憶がある)

ネットワークセットアップも終わり、IEを立ち上げてGoogle接続もOK

完了、と思いきや、Gmailが返ってこない。
そのまま放置すると何分かしてつながりはするのだが、これでは使いものにならない。
はて。

再起動とかしても変わらず、Gmail以外はサクサクなのに・・・。
Flashとか?
と思ってFlashを使っている他のサイトにアクセスしたが問題なし。
IE9に上げれば良いのかな・・・。

と思って一応ネットを探すとIEをリセットすると直るとか。

リセットたってあーた、さっきセットアップしたばかりですから。
と思いながら一応リセットすると、なんとサクサク動くじゃないですか。

ん~、IE恐るべし。

ちなみにリセットは、「ツール」「インターネットオプション」「詳細設定」で「リセット」ボタンをクリック。

2011年12月12日月曜日

◆ASP.NET MVC 検証機能を追加する

前回のサンプルに検証機能を追加してみる。

Viewの設定

まずはエラーが有った時に表示する文言をViewに設定しておく。

<body>
<div>
<% using (Html.BeginForm("MyPost", "HelloWorld", FormMethod.Post))
{%>
<label>名前:</label>
<%: Html.TextBox("name","<初期値>") %>
<%: Html.ValidationMessage("name", "必須未入力エラーです", new { @Style = "color:red;font-weight:bold;" })%>
<input type="submit" value="送信" />
<% } %>

</div>
</body>

追加したのは7行目。
HtmlはViewPageクラスのHtmlプロパティでHtmlHelper型。そのValidationMessageメソッドを呼び出すとModelStateDictionaryの中身を調べて第1引数で指定したコントロールにエラーが有るか調べてくれる。エラーが有った場合は第2引数で指定したメッセージをHTMLとして出力する。第3引数はそのメッセージのStyleと言った感じだ。
実際ModelStateDictionaryの中身を作るのはコントローラー側の仕事だ。


ちなみに、ValidationMessageメソッドは拡張メソッドになっていて、実際にはValidationExtensionsクラスで実装されている。


コントローラーでエラーチェック


View側で表示の準備が出来たので、こんどはコントローラー側で入力チェックを行い、エラーがあればModelStateDictionaryにエラー内容を突っ込んでいけば良い。
ModelStateDictionaryはControllerクラスのModelStateプロパティで参照可能だ。


        [HttpPost]
public ActionResult MyPost(string name)
{
if (String.IsNullOrEmpty(name)){ModelState.AddModelError("name", "");}

if (!ModelState.IsValid) { return View(); }

ViewData["HelloName"] = "Hello " + name;
return View("Result");
}

 


ここでは、単純にPostされてきたname引数が空だったらModelStateDictionaryのAddModelErrorメソッドでエラーを追加している。
第1引数がエラーのあったコントロール、第2引数がエラーメッセージ。
(View側でエラーメッセージまで定義したのでとりあえずこちらでは何も指定してない。)


実際には、ここで様々な入力項目のチェックを行い、その結果1つでもエラーが有ったかどうかを6行目のIsValidプロパティで判定することになる。
エラーが無ければ9行目で結果画面を表示させるし、エラーがあればそのままView画面に差し戻しといった感じである。


結果


2011-11-28 11h18_47


エラー表示にスタイルシートを使う


上記エラー画面のソースは以下のようになっている。


5行目、6行目を見ると「input-validation-error」、「field-validation-error」というクラス名が付与されているのが判る。
HtmlHelperクラスがエラーに応じて付与してくれるのだろう。
MVCプロジェクトには予めSite.cssというスタイルシートが用意されているので、それを使えば良いようだ。


スタイルシートを使うように変更したソースは以下の通り。


<body>
<div>
<form action="/HelloWorld/MyPost" method="post">
<label>名前:</label>
<input class="input-validation-error" id="name" name="name" type="text" value="" />
<span Style="color:red;font-weight:bold;" class="field-validation-error">必須未入力エラーです</span>
<input type="submit" value="送信" />
</form>

</div>
</body>

<head runat="server">
<title>MyPost</title>
<link rel="Stylesheet"
type="text/css" href="../../Content/Site.css"/>
</head>
<body>
<div>
<% using (Html.BeginForm("MyPost", "HelloWorld", FormMethod.Post))
{%>
<label>名前:</label>
<%: Html.TextBox("name","<初期値>") %>
<%-- <%: Html.ValidationMessage("name", "必須未入力エラーです", new { @Style = "color:red;font-weight:bold;" })%>
--%>
<%: Html.ValidationMessage("name", "必須未入力エラーです")%>
<input type="submit" value="送信" />
<% } %>

</div>
</body>

3行目でスタイルシートへの参照を追加して、12行目して指定していた個別のスタイル指定を削除した。


しかし、これで実行すると、


2011-11-28 11h57_22


といった表示になってしまい、なんとなくイマイチ。
あー、このスタイルシートはデフォルトで作られている以下のページ用なのね・・・。
2011-11-28 11h58_59


さしあたって、Validation関係のスタイル以外は削除し以下の通りとした。


/* Styles for validation helpers
-----------------------------------------------------------*/
.field-validation-error
{
color: #ff0000;
}

.field-validation-valid
{
display: none;
}

.input-validation-error
{
border: 1px solid #ff0000;
background-color: #ffeeee;
}

.validation-summary-errors
{
font-weight: bold;
color: #ff0000;
}

.validation-summary-valid
{
display: none;
}

サマリーエラーの表示


よくあるパターンとして、エラー内容を個々に表示するのではなく、サマリーとして纏めて表示する方法がある。


それには、Html.ValidationSummaryメソッドを使うと良い。
エラーチェック(Actionメソッド)側では、ModelState.AddModelError("name", "サマリーエラー")としてエラーメッセージを指定する。


        [HttpPost]
public ActionResult MyPost(string name)
{
if (String.IsNullOrEmpty(name)){ModelState.AddModelError("name", "サマリー用エラー発生");}

if (!ModelState.IsValid) { return View(); }

ViewData["HelloName"] = "Hello " + name;
return View("Result");
}
}

<body>
<div>
<% using (Html.BeginForm("MyPost", "HelloWorld", FormMethod.Post))
{%>
<label>名前:</label>
<%: Html.TextBox("name","<初期値>") %>
<%-- <%: Html.ValidationMessage("name", "必須未入力エラーです", new { @Style = "color:red;font-weight:bold;" })%>
--%>
<%: Html.ValidationMessage("name", "必須未入力エラーです")%>
<%=Html.ValidationSummary("以下のエラーが発生しました。")%>
<input type="submit" value="送信" />
<% } %>

</div>
</body>

2011年12月9日金曜日

◆PowerPivotでスライサーの追加エラー

ExcelのアドオンであるPowerPivotを検証している。

機能的には気に入ったが、若干動作が不安定で、再起動すると直ったりする。

Webサイトからテーブルデータをコピペしてシートを作り、ピボットテーブル化してスライサーを追加しようとした所以下のようなエラーが出た。(スライサーフィールドを追加できませんでした)

image

なぜだかよくは判らないが、対処方法としては「Ctrl + Alt + F5」で最新状態に更新してやると良いようだ。

2011年12月5日月曜日

◆SQLServerの外部接続を許可する

全くのFAQと思うが、いつも忘れるのでメモしておく。(今回は2008R2で確認している)

  1. 「SQL Server Configuration Manager」の「SQL Server ネットワークの構成」にて「TCP/IP」プロトコルを「有効」にする。
    image
  2. ファイアウォールの設定
    1. コントロールパネルにて「Windows ファイアウォール」を開く。
      image
    2. 「Windowsファイアウォールを介したプログラムまたは機能を許可する」をクリック。
      image
    3. 「別のプログラムの許可」ボタンをクリック。
      image
    4. 「参照」ボタンをクリックしSQLServerのプログラムの場所を指定。(デフォルトではC:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Binn\SQLServer.exe)
      image

      ※ポートを指定して穴を開ける方法でも良いが、SQLExpressなどは動的なポートを使うため、プログラムを指定する方法で統一しておいたほうが良いかも。
  3. SQLServerインスタンスをブラウズ(一覧検索)する必要がある場合は、先の「SQL Server Configuration Manager」で「SQL Server Browser」を自動開始にしておく。
    image

2011年11月25日金曜日

◆ASP.NET MVC Postデータを取得する

 

ポストページ表示用Actionメソッド

まずは、Post用のページを表示するためのActionメソッドを定義する。(ここではMyPostとした)

ちなみに、ActionメソッドはActionと入力しTab,Tabでコードスニペットを使うのが良さそうだ。

        public ActionResult MyPost()
{
return View();
}

次にこのメソッドの場所で右クリックして「ビューの追加」を選択。
2011-11-25 15h13_39


ポストページ表示用ビューサンプル


MyPost.aspx


<body>
<div>
<% using (Html.BeginForm())
{%>
<label>名前:</label>
<%: Html.TextBox("name","<初期値>") %>
<input type="submit" value="送信" />
<% } %>

</div>
</body>

ここではまず、HtmlヘルパークラスのBeginFormメソッドを使ってFormタグを展開している。
その中に、ラベル、テキストボックス、ボタンを配置。
テキストボックスにはこれもまたHtmlヘルパークラスのTextBoxメソッドを使用した。
これで表示される画面とソースは以下の通り。
2011-11-25 16h39_42


2011-11-25 16h40_48


ヘルパークラスを使っても、それほど便利という感じでもないが、最近ではRazor記法とかが出てきているようなのでそちらを使ったほうが良いのだろう。


ちなみに、これも最近の機能っぽいが、<%:  %> とするとHTMLエンコードまでやってくれるらしい。


なお、<% using (Html.BeginForm("MyPost", "HelloWorld", FormMethod.Post))とすることでactionとmethodを明示的に指定することも可能。


ポストされたデータを処理するアクションメソッド


基本的には入力画面を表示したアクションメソッドと同じメソッド名になるのだが、区別するためにこちらには[HttpPost]属性を付加する。(というかActionPostスニペットで展開させるとそうなる)
また、ポストされたデータを受け取るためにメソッドに引数を指定する。ここでは画面入力された「name」の値を取得するために(string name)としている。


入力値はRequestプロパティから参照できるHttpRequestオブジェクトからも取得できる(Request.Form(“name”))ので引数の指定は必須では無いようにも思うが、シグネチャが被るので1つは指定しないといけないだろう。


取得したポストデータは画面に渡すためにViewData["HelloName"]に入れておく。


このケースではアクションメソッドの名前と、結果を表示するためのビューの名前が異なるため、Viewメソッドにビューの名前を引数で与えている。


        [HttpPost]
public ActionResult MyPost(string name)
{
ViewData["HelloName"] = "Hello " + name;
return View("Result");
}

結果を表示するビュー


上記で設定されたViewDataを取ってきてそのまま表示するだけだ。


<body>
<div>
<%:ViewData["HelloName"]%>
</div>
</body>

◆ASP.NET ユーザーパラメータを受け取る

ユーザーパラメータを受け取るにはActionメソッドの引数に指定すれば良い。

        public ActionResult Index(string id)
{
ViewData["param1"] = "パラメータ1です。";
ViewData["id"] = String.Format("ユーザーパラメータは({0})です。",id);
return View();
}

<body>
<div>
Hello World !!<br/>
<%=Html.Encode(ViewData["param1"]) %><br />
<%=Html.Encode(ViewData["id"]) %><br />

</div>
</body>

2011-11-25 14h41_48


なお、パラメータを増やすにはGlobal.asaxのルーティング定義にパラメータを追加してあげれば良い。


image


image


image


2011-11-25 14h52_08

◆ASP.NET MVC コントローラーからビューにデータを渡す

コントローラー側は、ControllerベースクラスにViewDataプロパティが用意されている。
これは、ViewDataDictionaryクラスになっていて「Key」「Value」で値が設定できるので以下のようにKey名称を適当に決めて値をセットしてあげれば良い。

        public ActionResult Index()
{
ViewData["param1"] = "パラメータ1です。";
return View();
}

受け取り側のビューでも同様にViewData[“param1”]とやれば値が取ってこれる。
HTMLに埋め込むには<%=……%>コードブロックを使えば良さげ。(かつてのASPっぽい感じかな)


また、HTMLエンコードにはヘルパークラスが提供されていて、Html.Encode()メソッドが使える。


<body>
<div>
Hello World !!<br/>
<%=Html.Encode(ViewData["param1"]) %>
</div>
</body>

2011-11-25 14h17_12

◆ASP.NET MVC ルーティング

ルーティングはGlobal.asaxで定義されている。

    public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // ルート名
"{controller}/{action}/{id}", // パラメーター付きの URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // パラメーターの既定値
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);
}
}

RouteCollection型となっているので複数のルーティングを定義できるのだろう。
初期状態では”Default”というルーティングが定義されていて、
「コントローラー名/アクション名/パラメータ」でルーティングされるようだ。


ControllerにはHome、actionにはIndexが初期値として定義してあるので、例えば
「http://ホスト名/コントローラ名」でアクセスされたときにはIndexアクションが実行されてIndexページが返るという仕掛けなのだろう。

◆ASP.NET MVC でHelloWorld

 

以下のサイトを参考にしながら自分なりに勉強してみる。
連載:ASP.NET MVC入門 - @IT

新しいプロジェクトの作成

image

使っているVisualStudioのバージョンやインストールしているMVCモジュールのバージョンによってMVC2だったりMVC3だったりする。(ここではVisualStudio2010の素の状態を使っている)

デフォルトのフォルダ構成

2011-11-21 10h46_402011-11-21 10h49_26

コントローラークラスを作る

    1. 「ソリューションエクスプローラー」で「Controllers」フォルダを右クリックして「追加」「コントローラー」を選択。
      image
    2. 「コントローラーの追加」ダイアログで「コントローラー名」を指定する。
      xxxxControllerという名前にする必要がある。
      image
    3. 「Controllers」フォルダにコントローラーソースが追加される。
      image
      「AccountController」と「HomeController」はテンプレートが追加したもの。
    4. Viewを返す。
      デフォルトでActionResultオブジェクトを返すIndexメソッドが定義されるので、その中でとりあえずViewメソッドを呼んでやるとIndexメソッドに対応したIndex.aspxがブラウザに返るという仕組みのようだ。
      Viewメソッドは継承元のControllerクラスで定義されている。
      ActionResultは抽象クラスなので実際には、それを実装したViewResultオブジェクトを返している。

ビューを作る

Index.aspxを返すコントローラークラスが出来たので、あとはIndex.aspxの実体をViewとして作ってあげる。

    1. 追加された「HelloWorldController」クラスの「Index」メソッド上で右クリックして「ビューの追加」を選択する。
      2011-11-21 11h18_59
    2. 表示されたダイアログでオプションを全てOFFにした状態で「Index」ビューを追加する。
      2011-11-21 11h22_28
    3. 「Views」フォルダーに下にコントローラーと同名のフォルダが作られ、「Index.aspx」ページが追加される。
    4. デフォルトで以下のようなシンプルなHTMLの雛形が作られるので、とりあえず「Hello World!!」だけ追加してみた。
      <html xmlns="http://www.w3.org/1999/xhtml" >
      <head runat="server">
      <title>Index</title>
      </head>
      <body>
      <div>
      Hello World !!
      </div>
      </body>
      </html>

    5. コントローラーとViewの関係を簡単にまとめるとこんな感じだろうか。2011-11-25 11h25_02

動作確認



ここまでとりあえずF5キーを押して動作を確認すると、最初はひな形で作られた以下の画面が表示されるので、適切なドレスに変更する。
2011-11-25 11h59_56


今回の場合は、こんな感じになる。
2011-11-25 12h02_49

2011年11月13日日曜日

◆WPF バインディング2

<オブジェクトとのバインディング>

今度は、コントロール同士ではなくコードビハインド側で作成したオブジェクトとコントロールをバインドしてみる。

とりあえず、画面表示用に以下のXAMLを定義した。

<Window x:Class="BindingSample.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300" Name="MyWindow">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="名前:"/>
<TextBox Text="{Binding Name}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="住所:"/>
<TextBox Text="{Binding Address}" />
</StackPanel>
</StackPanel>
</Window>

image


バインドするエンティティのクラスはとりあえず以下のとおり。


    class Person
{
public string Name { get; set; }
public string Address { get; set; }
}

あとはコードビハインドで、このクラスのインスタンスを作り、WindowのContextに設定してあげれば良い。


        public Window2()
{
InitializeComponent();

Person p = new Person { Name = "原 辰徳", Address = "相模原市1-1" };
this.MyWindow.DataContext = p;
}

バインド先のTextBoxは自分の親を直近から探していって最初に見つかったDataContextを使う。(包含継承というらしい)


image


コントロールの時と同様にコードだけでバインドすると以下のようになる。


        public Window2()
{
InitializeComponent();

Person p = new Person { Name = "原 辰徳", Address = "相模原市1-1" };
//this.MyWindow.DataContext = p;
var bindName = new Binding();
bindName.Path = new PropertyPath("Name");
bindName.Source = p;
txtName.SetBinding(TextBox.TextProperty, bindName);

var bindAddr = new Binding();
bindAddr.Path = new PropertyPath("Address");
bindAddr.Source = p;
txtAddr.SetBinding(TextBox.TextProperty, bindAddr);
}

9行目と14行目はDataContextを指定すれば不要になる。
また、Bindingクラスのコンストラクタ引数にPathを文字列で指定できるようなので8行目と13行目も省略できることになる。


        public Window2()
{
InitializeComponent();

Person p = new Person { Name = "原 辰徳", Address = "相模原市1-1" };
this.MyWindow.DataContext = p;
var bindName = new Binding("Name");
txtName.SetBinding(TextBox.TextProperty, bindName);

var bindAddr = new Binding("Address");
txtAddr.SetBinding(TextBox.TextProperty, bindAddr);
}

少し簡単になった。


ちなみに、バインドモードは指定しなければDefaultという値になり状況に応じてWPFが決めてくれるらしい。TextBoxの様に入力可能なコントロールとバインドした場合は双方向になるとのこと。
ただし、TextBoxは依存関係プロパティになっていて変更通知機能があるのでTextBoxの変更をDataContextに伝えることができるが、DataContextへの変更はそのままではTextBoxに伝わらないのだと。


一般的にはDataContextに指定されたCLRオブジェクトに対してはINotifyPropertyChangedインタフェースを実装することにより変更通知を行う必要がある。


とりあえずDataContextの値を確認する為にボタンを追加してソースを以下の様に変更した。


image


    public partial class Window2 : Window
{
Person p = new Person { Name = "原 辰徳", Address = "相模原市1-1" };
public Window2()
{
InitializeComponent();

this.MyWindow.DataContext = p;
var bindName = new Binding("Name");
txtName.SetBinding(TextBox.TextProperty, bindName);

var bindAddr = new Binding("Address");
txtAddr.SetBinding(TextBox.TextProperty, bindAddr);
}
//DataContextの値を確認
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(p.Name + ":" + p.Address,"DataContextの確認");
}
//名前を長島に
private void Button_Click_1(object sender, RoutedEventArgs e)
{
p.Name = "長島茂雄";
}
}


これで確認してみると確かにDataContextへの変更はTextBoxに反映しないことが分かった。


DataContextに設定しているPersonクラスにINotifyPropertyChangedインタフェースを実装したのが以下のソース。
PropertyChangedイベントを発せさせれば良いだけだ。
(まったく決まりきった実装になるようだ)


    public class Person : INotifyPropertyChanged
{
private string _name;
private string _address;
public string Name
{
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
_name = value;
OnPropertyChanged("Name");
}
}
public string Address
{
get
{
return _address;
}
set
{
if (_address == value)
{
return;
}
_address = value;
OnPropertyChanged("Address");
}
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var d = PropertyChanged;
if (d != null)
{
d(this, new PropertyChangedEventArgs(propertyName));
}
}
}

確かにDataContextへの変更が即座にTextBoxへ反映されるようになる。


image

2011年11月6日日曜日

◆WPF バインディング

<コントロール同士のバインディング>

まずは、WPFのバインディングで最初の頃必ず出てきたテキストボックスとスライダーのバインディング。
スライダーを動かすと数値が変化し、数値を入力するとスライダーが動くというやつだ。(双方向のバインディング)

image

XAMLはこんな感じになる。

<Window x:Class="BindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBox Name="myValue">0</TextBox>
<Slider Maximum="100" Minimum="0" Value="{Binding ElementName=myValue, Path=Text}" />
</StackPanel>
</Window>

スライダーのvalueプロパティにテキストボックスのTextプロパティをバインディングするには、
Value="{Binding ElementName=myValue, Path=Text}"
というようにバインドするコントロール名とプロパティ名を指定してあげる。
ちなみに、この{}で囲んだ書き方は「マークアップ拡張」と呼ばれるXAML独自の記法(多分)で、本来は以下のように書くべきもの。


        <Slider Maximum="100" Minimum="0">
<Slider.Value>
<Binding ElementName="myValue" Path="Text" />
</Slider.Value>
</Slider>


多分バインドは多用されることになるためシンタックスシュガー的に簡略記法を用意したのだろう。
ただし、私などは最初この省略形であるということが分からずにどうもピンと来なかった。
というか世の中のサンプルを見ていると様々な記法で書かれており(Pathというキーワードも省略できたり)、一体何が違うのかと混乱していた。
バージョンが上がって省略記法が用意されれば解りやすかったのだが、私のような素人にはちょっと取っ付きづらい部分だった。(最初から気が効きすぎていたというか)
また、上記TextBoxにはNameプロパティで名前を指定しているのだが、これもサンプルによってはx:nameと別のネームスペースを使っていたりして混乱した。
今回再勉強して分かったのは、この名前空間はXAML独自の名前空間らしいということ。WPFとして用意されていない要素、属性などはXAMLとして独自に拡張した機能をこの名前空間で提供しているらしい。
なのでnameプロパティにしてもWPFでもともと存在しているものについてはそれを使えばよいし、nameプロパティを持たないコントロールなどを参照したいときはx:nameで名前をつけてあげれば良い。


データバインドは必ずしも1対1でなくとも良いので、最初のサンプルに省略しない記法で書いたスライダーをもう一つ追加するとこんな感じになる。


<Window x:Class="BindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBox Name="myValue">0</TextBox>
<Slider Maximum="100" Minimum="0" Value="{Binding ElementName=myValue, Path=Text}" />
<Slider Maximum="100" Minimum="0">
<Slider.Value>
<Binding ElementName="myValue" Path="Text" />
</Slider.Value>
</Slider>

</StackPanel>
</Window>


image


どちらのスライダーを動かしても双方張り付いて全く同じに動く。


ちなみに、このnameプロパティの値はは大文字と小文字が区別され、間違ったりしてもエラーにならないので注意が必要だ。


Bindオブジェクト(要素)はModeプロパティでバインド方向を、
image
UpdateSourceTriggerプロパティでそのタイミングも指定できるようになっている。
image


ここで、こんどはXAMLではなくコードでバインドするとどうなるか試してみた。
Sliderをもう一つ追加し名前を”mySlider”とした。


        <Slider Maximum="100" Minimum="0" Value="{Binding ElementName=myValue, Path=Text}" />
<Slider Maximum="100" Minimum="0">
<Slider.Value>
<Binding ElementName="myValue" Path="Text" />
</Slider.Value>
</Slider>
<Slider Name="mySlider" Maximum="100" Minimum="0" />



        public Window1()
{
InitializeComponent();

var bind = new Binding();
bind.ElementName = "myValue";
bind.Path = new PropertyPath("Text");

mySlider.SetBinding(Slider.ValueProperty, bind);
}


XAMLの省略していない方の記述を見ながらそのとおりにコーディングしていけばよいので、それほど難しくはない。XAMLが入れ子で表現している部分はSetBindingメソッドを使ってあげれば良いようだ。
SliderのプロパティはSlider自身が持っているxxxPropertyスタティックプロパティが使える。
PropertyPathクラスのコンストラクターで指定している引数(型の定義はobjectになっている)も本来はTextBox.TextPropertyなのだと思うがXAMLと同様に”Text”でも動作してくれる。
PropertyPathクラスは以下のような定義になっているので、
[TypeConverterAttribute(typeof(PropertyPathConverter))]
public sealed class PropertyPath
ここで指定されたPropertyPathConverterが文字列からTextPropertyへの変換をしているのかな・・・。


単純に考えれば、文字列を取るコンストラクターを用意すればよいだけに思えるのだが・・・。
そうか、こいつはコンパイル時に変換してくれるという事なのかも。


<自分自身や親要素とのバインド>


        <TextBox Height= "65"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Path=Title}"
Width="{Binding RelativeSource={RelativeSource Self}, Path=Height }" />

バインドの対象を指定するのにはnameプロパティを参照する以外にも、このような指定もできる。


2行目では自分の親をたどってWindowコントロールを探し、そのタイトルプロパティとバインドしている。
はっきり言ってちょっと複雑・・・。
それほど使う機能でも無いのでこんなものだとメモしておけば良いか・・・。


4行目はWidthプロパティに対して自分自身のHeightプロパティをバインドしている。(結果的に正方形になる)


ココらへんは記法は面倒だが、当初に比べればだいぶインテリセンスが効いてくれるのですこしは楽になった。

◆Googleも殿様商売になってきたなぁ(いやーな感じ)

下の子がメールアドレスが欲しいというので登録してあげようと思ったのだが、いつも悩まされる認証確認の文字がいつもにも増して読めない。

image

いったい誰がこんな文字をまともに読めるのだろう。
都度パスワードをクリアしたくらいにして(仕方ないとはいえ)。

だんだん腹立たしく思えてきた。
しかもそのうち年齢制限がどうとかエラーになり始めた。

・・・・。

かなーり奮闘してやっと通ったと思ったらこんどは携帯で認証が必要なんだと。

image

以前はこんなのなかったのに・・・。
おれは携帯なんぞ持っていないっちゅーに。

たとえ持っていても教えたくはない!!

Google、いやーな感じぃ・・・・

驕れる者久しからず。

2011年10月30日日曜日

◆WPF FirstBinding

[WPF]レイアウトに飽きてきたのでバインディングしてみる

サンプルは基本的に上記サイトからそのまま引用させてもらっている。

<XAML>

<Window x:Class="DockPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<Label Content="値:" Grid.Row="0" Grid.Column="0" />
<Label Name="valueLabel" Content="ここに値が来ます" Grid.Row="0" Grid.Column="1" />
<Label Content="概要:" Grid.Row="1" Grid.Column="0" />
<Label Name="descriptionLabel" Content="ここに概要が来ます" Grid.Row="1" Grid.Column="1" />
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" >
<Button Name="incrButton" Content="インクリメント" Margin="2" Click="incrButton_Click" />
<Button Name="decrButton" Content="デクリメント" Margin="2" Click="decrButton_Click" />
<Button Name="dumpButton" Content="Dump" Margin="2" Click="dumpButton_Click" />
</StackPanel>

</Grid>
</Window>

<ソース>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

namespace DockPanel
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
Counter _counter;
BindingExpressionBase _valueBindingExpression;

public MainWindow()
{
InitializeComponent();

//カウンタを作る
_counter = new Counter(){Description="サンプルカウンター"};
InitializeBinding();
}

private void InitializeBinding()
{
Binding valueBinding = new Binding("Value");
_valueBindingExpression = BindingOperations.SetBinding(
valueLabel, Label.ContentProperty, valueBinding);

Binding descriptionBinding = new Binding("Description");
BindingOperations.SetBinding(
descriptionLabel, Label.ContentProperty, descriptionBinding);

// カウンタをDataContextに!
this.DataContext = _counter;
}

class Counter
{
public int Value { get; private set; }
public string Description { get; set; }

public void Incr()
{
Value++;
}
public void Decr()
{
Value--;
}
}

private void incrButton_Click(object sender, RoutedEventArgs e)
{
_counter.Incr();
_valueBindingExpression.UpdateTarget();

}

private void decrButton_Click(object sender, RoutedEventArgs e)
{
_counter.Decr();
_valueBindingExpression.UpdateTarget();

}

private void dumpButton_Click(object sender, RoutedEventArgs e)
{
// カウンタの中身を確認
MessageBox.Show(string.Format("{0}: {1}", _counter.Value, _counter.Description));
}
}
}

バインディングの構文
image


データソースとしてここでは、DataContextに指定したCounterオブジェクトを使用している。
そのDataContextのプロパティ名でBindingオブジェクトを作ってSetBindingするというパターンのようだ。


ソース値の変更を反映するには、値を変更したタイミングでUpdateTargetメソッドを呼んであげる。


Updateを自動的に行うにはデータソースのクラスに
INotifyPropertyChangedインタフェースを実装する。


このインタフェースは以下のイベントの実装を要求する。
event PropertyChangedEventHandler PropertyChanged


イベントを追加したCounterクラスを以下に引用する。

        class Counter:INotifyPropertyChanged
{
private int value;
public int Value
{
get { return value; }
set
{
this.value = value;
OnPropertyChanged("Value");
}
}

private string description;
public string Description
{
get { return description; }
set
{
this.description = value;
OnPropertyChanged("Description");
}
}

public void Incr()
{
Value++;
}
public void Decr()
{
Value--;
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

プロパティが沢山あったら書くのが面倒くさそう。
ほとんどが定型的な処理なので何かしらVSのサポートがあったもよさそうなものだが・・・。
(WPFが浸透して行かない理由の1ではなかろうか。)


個人的には文字列指定の多用も好きになれない。(リフレクションでゴネゴネするらしいが)

2011年10月26日水曜日

◆WPF パネルを使ってコントロールを幾つか追加する

レイアウトに挑戦

Hello World からもう少し進んでWindowに幾つかコントロールを追加する。
Windowsは子どもがひとつしか持てない仕様になっているので、子どもをたくさん持てるパネルコントロールに纏めて配置してから追加する。

パネルコントロールにはGridやStackPanelなど幾つか用意されている。

// need to add System.Xaml.dll , WindowBase.dll , PresentationCore.dll , PresentationFramework.dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;
using System.Windows.Controls; //PresentationFramework.dll

namespace WPFFirstPanel
{
class Program:Application
{
[STAThread]
static void Main(string[] args)
{
new Program().Run(new FirstPanelWindow());
}

}

class FirstPanelWindow : Window
{
public FirstPanelWindow()
{
InitializeComponent();
}

private void InitializeComponent()
{
this.Title = "FirstPanel";
this.Height = 400; this.Width = 400;
var stPanel = new StackPanel();
var btn1 = new Button() { Width = Double.NaN, Height = 20, Content = "Hrizontal", Margin = new Thickness(5) };
var btn2 = new Button() { Width = Double.NaN, Height = 20, Content = "Virtical", Margin = new Thickness(5) };
var btn3 = new Button() { Width = 200, Height = 20, Content = "btn3", Margin = new Thickness(5) };
btn1.Click += new RoutedEventHandler((o, e) => { stPanel.Orientation = Orientation.Horizontal; });
btn2.Click += new RoutedEventHandler((o, e) => { stPanel.Orientation = Orientation.Vertical; });

stPanel.Children.Add(btn1); stPanel.Children.Add(btn2); stPanel.Children.Add(btn3);
this.AddChild(stPanel);

this.SizeToContent = SizeToContent.WidthAndHeight;
}
}


}

--


<キーワード>
コードでAutoサイズを指定する
画面サイズを中身のサイズに合わせる

2011年10月25日火曜日

◆ページファイルを再作成してシステムを高速化

VS Express(C#)が最近よく落ちる。

障害が発生しているアプリケーション名: vcsexpress.exe、バージョン: 10.0.40219.1、タイム スタンプ: 0x4d5f2a6b
障害が発生しているモジュール名: kernel32.dll、バージョン: 6.1.7601.17651、タイム スタンプ: 0x4e211318
例外コード: 0xc0000005
障害オフセット: 0x0002cf79
障害が発生しているプロセス ID: 0x1708
障害が発生しているアプリケーションの開始時刻: 0x01cc92cfeb77a3e9
障害が発生しているアプリケーション パス: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\vcsexpress.exe
障害が発生しているモジュール パス: C:\Windows\syswow64\kernel32.dll
レポート ID: ce8fde33-fec3-11e0-837b-001d92804a05

調べてみると、DLLとかが実際に壊れているかTEMPフォルダーやページファイルが悪さをしている可能性が高いらしい。

DLLについては先日システムファイルチェッカーを掛けたばかりなので大丈夫だと思う。
となると一時ファイルが怪しげ、ということでTEMPフォルダをクリアした後にページファイルを別ドライブに移してみた。

見事、解決!!

嬉しいことにシステムがかなり高速化した。
体感速度がだいぶ違う。

ページファイルのフラグメントがシステム速度に影響することは知っていたが、固定サイズで設定してあれば大丈夫なのかと思っていた。

固定サイズでも安心できないのね・・・・。

定期的にクリアしよう。(家のマシンも早速やらなきゃ)

◆Hello XAML

xamlで書いてみよう

今度はXAMLで書いてみるパターンだ。

デフォルトのXAMLファイルを以下のように修正した。
・GridをStackPanelに変更
・StackPanelの子どもにボタンを追加
・ボタンのクリックイベントハンドラーにメッセージボックス表示を追加

2011-10-25 14h12_44

2011-10-25 14h13_43

2011-10-25 13h42_39

この程度のXAMLであればHTML的な知識とWindowsフォームの知識でもまだまだついていける。

2011年10月24日月曜日

◆WPFでHelloWorld

WPF入門してみた

なにはなくともHelloWorld。

基本はコンソールアプリからでしょ、って事でコンソールプロジェクトからWPFフォームをXAMLを使わずに表示してみた。

XAMLを使わなければWindowsフォームとイメージ的にそれほどの違いはない。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows; //added
using System.Windows.Controls; /added

namespace HelloWPF
{
class Program:Application
{
[STAThread]
static void Main(string[] args)
{
new Program().Run(new HelloWindow());
}

class HelloWindow : Window
{
public HelloWindow()
{
this.Title = "Hello WPF!!";
this.Width = 400;
this.Height = 300;
var btn = new Button();
btn.Content = "Show Message";
btn.Click += (sender, e) => { MessageBox.Show("Clicked"); };
this.AddChild(btn);
this.Show();
}
}

}
}

コンソールプロジェクトから作ると参照設定が色々足りないが、コンパイラーの仰せのとおり追加していけば問題ない。

◆WPF再入門

数年前、WPFが出始めの時にちょこちょこ触ったのだが、仕事の関係で最近はずっと放置していた。

WPFはWindowsフォーム等と比べると高機能な分、若干難しいため当時は多少使えたのだが今となっては殆ど忘れてしまった。

特に、当時はあまり体系だった説明をした日本語リソースが無かったために、中身を理解せずにサンプルを真似て動いて満足していた。
なので、忘れるのも早かったと反省しもう少し理論的に理解しながら再入門してみようと思う。

幸い、あれからだいぶ時間が経ったために以下のような詳しい解説も出ている。
WPF入門 - @IT
この記事を理解しながら、当時よく参考にしていたかずきのBlogをもう一度なぞっていこうと思う。

WindowsフォームからWPFへの移行はもっと速い速度で行われると思ったのだが、デスクトップアプリケーションの比率が下がり、HTML5の出現でSilverLightの扱いも微妙になったためか思いの外WPFは浸透していないようだ。
ただし、今後WindowsPhoneが普及するとどうなるかわからないし、どちらにしてもWPF自体はWindowsOSの基本テクノロジーに変わりは無いのでどこかでちゃんと勉強しておかないと・・・。

2011年10月20日木曜日

◆Windows Live Meshが同期エラーになる

一昨日くらいから同期エラーになり数分おきにログインダイアログが表示される。(インターネットに繋がらないと文句を言う)

障害が発生しているアプリケーション名: WLSync.exe、バージョン: 15.4.3538.513、タイム スタンプ: 0x4dcdaf2f
障害が発生しているモジュール名: KERNELBASE.dll、バージョン: 6.1.7601.17651、タイム スタンプ: 0x4e211319
例外コード: 0x80000003
障害オフセット: 0x0001280c
障害が発生しているプロセス ID: 0xee0
障害が発生しているアプリケーションの開始時刻: 0x01cc8df039102e95
障害が発生しているアプリケーション パス: C:\Program Files (x86)\Windows Live\Mesh\WLSync.exe
障害が発生しているモジュール パス: C:\Windows\syswow64\KERNELBASE.dll
レポート ID: a8eb1943-f9e4-11e0-83ba-001d92804a05

ネットワーク環境自体は全く普通の状態。

まるでウイルスの様に鬱陶しい。(プロセスを見つけてKillするしかなくなる)

別のPCでは同期できているようなので、このPC固有の問題のようだ。

ネットでもあまりそれらしい情報は出ていない・・・。
問題が出たら再インストールって解決策が多いようだ。

仕方が無いので一旦アンインストールして再インストール。
っと思ったが、インストーラが「インターネットに繋がらない」とエラーを吐く。

・・・。

うちの会社のファイアウォールが悪さしている可能性も無いではないが、雰囲気的にはモジュールの不整合が起きてるっぽい・・・。

探してみるとオフライン版のインストーラーが有ったのでこいつをダウンロードしてインストール。

エラーは出なくなった。

2011年10月16日日曜日

◆Windows8に触ってみる

普段、製品前のバージョンに触ってみるといったことはやらない。
人柱になるほどパソコンとか好きなわけではないしそれほどのパワーユーザーでもないので。

ただ、今回事情がありWindows8をインストールしてみた。

インストール環境はVirtualPCにと思ったのだが、現時点でVirtualPCへのインストールはサポートされていないようだ。

となると、素のPCに入れるかVHDブートするかHyper-Vに入れるかVMWareに入れるかといったあたりになる。
VMWareは使ったことがないのでパス。
VHDブートが最適のような気もするが、ブートマネージャは置き換えられてしまいそうに思うのでちょっと躊躇してしまう。
Hyper-Vを使うにはServer環境を作らなければいけないので、これもまた面倒なのだが、やはり昨今何かとHyper-Vが使えると便利なのでひとつ環境を作ることとした。(Windows7とのマルチブート)

これまでインストールしたことのない無線LAN環境へのインストールだったのでネット接続にちょと戸惑った。

まず、そもそもホスト側での無線LAN構築でWLanapi.dllが見つかりませんというエラーが出る。
Serverでは、Windows7でデフォルト有効になっている機能でも無効になっているケースが多いので何か機能が足りないのだろう。
調べてみると「ワイヤレスLANサービス」機能を追加する必要があるらしい。
image

こいつを入れてホスト側はとりあえず解決。

次はゲスト側なのだが、こちらもちょっと設定が必要。
通常は「仮想ネットワークマネージャ」から「外部」ネットワークの追加でホストのNICを指定してあげればよい。
image
image

だが、無線LANの場合は追加するNICの選択肢として表示されてこないのだ。
これも調べてみると、どうも無線LANは直接的にはサポートされていないらしい。
回避策としてはいくつかあるようなのだが、今回はお遊び環境なので一番簡単そうな「ブリッジ接続」にしてみた。
方法はいたって簡単で、先ほどの「仮想ネットワークの作成」で「外部」ではなく「内部」を選択して追加する。
するとホスト側に追加した接続が表示されるので、
image

その追加されたネットワークと無線LANネットワークを同時に選択して右クリックから「ブリッジ接続」を選択してあげればよい。
ゲスト側では、設定画面で追加した「内部」ネットワークを指定しておくだけ。
image

DHCP環境であればこれだけでゲストOSでもホストの無線LANが使えるようなる。
(DHCP環境でなければ適宜IPアドレスの指定も必要なる思われ)

 

これでやっとWindows8に取り掛かれる。

Windows8のHyper-Vへのインストール自体はこれまでと違ったところは特になく、巷で見かける「メトロ」がすぐに表示された。
image

操作は若干癖があり慣れが必要と思われるが個人的には好印象。
すでに解説記事とかもいろいろと出回っているので一度そういった記事を見てから触ってみたほうがよいだろう。

イメージ的にはWindows8 = Windows7 + WindowsPhone
といった感じで、2つの異なるOSを切り替えながら使えるOSになっている。

アプリケーションのプラットフォーム(API)も別々のようなので2つのShellを纏っているというよりは、リソースを共有しながら動く2つのOSと捕らえたほうが理解しやすいような気がする。

両者間の移動は、メトロ側へは「Windows」キーで、旧インタフェース側へは「Windows + D」キーで(すなわちデスクトップの表示)で行える。
(Windowsキーを頻繁に使うことになるので全画面表示で操作するのが吉と思われ)
デスクトップの表示はメトロ画面でタイル表示されている「DESKTOP」をクリックしても表示できる。

旧インタフェース側では「スタートメニュー」が使えないので「Windows + R」で直接アプリケーションを起動するのが良さそうだ。(一度起動してしまえば普段使うものについてはピン止めしておけばよい)

 

WindowsPhoneユーザーに対しては、PCにおいても同じ環境と同じ操作性を提供し、既存のPCユーザーに対しては、これまでどおりの環境を提供しつつ「WindowsPhone」ってこんな感じなんだぁ、というエクスペリエンスを提供する。
その2つを変に融合することなく、シームレスに行き来できる別世界として提供するMSならではのなかなかうまい戦略ではなかろうか。

メトロ側がプライベートユース、旧インタフェース側がビジネスユースと捕らえることもできそうだ。

開発者としても、特に「スマホなんて関係ありません」という人はこれまでとなんら変わらぬ世界で生き続けることができるし、WindowsPhone開発者は普通にWindowsPhoneアプリを作ればそのままでPCでも動いてしまうという一粒で二度おいしい世界が簡単に手に入る。

なんとすばらしい世界なのだろう。
これでMSも安泰だ!!

なんてなるのだろうか(笑)

以上、まったく個人的で無責任な感想です。

私が最近チェックした記事