質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

解決済

gridviewで数値と文字列が混在している際に数値の大小順に並べ替えたい

tkm_43522
tkm_43522

総合スコア10

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

3回答

0グッド

0クリップ

2251閲覧

投稿2021/05/17 05:58

編集2021/05/19 00:15

accessから読み込んだデータをソースとしてgridviewで表示し、任意の列を数値の大小で並べ替えるアプリを作成しています。
accessのテーブルは、元となるexcelファイルから外部データのリンクで取得しているため、各列のデータの型を指定出来ない状況です。
一部の列は、数値と文字列が混在してしまっているのですが、そのような列でも数値が入力されている行だけまず並び替えて、続いて文字列を並び替えるというような動作をさせたいと考えています。
excelの並び替えでは上記のような動作をするので、それが理想です。

gridviewにはAllowSorting="True"とするだけでソートできるようになる機能がありますが、これだと型が短いテキストとなっている列では
1→10→2→20→30→あいうえお
というように並べ替えられてしまいます。
これを
1→2→10→20→30→あいうえお

となるようにするにはどのようにすればよいでしょうか?

追記です。
使用した並べ替え対象のデータ
使用した並べ替え対象のデータ

test.aspx

aspx

1<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="sorttest.aspx.vb" Inherits="test.sorttest" %> 2 3<!DOCTYPE html> 4 5<html xmlns="http://www.w3.org/1999/xhtml"> 6<head runat="server"> 7<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 8 <title></title> 9 <style type="text/css"> 10 th.sortedAscHeader, 11 th.sortedDscHeader { 12 background-repeat: no-repeat; 13 background-position: right; 14 padding-right:18px; 15 } 16 17 th.sortedAscHeader { 18 background-image: url(Images/arrow-up.png); 19 } 20 21 th.sortedDscHeader { 22 background-image: url(Images/arrow-down.png); 23 } 24 </style> 25 26</head> 27<body> 28 <form id="form1" runat="server"> 29 <div> 30 <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> 31 <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataSourceID="SqlDataSource1" OnSorting="onsorting" PageSize="60" DataKeyNames="フィールドA"> 32 <Columns> 33 <asp:CommandField ShowSelectButton="True" /> 34 <asp:BoundField DataField="フィールドA" HeaderText="フィールドA" SortExpression="フィールドA" /> 35 <asp:BoundField DataField="フィールドB" HeaderText="フィールドB" SortExpression="フィールドB" /> 36 <asp:BoundField DataField="フィールドC" HeaderText="フィールドC" SortExpression="フィールドC" /> 37 </Columns> 38 <SortedAscendingHeaderStyle CssClass="sortedAscHeader" BackColor="#FFCCFF" /> 39 40 <SortedDescendingHeaderStyle CssClass="sortedDscHeader" BackColor="#99CCFF" /> 41 42 43 </asp:GridView> 44 <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString3 %>" ProviderName="<%$ ConnectionStrings:ConnectionString3.ProviderName %>" SelectCommand="SELECT * FROM [sorttest]"></asp:SqlDataSource> 45 46 <asp:HiddenField ID="hiddenselectcommand" runat="server" /> 47 <br /> 48 <br /> 49 </div> 50 </form> 51</body> 52</html> 53 54

test.aspx.vb

VB

1 2Public Class sorttest 3 Inherits System.Web.UI.Page 4 5 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 6 SqlDataSource1.SelectCommand = "Select * FROM [sorttest]" & hiddenselectcommand.Value 7 8 End Sub 9 10 11 Protected Sub OnSorting(sender As Object, e As GridViewSortEventArgs) Handles GridView1.Sorting 12 13 Dim field As String = e.SortExpression 14 Dim direction As String 15 Dim selectcommandstr As String = SqlDataSource1.SelectCommand 16 17 18 If selectcommandstr.IndexOf("ASC") <> -1 Then 19 direction = "DESC" 20 Else 21 direction = "ASC" 22 End If 23 If selectcommandstr.IndexOf("order") <> -1 Then selectcommandstr = selectcommandstr.Remove(selectcommandstr.IndexOf("order")) 24 selectcommandstr = selectcommandstr & " order by IsNumeric([" & field & "]), Val([" & field & "]) " & direction & ", [" & field & "] " & direction & "" 25 26 27 SqlDataSource1.SelectCommand = selectcommandstr 28 29 If selectcommandstr.IndexOf("where") <> -1 Then 30 selectcommandstr = selectcommandstr.Remove(0, selectcommandstr.IndexOf("where")) 31 Else 32 33 If selectcommandstr.IndexOf("order") <> -1 Then 34 selectcommandstr = selectcommandstr.Remove(0, selectcommandstr.IndexOf("order")) 35 Else 36 selectcommandstr = "" 37 End If 38 End If 39 40 hiddenselectcommand.Value = selectcommandstr 41 42 e.Cancel = True 43 44 End Sub 45 46 Protected Sub GridView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles GridView1.SelectedIndexChanged 47 TextBox1.Text = GridView1.SelectedValue.ToString 48 End Sub 49End Class 50

