by WebSurfer
2014年10月20日 17:21
TreeView の SelectedNodeStyle-ImageUrl(正確には TreeView.SelectedNodeStyle プロパティで取得できる TreeNodeStyle オブジェクトの ImageUrl プロパティ)にイメージの URL を設定しても無視されます。
例えば、上の画像のように、選択されたノード(上の画像の例では Topic 1.0.1)の左隣に表示される三角形は青、それ以外は白抜きの三角形にしたいとします。
その場合、NodeStyle-ImageUrl には白抜きの三角形、SelectedNodeStyle-ImageUrl に青の三角形のイメージを設定するとよさそうですが、実際にそのように設定して試すと SelectedNodeStyle-ImageUrl の方は無視されます(ノードを選択しても白抜きの三角形のまま変わりません)。
これは stackoverflow のページ およびそのページにあるリンク先に書いてあるようにバグのようです。ASP.NET 4.5 でも修正されていません。
では、どうすれば選択されたノードの左隣に表示されるイメージを、期待した通り上の画像のような青三角のイメージにできるかですが、その方法を以下に書きます。
サンプルとして、MSDN ライブラリの TreeView.SelectedNodeStyle プロパティ にあるコードに手を加えてみました。
まず、選択されてないノード用のイメージですが、各 TreeNodeStyle の ImageUrl プロパティに白抜き三角のイメージの URL を静的に設定します。
SelectedNodeStyle-ImageUrl は静的に設定しても無視されるので、TreeView の SelectedNodeChanged イベントのハンドラで SelectedNode の ImageUrl に青三角のイメージの URL を動的に設定します。
ただし、設定しっぱなしではノードの選択を変更した時に前に選択したノードのイメージが青三角のまま元に戻りません。ノードの選択が変更された場合は、前に選択されたノードのイメージを白抜き三角イメージの URL に書き戻すコードが必要になります。
そのため、選択したノードの ValuePath を ViewState に保持しておき、ノードの選択が変更になった場合は ViewState に保持したパス情報を元に前に選択されたノードを探し、その ImageUrl を書き換えます。その後、新たに選択されたノードの ValuePath を ViewState に保存します。
ちなみに、ValuePath はルートノードから選択されたノードまでの Value をつなげた文字列になります。例えば Topic 1.0.1 を選択した場合は "Table of Contents/Chapter One/Section 1.0/Topic 1.0.1" になります(サンプルコードでは Value プロパティを明示的に設定してないので Text プロパティの値が使用されます)。
修正後のコードは以下の通りです。実際に動かして試すことができるよう 実験室 にアップしましたので、興味がありましたら試してみてください。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Select_Change(Object sender, EventArgs e)
{
Message.Text =
"You selected: " + LinksTreeView.SelectedNode.Text;
// これだけではダメ。イメージは元に戻らない。
LinksTreeView.SelectedNode.ImageUrl =
"~/Images/right_selected.gif";
// 前に選択されたノードのイメージを元に戻す。
string valuePath =
(string)ViewState["TreeNodeValuePath"];
if (!String.IsNullOrEmpty(valuePath))
{
LinksTreeView.FindNode(valuePath).ImageUrl =
"~/Images/right.gif";
}
ViewState["TreeNodeValuePath"] =
LinksTreeView.SelectedNode.ValuePath;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>TreeView SelectedNodeStyle Example</title>
</head>
<body>
<form id="form1" runat="server">
<h3>TreeView SelectedNodeStyle Example</h3>
<asp:TreeView id="LinksTreeView"
Font-Names= "Arial"
ForeColor="Blue"
SelectedNodeStyle-ForeColor="Green"
SelectedNodeStyle-VerticalPadding="0"
OnSelectedNodeChanged="Select_Change"
runat="server">
<LevelStyles>
<asp:TreeNodeStyle ChildNodesPadding="10"
ImageUrl="~/Images/right.gif"
Font-Bold="true"
Font-Size="12pt"
ForeColor="DarkGreen"/>
<asp:TreeNodeStyle ChildNodesPadding="5"
ImageUrl="~/Images/right.gif"
Font-Bold="true"
Font-Size="10pt"/>
<asp:TreeNodeStyle ChildNodesPadding="5"
ImageUrl="~/Images/right.gif"
Font-UnderLine="true"
Font-Size="10pt"/>
<asp:TreeNodeStyle ChildNodesPadding="10"
ImageUrl="~/Images/right.gif"
Font-Size="8pt"/>
</LevelStyles>
<Nodes>
<asp:TreeNode Text="Table of Contents"
SelectAction="None">
<asp:TreeNode Text="Chapter One">
<asp:TreeNode Text="Section 1.0">
<asp:TreeNode Text="Topic 1.0.1" />
<asp:TreeNode Text="Topic 1.0.2" />
<asp:TreeNode Text="Topic 1.0.3" />
</asp:TreeNode>
<asp:TreeNode Text="Section 1.1">
<asp:TreeNode Text="Topic 1.1.1"/>
<asp:TreeNode Text="Topic 1.1.2" />
<asp:TreeNode Text="Topic 1.1.3" />
<asp:TreeNode Text="Topic 1.1.4" />
</asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="Chapter Two">
<asp:TreeNode Text="Section 2.0">
<asp:TreeNode Text="Topic 2.0.1" />
<asp:TreeNode Text="Topic 2.0.2" />
</asp:TreeNode>
</asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="Appendix A" />
<asp:TreeNode Text="Appendix B" />
<asp:TreeNode Text="Appendix C" />
</Nodes>
</asp:TreeView>
<br /><br />
<asp:Label id="Message" runat="server"/>
</form>
</body>
</html>
by WebSurfer
2011年11月13日 19:12
TreeView のノードをクリックするとポストバックが起こり、サーバー側で TreeView.SelectedNode プロパティでクリックされた TreeNode を取得できます。
上の画像は、book というノードをクリックし、book ノードに含まれる子ノードの内 title ノードを取得してその Value を表示したものです。
そのコードは下に示したサンプルのとおりです。データとして使用している XML ファイルは MSDN ライブラリの チュートリアル : TreeView コントロールでの階層データの表示 のものです。
しかしながら、このコードでは、どの book ノードをクリックしても、表示されるのは一番上の book ノード下の title ノードの Value になってしまいます。
何故でしょう? 理由は以下の通りです。
どのノードがクリックさ���たかのサーバー側での判定は、root からクリックされたノードまでの Value をつなげた文字列を javascript:__doPostBack 関数の引数に設定し、ポストバックされた際にそれを取得して識別しています。
下のサンプルコードの例では、book ノードのハイパーリンクとして a 要素の href 属性に以下のように設定されます。
href="javascript:__doPostBack('TreeView1','sbookstore\\genre\\book')"
book ノードの Value はどれも同じ book ですので、__doPostBack 関数の引数はどの book ノードでも同じになってしまいます。それゆえサーバー側ではどの book がクリックされたか特定できません。だから、最初に該当する一番上の book が選択されたと判定してしまうようです。
解決策は、book ノードの Value が一意になるように TreeView の DataBindings に以下のように設定してやることです。
<asp:TreeNodeBinding DataMember="book"
TextField="#Name"
ValueField="ISBN" />
考えてみれば、Windows アプリとは違って、ブラウザの画面に表示されているノードはインスタンスを指していないので、当たり前ですね。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void TreeView1_SelectedNodeChanged(
object sender, EventArgs e)
{
TreeNode selectedNode = TreeView1.SelectedNode;
if (selectedNode.Text == "book")
{
foreach (TreeNode child in selectedNode.ChildNodes)
{
if (child.Text == "title")
{
Label1.Text =
"選択した本のタイトル: " + child.Value;
break;
}
}
}
else
{
Label1.Text = String.Empty;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TreeView ID="TreeView1"
runat="server"
DataSourceID="XmlDataSource1"
OnSelectedNodeChanged="TreeView1_SelectedNodeChanged">
<DataBindings>
<asp:TreeNodeBinding DataMember="title"
TextField="#Name"
ValueField="#InnerText" />
</DataBindings>
</asp:TreeView>
<asp:XmlDataSource ID="XmlDataSource1"
runat="server"
DataFile="~/App_Data/Bookstore.xml">
</asp:XmlDataSource>
<br />
<br />
<asp:Label ID="Label1" runat="server">
</asp:Label>
</div>
</form>
</body>
</html>
by WebSurfer
2011年10月30日 15:16
TreeView に表示されるノードの上下のスペーシングを調整するにはどうすればいいでしょうか。
子ノードを親ノードに接続する線を表示しない(TreeView.ShowLines プロパティが false)なら NodeStyle-NodeSpacing か NodeStyle-VerticalPadding で設定可能です。
しかし、接続線を表示する場合はそれではうまくいきません。
下の画像は、NodeStyle-VerticalPadding を 10px に設定した TreeView を表示している IE9 とその開発者ツールです(重ねて表示しています)。
NodeStyle-VerticalPadding を 10px に設定したことにより、td 要素の上下の padding が 10px に設定されてスペーシングは広がったものの、接続線の画像がデフォルトのままなので、線がつながっていません。
線がつながるようにするには、接続線の画像のサイズを大きくする必要があります。(というより、NodeStyle-NodeSpacing や NodeStyle-VerticalPadding は使わないで、画像のサイズだけでスペーシングを調整するようにします。)
接続線の画像は、デフォルトでは TreeView コントロールの埋め込みリソースから 19 x 20 サイズの GIF ファイルがダウンロードされるようになっていますが、以下の手順で変更可能です。
-
デザイン画面で TreeView の > 印をクリック。
-
「TreeView タスク」メニューが表示されるので、[線のイメージのカスタマイズ ...]をクリック。
-
「ASP.NET TreeView ラインイメージジェネレーター」ダイアログが表示されるので、Height を指定する(デフォルトは 20)。必要なら、幅も Width の設定で変えられます(デフォルトは 19)。
-
TreeLineImages フォルダ(存在しなければ自動生成される)の中に、上記 3 で指定したサイズの接続線の GIF イメージファイルが自動的に生成され、配置される(既存の画像ファイルがあれば置き換えられる)。
下の画像は、上記の手順で Height x Width を 40 x 40 に設定して自動生成した接続線の GIF イメージの一部です。
TreeView.LineImagesFolder プロパティに上記 4 の TreeLineImages フォルダを設定し(自動的に設定されます)、上記 3 で画像の幅(Width)を変更していたら TreeView.NodeIndent をそれに合わせて調整します。
でも、これだけではまだ一部で線がつながりません(これはデフォルトの時でも同じです)。下の画像を見てください。
上の画像が示すように、TreeView.NodeIndent プロパティで設定した幅のインデントを設けるため、td 要素の中に div 要素が配置されています。その場所に接続線がある場合は、その div 要素の中に img 要素を配置して接続線の GIF イメージを表示します。
この例では、NodeIndent="40" としたので div 要素の style 属性で width: 40px; となっています。しかし、height は常に 1px になります。
インデントだけなら height が 1px でも問題ありませんが、接続線を表示する場合は 1px ではダメです。
その問題を解決するには、以下のようなスタイルを定義して、TreeView.CssClass に設定してやります。その結果が一番上の画像です。
<style type="text/css">
.treeview table td div
{
height: 100% !important;
}
</style>