上記とすることで、gridviewのヘッダーをクリックするたびに昇順降順を切り替えて
昇順
1→2→10→20→30→あい→うえお
降順
30→20→10→2→1→うえお→あい
と並び替えられるようになりました、が、
e.cancelとしていることでgridviewの機能としては並び替わったことにならないため、SortedAscendingHeaderStyleが反映されなくなってしまいました。
できれば並び替わっている列とその向きがわかるようにしたいのですが、gridviewのsortイベントを介さずにgiridviewに現在並び替えられているフィールドとその向きを設定するなどして、すでに並び替わったことに出来ないでしょうか。
gridview.SortDirectionを書き換えようとしてみましたが、readonlyのため無理なようでした。

追加ですみませんが、ご存知の方がいらっしゃいましたら教えて下さい。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

SurferOnWww

2021/05/17 06:49

文字列としてソートしていると思いますが、その場合は元の文字列を「01 02 10 20 30 あいうえお」としないと何ともならないかと。それができなければ列を数字と文字で別に分けるとか、組み込みのソート機能ではなく自力で実装するとかしないと手はなさそうですが、そこまでやる気はありますか?
tkm_43522

2021/05/17 07:09

gridviewはsqldatasourceでデータをbindしているので、gridview.sortingイベントが発生したときにsqldatasourceをbindされる前に下記リンクのようにORDER BY CAST(〇〇 as int)のように並び替えられないかなと考えているのですが、gridview.sortingイベントをどのように捕まえるのか、捕まえられたとして、組み込みのソート機能と想定しているbind前の並び替えのどちらが後に起こるのかなど、さっぱりわからないでいます。 https://kojimanotech.com/2020/11/19/267/ 方法があるのなら、自力で実装するのに挑戦したいと考えておりますが、ご教示いただけると大変助かります。
SurferOnWww

2021/05/17 07:46 編集

> 下記リンクのようにORDER BY CAST(〇〇 as int)のように並び替えられないかな それは「ORDER BY するときにint型にCASTすることで解決します」という話なので、"あいうえお" とかが混ざっていたら何ともならないはずです。 > 組み込みのソート機能と想定しているbind前の並び替えのどちらが後に起こるのかなど、さっぱりわからないでいます。 SqlDataSource + GridView の機能を使ってソートを行う場合、(1) GridView のヘッダのリンクボタンのクリックによってポストバックが起こる、(2) サーバー側ではそれを受けて Access から SqlDataSource 経由でデータを取得、(3) 取得したデータから DataView を作って、その Sort プロパティ に SortExpression を設定、(4) それによりソートされた結果を GirdView に表示する・・・という動きになっています。 > 方法があるのなら、自力で実装するのに挑戦したいと考えておりますが、 上記の動作を何とかして希望の動作をできるようにするには、(3) ~ (4) に大幅な手を加える必要があると思いますが、できますか?
tkm_43522

2021/05/17 09:05

ありがとうございます。 おっしゃる通り、試しにsqldatasource.selectcommandにORDER BY CAST(〇〇 as int)としてしまうとエラーが出てしまいました。ですが、saziさんにご助言いただいたように、 order by IsNumeric([フィールド]), Val([フィールド]), [フィールド] とすると、はじめに数値が並び、続いて文字列が並ぶという様に並べ替えられました。 クエリ文で希望するように並べ替えが可能ということがはわかったので、(2)でクエリ文でデータ取得、続いて(3)を飛ばして, (4)ができれば良いという理解で良いでしょうか?
SurferOnWww

2021/05/17 12:40 編集

> クエリ文で希望するように並べ替えが可能ということがはわかったので、(2)でクエリ文でデータ取得、続いて(3)を飛ばして, (4)ができれば良いという理解で良いでしょうか? 自分的にはどう考えても違うと思います。 初期画面でソートされていればそれだけで良いということなら話は違うかもしれませんが・・・ 何にせよ、全体的に何をしたいのか不明ですので的確なアドバイスはできません。 実際に手を動かしてやってみたら、その課程で突破口が見つかるかもしれませんので、人に聞くよりとにかく自分の手を動かしてやってみてはいかがですか。
SurferOnWww

2021/05/18 01:11

上のコメントに、 > 初期画面でソートされていればそれだけで良いということなら話は違うかもしれませんが・・・ と書きましたが、それを回答欄に書いておきます。質問者さんのやりたいことと違う場合は、どこがどのように違うのか回答のコメント欄に書いてください。
SurferOnWww

2021/05/20 01:31

解決したようですのでベストアンサーを選んでクローズしてください。

回答3

1

既存の私の回答欄に追記しようとしましたが、サイズの問題かできないので、新しい回答欄で追記します。

【追記2】

サンプルを書いておきます。サーバー側で RowCreated イベントのハンドラで css を追加しています。

ポイントは以下の点です。

(1) BoundField は TemplateField に変換し、それに HeaderTemplate を追加し、その中に LinkButton を配置。LinkButton の ID, CommandName, CommandArgument を適宜設定。

(2) GridView に独自プロパティ CurrentSortField, CurrentSortDir を追加し、それによって制御を行う。

ページング、選択でポストバックすると css の適用は外れてしまいますが、それも何とかということであれば、そのあたりは質問者さんの方で考えていただきたく。

詳しくは以下のサンプルコードを見てください。

aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="207-AccesSample.aspx.cs" Inherits="_207_AccesSample" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <style type="text/css"> .sortasc-header { background: url(img/sort-asc.png) right center no-repeat; } .sortdesc-header { background: url(img/sort-desc.png) right center no-repeat; } th a { padding-right: 20px; } </style> </head> <body> <form id="form1" runat="server"> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Access %>" DeleteCommand="DELETE FROM [XXX] WHERE [ID] = ?" InsertCommand="INSERT INTO [XXX] ([ID], [Info1], [Info2]) VALUES (?, ?, ?)" ProviderName="<%$ ConnectionStrings:Access.ProviderName %>" SelectCommand="SELECT [ID], [Info1], [Info2] FROM [XXX]" UpdateCommand="UPDATE [XXX] SET [Info1] = ?, [Info2] = ? WHERE [ID] = ?"> <DeleteParameters> <asp:Parameter Name="ID" Type="Int32" /> </DeleteParameters> <InsertParameters> <asp:Parameter Name="ID" Type="Int32" /> <asp:Parameter Name="Info1" Type="String" /> <asp:Parameter Name="Info2" Type="String" /> </InsertParameters> <UpdateParameters> <asp:Parameter Name="Info1" Type="String" /> <asp:Parameter Name="Info2" Type="String" /> <asp:Parameter Name="ID" Type="Int32" /> </UpdateParameters> </asp:SqlDataSource> <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="ID" DataSourceID="SqlDataSource1" OnSorting="GridView1_Sorting" CurrentSortField="" CurrentSortDir="" OnSelectedIndexChanged="GridView1_SelectedIndexChanged" OnRowCreated="GridView1_RowCreated"> <Columns> <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" /> <asp:TemplateField HeaderText="ID" InsertVisible="False" SortExpression="ID"> <EditItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("ID") %>'></asp:Label> </EditItemTemplate> <HeaderTemplate> <asp:LinkButton ID="ID" runat="server" CommandName="Sort" CommandArgument="ID">ID</asp:LinkButton> </HeaderTemplate> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Bind("ID") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Info1" SortExpression="Info1"> <EditItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Info1") %>'></asp:TextBox> </EditItemTemplate> <HeaderTemplate> <asp:LinkButton ID="Info1" runat="server" CommandName="Sort" CommandArgument="Info1">Info1</asp:LinkButton> </HeaderTemplate> <ItemTemplate> <asp:Label ID="Label2" runat="server" Text='<%# Bind("Info1") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Info2" SortExpression="Info2"> <EditItemTemplate> <asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("Info2") %>'></asp:TextBox> </EditItemTemplate> <HeaderTemplate> <asp:LinkButton ID="Info2" runat="server" CommandName="Sort" CommandArgument="Info2">Info2</asp:LinkButton> </HeaderTemplate> <ItemTemplate> <asp:Label ID="Label3" runat="server" Text='<%# Bind("Info2") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> </form> </body> </html>

aspx.cs

using System; using System.Web.UI.WebControls; public partial class _207_AccesSample : System.Web.UI.Page { bool isSorted = false; protected void Page_Load(object sender, EventArgs e) { string selectQuery = (string)ViewState["CurrectSelectQuery"]; if (!string.IsNullOrEmpty(selectQuery)) { SqlDataSource1.SelectCommand = selectQuery; } } protected void GridView1_Sorting(object sender, GridViewSortEventArgs e) { GridView gv = (GridView)sender; string exp = e.SortExpression; string dir = ""; var field = gv.Attributes["CurrentSortField"]; var direction = gv.Attributes["CurrentSortDir"]; if (gv.Attributes["CurrentSortField"] != null && gv.Attributes["CurrentSortDir"] != null) { if (exp == gv.Attributes["CurrentSortField"]) { if (gv.Attributes["CurrentSortDir"] == "ASC") { dir = " DESC"; gv.Attributes["CurrentSortDir"] = "DESC"; } else { dir = " ASC"; gv.Attributes["CurrentSortDir"] = "ASC"; } } else { gv.Attributes["CurrentSortField"] = exp; dir = " ASC"; gv.Attributes["CurrentSortDir"] = "ASC"; } } SqlDataSource1.SelectCommand = "SELECT [ID], [Info1], [Info2] FROM [XXX] " + "ORDER BY IsNumeric([" + exp + "]) "+ dir + ", Val([" + exp + "])" + dir + ", [" + exp + "] " + dir; ViewState["CurrectSelectQuery"] = SqlDataSource1.SelectCommand; isSorted = true; e.Cancel = true; } protected void GridView1_SelectedIndexChanged(object sender, EventArgs e) { TextBox1.Text = GridView1.SelectedValue.ToString(); } protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.Header && isSorted) { string field = GridView1.Attributes["CurrentSortField"]; LinkButton lb = (LinkButton)e.Row.FindControl(field); if (GridView1.Attributes["CurrentSortDir"] == "ASC") { lb.CssClass = "sortasc-header"; } else if (GridView1.Attributes["CurrentSortDir"] == "DESC") { lb.CssClass = "sortdesc-header"; } } } }

実行結果は:

イメージ説明

投稿2021/05/19 04:57

SurferOnWww

総合スコア17335

tkm_43522👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

tkm_43522

2021/05/20 00:08

サンプルコードまでご作成いただきありがとうございました。 参考にさせていただきます。 確かにhiddenfieldよりもviewstateを使ったほうが良さそうですね。 今並び替え中のフィールド及び向きはselectocommandから抽出していたのですが、コントロールに独自プロパティを追加することができるんですね。 知らなかったので大変勉強になりました。 これならselectcommandから抽出する処理の負荷もなくなりますし、便利ですね。 また、gridviewの列をヘッダー名で指定することができない(やり方を知らないだけかもしれませんが)ようなので、下記の様にしてみたのですが、templatefieldにしてしまえばよいのですね。 findcontrolの内部処理がどの様になっているのかわからないのですが、for文で全列順次検索するよりも処理は早そうな気がします。 For i = 1 To GridView1.Columns.Count - 1 If GridView1.Columns(i).HeaderText = field Then If direction = "ASC" Then GridView1.Columns(i).HeaderStyle.CssClass = "sortedAscHeader" ElseIf direction = "DESC" Then GridView1.Columns(i).HeaderStyle.CssClass = "sortedDscHeader" End If       Exit For <以下略> 上記のやり方だと、なぜかページングやselectでポストバックしてもCSSの適用が保たれています。 ともあれ、今回質問させて頂いた件はおかげさまで無事解決いたしました。 色々とありがとうございました。
SurferOnWww

2021/05/20 00:13

解決したならベストアンサーを選んでクローズしてください。

1

上の質問のコメント欄の 2021/05/18 10:11 の私のコメントに、

初期画面でソートされていればそれだけで良いということなら話は違うかもしれませんが・・・

と書きましたが、それを以下に書いておきます。

SqlDataSource + GridView の機能を使ってソートを行う場合、(1) GridView のヘッダのリンクボタンのクリックによってポストバックが起こる、(2) サーバー側ではそれを受けて Access から SqlDataSource 経由でデータを取得、(3) 取得したデータから DataView を作って、その Sort プロパティ に SortExpression を設定、(4) それによりソートされた結果を GirdView に表示する・・・という動きになっています。

なので、SqlDataSource + GridView に備わっているページング機能を利用するのであれば、ソートは (3) の結果なので、「1→10→2→20→30→あいうえお」またはその逆(クリック毎に昇順降順が入れ替わります)となります。

そこを何とか望む形「1→2→10→20→30→あいうえお」にしようとすると、SqlDataSource は使わないで (3) ~ (4) を自力で実装する他には方法はなさそうです。

しかし、SqlDataSource + GridView を使っているということは、たぶん、ソートだけでなく、SqlDataSource + GridView に備わっているページング機能や編集機能も使いたいということだと想像しています。いかがですか?

そうだとすると、不可能とまでは言いませんがそれに近いくらい無理筋な話で、少なくともここのような Q&A サイトで聞いて解決するような話でなないと思います。

しかし、初期画面で特定の列だけ望む形「1→2→10→20→30→あいうえお」にするので良ければ、sazi さんが提案されたような ORDER BY 句を SqlDataSourece の SelectCommand に追加してやれば可能です。

だたし、ソートを有効にして SqlDataSource + GridView の機能を使ってソートを行う(GridView のヘッダのリンクボタンをクリックする)と、ソートは (3) の結果「1→10→2→20→30→あいうえお」になってしまいますが。

それでもよければ、以下にやり方を書きますので自分でやってみてください。質問者さんのやりたいことと違う場合は、どこがどのように違うのかを下のコメント欄に書いてください。

ベースとなる Access テーブルは以下の通りです。

イメージ説明

Visual Studio でツールボックスから SqlDataSource と GridView を aspx ページにドラッグ&ドロップしてデザイナ画面でウィザードベースでソート、ページング、編集可能なアプリを作ると以下のようになるはずです。赤枠の ORDER BY 句は後でソース画面で追加します。

イメージ説明

実行結果は以下のようになります。ページング、編集は問題なく可能です。ただし、GridView のヘッダのリンクボタンをクリックすると (3) の結果になってしまいますが。

イメージ説明

例えば、上の画像でヘッダの Info1 をクリックすると以下のようになります。もう一度クリックすると昇順降順が入れ替わります。

イメージ説明

【追記】

下のコメント欄の 2021/05/19 09:37 の質問者さんのコメントに対するレスです。

ORDER BY句を追加したselectcommandを、onsortingイベント内でhiddenfieldに代入し、pageloadでhiddenfieldからselectcommandを改めて読みこんでいる

なるほど、それは良い考えですね。それならページングも編集も問題なくできそうです。

HiddenField を使ったとのことですが、ViewState を使う方が ASP.NET Web Forms アプリとしては保守性場度を考えると良さそうです。

改めてSortedAscendingHeaderStyleが適用される方法を考えたいと思いますが、

ASP.NET の内部でどのようにしているのか分かりませんが、ソート対象にしたヘッダに動的に css を適用しているような感じです。

例えば、今回のような細工はせず、以下の記事のように普通にソートとそのための css を設定すると、

ASP.NET 4.0のGridViewの新しい並べ替えスタイル
https://codezine.jp/article/detail/5012?p=2

ヘッダのリンクをクリックすると以下の画像のように css が適用されます。

イメージ説明

今回のような細工をするとそれが設定されないので、自力で同様に css が設定されるようにコーディングする他なさそうな気がします。

思いつくのは、JavaScript か、サーバー側で行うなら RowCreated イベントのハンドラで、対象のヘッダを探して css を適用することです。

投稿2021/05/18 01:58

編集2021/05/19 02:44
SurferOnWww

総合スコア17335

sazi👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

sazi

2021/05/18 02:36

SQLはアクセスの文法で記述できるんですね。 いまいちそこが明言できなかったんです。
tkm_43522

2021/05/18 07:16

ありがとうございます。 ご推察の通り、gridviewのselectやページング機能は利用したいと考えています。 編集の機能は使う予定はありません。 昨日の時点で、selectcommandのORDER BY句に優先順位をつけることで初期画面では希望する並び順にすることができるのは確認できていたので、 質問欄に追記したようにしてみたところ、 gridview.sortingイベント発生時に、e.SortExpressionでフィールド名を取得、selectcommandを書き換えて、gridview本来のソートをe.cancelでキャンセルすることでヘッダーを押して起こる並び替えを防ぐ、とすることで、 任意の列のヘッダーをクリックするたびに期待するように並び替えられるようになりました。 gridviewの内部的な動きでよくわかっていないこともあるため、スマートなやり方では無いと思いますが、ヘッダーをクリックするたびに昇順降順を切り替えられていますし、select機能も利用できています。 ですが、一つ期待通りになっていない点があります。 できれば並び替えた後にどのフィールドが降順あるいは昇順で並び替わっているか判定するため、SortedAscendingHeaderStyleとSortedDescendingHeaderStyleプロパティでそれぞれ矢印と色を設定していたのですが、お示ししたやり方だとsortイベントをキャンセルしてしまっているので、並び替え後もヘッダーに何の変化もなくなってしましました。 イベントをキャンセルしてしまっているので、当然なのですが、 sortingイベントを経由せずに、gridviewの指定したヘッダーが並び替わっていることにコードで設定する方法はあるのでしょうか? e.cancelに続けて、e.sortdirection = "Ascending" や、gridview.SortDirection = "Ascending"などと鞣してみましたが、前者は型が違うようで、後者はreadonlyなのでどうもうまくいきません。 度々すみませんが、ご教示いただけませんでしょうか?
sazi

2021/05/18 07:39 編集

GridViewは詳しくありませんけど、並べ替えについてorder byで複数項目使用している事により弊害が発生しているなら、SQLでソート用のカラムを生成すれば良いのではないかと思うのですが。
tkm_43522

2021/05/18 08:06

gridviewの並べ替えたい列のヘッダーのリンクをクリック ⇓ 数値文字混在のデータが格納されているフィールドで数値の大小順、文字列は辞書順で並べ替え ⇓ もう一度ヘッダーをクリックすると逆順に並べ替え とできるようにしたいので、SQLでソート用のカラムを生成しても結局最終的にsqlselectcommandを書き換えてソートし、gridviewへ反映させることになるため、同じことになるのではないかと思います。 並べ替え自体はおかげさまでうまくいっています。 gridviewの機能として備わっている、ヘッダーのリンクをクリックすることで並べ替えが実行されるというイベントに割り込んで、その機能をキャンセルしてしまっているためにsortイベントを完了できないことが原因だと思っています。 sortされたgridviewには、gridview.sortexpression, gridview.sortdirectionといったプロパティがあるので、そのへんをコードで書き換えられれば解決するような気がするのですが、それらはreadonlyのプロパティのようなのでどうしたらよいか困っています。
sazi

2021/05/18 09:22 編集

並べ替えが行われる項目を生成してあげれば、キャンセルする必要がなくなると思ったのですが、違うんでしょうか? SQLのイメージは以下の様なものです。 select iif(isnumeric([フィールド]), val([フィールド]),Null) as sort1, iif(isnumeric([フィールド]),Null, [フィールド]) as sort2, * from [XXX]
SurferOnWww

2021/05/18 09:05

どういうコードを書いたのですか? 昇順降順の切り替えはそれなりににコーディングしないとできないはずですし、ページングで別ページを表示すると元に戻ってしまうと思うのですが・・・ 質問欄を編集して追記してください。
tkm_43522

2021/05/18 09:32

すみません、よくわからなかったのですが、 selectcommandをselect iif(isnumeric([フィールド]), val([フィールド]),Null) as sort1, iif(isnumeric([フィールド]), [フィールド],Null) as sort2, * from [XXX] order by [sort1] とするということでしょうか? その場合、gridviewの並べ替えをキャンセルしないと、結局最終的にヘッダーをクリックした列がgridviewの機能により並べ替えられて表示されてしまうため、結果gridviewの表示は 1→10→2→20→30→あいうえお となってしまいます。 勘違いしていたらすみません。
sazi

2021/05/18 09:41 編集

SQLはあくまでイメージです。 > 最終的にヘッダーをクリックした列がgridviewの機能により並べ替えられて表示されてしまう ヘッダーをクリックしたら、その項目でソートされるのは自然だと思いますので、不自然でない項目のみとなるようにselectで編集すれば良いのでは?というのが趣旨です。
tkm_43522

2021/05/18 09:41

SurferOnWwwさん コードは追記した通りとなります。 ヘッダーのリンクをクリックした際のonsortingイベントで、フィールド名を取得して、それを用いてsqldatasourceのselectcommandを作って、Accessからデータを取得し直しているため、Gridviewがそもそも新たに作られている(表現がわからないので、作られていると書きました)と考えています。 昇順降順に関しては、 一度並べ替えをすると、selectcommandに"ASC"か"DSC"が存在しているはずなので、それを単純に書き換えて、selectcommandを更新しているだけです。
SurferOnWww

2021/05/18 12:20

ページングで別ページを表示すると OnSorted ハンドラは通らないので、元の SelectCommand での抽出に戻ってしまうと思うのですが? で、ページ遷移の後ソートしたり、ページング操作とソート操作を交互に行ったりすると期待した結果になならないと思うのですが、どうですか? ページングとか編集が入ると無理だと思うのですが。
tkm_43522

2021/05/18 12:34

そうかも知れません。すみませんがページングは試しておらず、selectコマンドのみ試してみましたので。明日試してみようと思います。 編集はする予定がないので、できなくても問題ありません。 ページングはできたほうが良いのですが、想定している目的とデータ量ならできなくても大きな問題はないので、最低限セレクトさえ使えれば良いと思っています。 であれば、一応今のままで並べ替え列と向きが明示されればいいかなと思っていますが、直接gridviewのheaderstyleを書き換えるしかないでしょうか?
SurferOnWww

2021/05/18 12:43

ページングをすると期待した動作にならないのであれば、そこを解決しない限りその先の話をしても意味がないのでは? ダメならページングは諦めるとか言いう緩い要件の話だったのでしょうか。(だから、最初に編集・ページングも考えると無理筋だと言ったのですが)
tkm_43522

2021/05/18 13:28 編集

おっしゃる通りですね。 データ量が今後大幅に増えるとページングが必要になってくると思いますので、絶対に必要とはされていませんが、妥協せずページングも目指してみます。 とりあえず、現状でページングをした際に、おっしゃるように大元のselectcommandに戻ってしまうか確認してみます。 onsotingでソートをキャンセルしているので、onsortedハンドラも発生していないように思っていたのですが、そうはならないんですね。 gridviewがページングをするたびにsqldatasourceにデータを取りに行ってるとは知りませんでした。 GridViewコントロール(正確にはSqlDataSourceコントロール)では、内部的にはグリッド表に表示するすべてのデータをいったん取得してから、1ページ分のデータだけを抽出して表示しているにすぎないので、一度データを読み込んだら次にselectcommandが書き換わるまでデータを拾いに行かないと思っていました。 また、質問する際に、達成すべき要件の重要度をお伝えせずすみませんでした。以降は気をつけるようにします。
tkm_43522

2021/05/19 00:37

ページングが機能するか確認してみました。 並べ替え(昇順)→2ページ目に移動→並べ替え(降順)→1ページ目に移動→並べ替え(昇順) と何度か交互に試してみたところ、完全に意図したとおりに機能していました。 具体的には昇順で並び替えのときには数値の小→大、文字列辞書昇順と並び、2ページ目に移動した際には、きちんと先頭行は61個目の値(1ページ60行で設定)となっており、その状態で降順並べ替えをした際にも2ページの先頭行は降順の61個目の値となっております。 一応、selectが機能するか、textboxを設置して、フィールドAの値を表示させてみましたが、問題なく表示されたため、必要としていたページングとselectの機能を使用できる状態で望むように並べ替えができました。 一点補足させてください。 5/18にコードを載せた際に、pageloadの部分を転記し忘れていました。 作成したコードでは、ORDER BY句を追加したselectcommandを、onsortingイベント内でhiddenfieldに代入し、pageloadでhiddenfieldからselectcommandを改めて読みこんでいるので、ページングや昇順降順の切り替えが機能するだと思います。 昨日転記した不完全なコードをご覧になったためSurferOnWwwさんがページングが機能しないのでは、とおっしゃったのは尤もなことです。 余計なお手間を取らせて大変申し訳ありませんでした。 試しに、pageloadでselectcommandを読み込む行程を削除したところ、やはりページングは意図したとおりに機能せず、ページングをするたびに並び替えがリセットされてしまいました。 ページングの際にpageloadされるというのは知りませんでしたので、大変参考になりました。 並べ替えの部分が意図したとおりに機能することがわかったので、改めてSortedAscendingHeaderStyleが適用される方法を考えたいと思いますが、よい方法を御存知でしたらご教示いただけますでしょうか。 度々ですみませんが、よろしくお願いいたします。 onsortingイベントの際にheaderstyleを書き換えることでもできるのかなとは思うのですが、ページングの際にこちらも元に戻ってしまうでしょうし、それもpageloadで設定するようにすればよいのかもしれませんが、もっとスマートなやり方があるような気がしています。 gridviewのプロパティを編集して、あたかもcancelしたsortイベントが起こったかのように設定できればと思うのでしょうがいかがでしょうか。 よろしくお願いいたします。
SurferOnWww

2021/05/19 02:42

上のコメントに対するレスは回答欄に追記します。
SurferOnWww

2021/05/19 04:40

上の回答欄の【追記】ように言っておきながら、それではできなかったら何なので、サンプルを作って検証してみました。後でそれを回答欄に追記しておきます。

1

ベストアンサー

Access側に並べ替えをしたクエリーを作成して、そのクエリーを参照するのが最も簡単だと思います。

並べ替えに利用できそうな関数として、Val関数があります。

フィールド内に混在ではなく数値か文字かという事なら、以下の様に数値のみのソートを優先すれば希望の並びになるかと思います。

SQL

1order by IsNumeric([フィールド]), Val([フィールド]), [フィールド]

※Val()は文字列先頭の数値を返却します。先頭が数字でない場合は0が返却されます。
IsNumeric()はFalse=0 True=-1

投稿2021/05/17 08:33

sazi

総合スコア24562

SurferOnWww👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

tkm_43522

2021/05/17 08:56

ありがとうございます。 ORDER BYに複数条件を設定できるんですね! 基礎的なことなのかもしれませんが、知りませんでした。 大変参考になりました。 教えて頂いたように、早速sqlselectcommandのORDER BYにIsNumeric([フィールド]), Val([フィールド]), [フィールド]と追記してみたところ、期待していた動作ができるようになりました。 webアプリとして開発しているので、アクセス側にクエリを作成するのをsqldatasourceを介して行いたいのですが、どうすればよいかご存知でしたらご教示いただけますでしょうか。
sazi

2021/05/17 10:20 編集

commandでorder byの指定がエラーにならないなら、クエリーは作成する必要はありません。
tkm_43522

2021/05/18 10:27

すみません、SurferOnWwwさんの回答に書き続けていると、話がごちゃごちゃになりそうなのでこちらで続けさせていただきます。 saziさんのおっしゃりたいことは、数値文字列混在の列から、例えば数値のみにしたカラムを新たにsort1などと名前をつけて生成して、それを並べ替えれば良いということですよね? それはわかるのですが(勘違いしていたら申し訳ありません)、その後のイメージがやはり湧きません。 理解力がなくて申し訳ない限りですが、 そうして適切な順序で並べ替えても、キャンセルしないとgridviewにバインドされたあとでe.sortexpressionとe.sortdirectionに基づいて望まない形で並べ替えられてしまうのです。 ですのでバインドさせたあとで並べ替えがなされる必要があり、e.sortexpressionをsort1などと書き換えないと、数値として並べ替えられるようにはならないのですが、その場合gridviewに新たに動的に列を追加して、そこを並べ替えることとなるので、レイアウトが崩れてしまうと思うのです。 ですので追記したコードのように、SurferOnWwwの表現する所の初期画面ですでに指定した任意の列が並び替えられている状態を作ったわけです。
sazi

2021/05/18 12:51

GridViewの事は詳しくありませんので、単にテーブルを表示させておけば、並べ替えに問題が生じないのであれば、という前提でカラム生成してはどうかという提案ですので、単なるテーブルの表示でも生じる並べ替えの問題であれば、スルーして下さい。
tkm_43522

2021/05/19 06:29

すみません、私はSQLに疎いので、もしかするとsaziさんのアドバイスで達成出来たのかもしれませんが、私の知識ではちょっとわかりませんでした。 今回教えていただいた、order by 句に優先順位をつけることでほぼ目的は達成出来たのですが、一点状況によってエラーが出てしまいます。 データベースに空の行があると、val関数でエラーが出て、「抽出条件でデータ型が一致しません」となってしまいます。 空白が含まれるようなデータに対応するためには、どのようなORDER BY句を設定すればよいのでしょうか? 並べ替えの順番としては、 数値の大小→文字列辞書順→空白 となると理想的です。 度々お手数ですが、よろしくお願いいたします。
sazi

2021/05/19 08:43

以下の様にNz()を加えてみてください。 order by IsNumeric([フィールド]), Val(Nz([フィールド])), [フィールド]
tkm_43522

2021/05/19 09:58 編集

ありがとうございます。 NzもSQLで使用できるんですね。IIFも使えるので、工夫すればほぼ望む形で並べ替えられそうです。 おかげさまで空白によるエラーは回避できました。 追加でもう一点教えていただきたいのですが、 val関数で、空白以外でもエラーが出てしまうデータがあり、 -1.5% や 1.5% などがval関数にかけると抽出条件でデータ型が一致しませんとなってしまいます。 空白がだめ、というのは調べれば出てきたのでわかったのですが、上記の文字列がなぜエラーとなるのかわかりません。 %が悪いのかと思い、 1.5 15% の文字列を試してみたところ、これらはエラーとはならないため、%が悪いわけではなく、 ピリオドと%の組み合わせが良くないということまではわかったのですが、 不思議なことに(ご存知の方からは不思議でもなんでも無いのでしょうが) 1.0%や 5.0% の様に.0%の場合は問題ないのです。 しかし、1.50%はだめで、さっぱりわかりません 一体これはどういう法則に基づいてエラーが生じているのでしょうか? val関数に値を入れるときにエラーを回避する方法や、他にもval関数でエラーが出る典型的な例がありましたら、ご教示いただけると嬉しいです。
sazi

2021/05/19 10:53

iif(IsNumeric([フィールド]), Val([フィールド]), Null) でどうですか? こういった式については、Accessのイミディエイトウインドウを使用して色々なケースの検証が出来ると思いますよ。
sazi

2021/05/19 11:04

元々の質問と関連しているとはいえ、コメントでのやり取りの内容が、なんだか、サポートの様相を呈している感じがしていますので、配慮をお願いします。
tkm_43522

2021/05/19 23:45

ありがとうございます。 勉強になりました。 >サポートの様相を呈している感じがしています 失礼しました。 数値文字列混在時の並べ替えが意図したとおりにならない、という本件の質問はとりあえず解決しました。 色々とありがとうございました。
SurferOnWww

2021/05/20 01:30

解決したようですのでベストアンサーを選んでクローズしてください。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。