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

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

新規登録して質問してみよう
ただいま回答率
85.50%
DataGrid

GUIの一種であり、データを表の形式でみることが可能です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

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

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

Q&A

解決済

2回答

4298閲覧

C# DataGridViewで日付の部分一致検索機能を付けたい

ponkotsuSE

総合スコア1

DataGrid

GUIの一種であり、データを表の形式でみることが可能です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

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

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

0グッド

0クリップ

投稿2020/11/17 01:54

前提・実現したいこと

【相談内容】
DataGridViewに表示されてる日時(時間含む)の日付のみを
部分又は前方一致検索できるようにしたいのでアドバイスをお願いします。

【詳細】
C#で社員番号や勤務時間の入力と日報作成のためのツールを作っています。

私はロガーを担当をしていて、ログ内容をテキストメモに出力させ
それをWindows FormsのDataGridViewで表示させるところまでできました。
直接DataGridViewに出力させないのはなるべくメモリの消費を抑えるためです。

また上記と同じ理由でデータベースにも接続せずに使いたいです。
(実際データグリッドに出力はできているので。)

NLogを使用しており、NLog.config(XML)内のlayoutで
${longdate}(書式はyyyy-MM-dd HH:mm:ss:mmmです)
を使用しているのでデータグリッドにもそのように表示されます。

検索機能を作成するにあたって、ログレベルは短い単語なので完全一致で
いいのですが、日付の検索もyyyy-MM-dd HH:mm:ss:mmmの形の完全一致でしかできません。
日付のみの部分(前方)一致での検索機能を付けるのに苦戦しています。
どなたかアドバイスをお願いできないでしょうか。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

C#

1  public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 toolTip1 = new ToolTip(); 7 } 8 9 private void Form1_Load(object sender, EventArgs e) 10 { 11 showLogs(); 12 } 13 14 private void button_Search_Click(object sender, EventArgs e) 15 { 16 searchLogs(); 17 } 18 19 private void button_Close_Click(object sender, EventArgs e) 20 { 21 try 22 { 23 throw new Exception(); 24 } 25 catch 26 { 27 LogUtil.Info("テスト ログ出力"); 28 29 } 30 31 Close(); 32 } 33 34 DataTable table = new DataTable(); 35 36 public void showLogs() 37 { 38 table.Columns.Add("日付と時刻", typeof(string)); 39 table.Columns.Add("ログレベル", typeof(string)); 40 table.Columns.Add("メッセージ", typeof(string)); 41 table.Columns.Add("情報", typeof(string)); 42 43 dataGridView1.DataSource = table; 44 45 string[] lines = File.ReadAllLines(@"C:~~~\testlog\testlog.log"); 46 string[] values; 47 48 for (int i = 0; i < lines.Length; i++) 49 { 50 values = lines[i].ToString().Split('/'); 51 string[] row = new string[values.Length]; 52 53 for (int j = 0; j < values.Length; j++) 54 { 55 row[j] = values[j].Trim(); 56 } 57 58 table.Rows.Add(row); 59 } 60 61 } 62 63 public void searchLogs() 64 { 65 DataTable sub = new DataTable("sub"); 66 67 DataRow[] dRows1 = table.AsEnumerable() 68 .Where(row1 => row1.Field<string>("日付と時刻") == textBox1.Text).ToArray(); 69 70 DataRow[] dRows2 = table.AsEnumerable() 71 .Where(row2 => row2.Field<string>("ログレベル") == comboBox1.Text).ToArray(); 72 73 // カラム名の追加 74 sub.Columns.Add("日付と時刻"); 75 sub.Columns.Add("ログレベル"); 76 sub.Columns.Add("メッセージ"); 77 sub.Columns.Add("情報"); 78 79 foreach (var row1 in dRows1) 80 { 81 sub.Rows.Add(row1[0], row1[1], row1[2], row1[3]); 82 } 83 84 foreach (var row2 in dRows2) 85 { 86 sub.Rows.Add(row2[0], row2[1], row2[2], row2[3]); 87 } 88 89 dataGridView1.DataSource = sub; 90 91      //以下試してみたけど動きませんでした。 92    System.Text.RegularExpressions.MatchCollection dRow1 = 93 System.Text.RegularExpressions.Regex.Matches( 94 textBox1.Text, @"\d\d\d\d-\d\d-\d\d"); 95 foreach (System.Text.RegularExpressions.Match m in dRow1) 96 { 97 sub.Rows.Add(row1[0], row1[1], row1[2], row1[3]); 98 } 99 }   100 } 101

試したこと

・NLog.configの${longdate}はハイフンで日時が表示されるので
スラッシュ表記のDateTimePickerはできなさそうでした。

・DateSetを使用していないのでMatch,Selectメソッドはダメでした。

・ContainsメソッドやIndexOfメソッドの仕様が最適だと考えているのですが
データグリッドの内容をコードで直接書いているわけでない(テキストの読み込み)ので
書き方がわかりませんでした。

補足情報(FW/ツールのバージョンなど)

環境:Visual Studio 2019

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/11/17 02:31

DataTable の「日付と時刻」列の型が DateTime 型でないのは理由があるのでしょうか?
退会済みユーザー

退会済みユーザー

2020/11/17 02:32

BindingSource を使わないのには何か理由がありのですか?
ponkotsuSE

2020/11/17 02:49

コメントありがとうございます。 >DataTable の「日付と時刻」列の型が DateTime 型でないのは理由があるのでしょうか? すみません、プログラミング自体初心者過ぎてほとんどコピペに文字を書き換えただけなのでDateTime型に変換するというのがあまり理解できていないです、、 今少し書いてみたのですがDateTime型はカラムとRowの定義がないとエラーが出たのですがどうやって定義してあげればいいのでしょうか >BindingSource を使わないのには何か理由がありのですか? 一度調べて試したのですがBindingSourceってデータベースに接続しないと使えないのかな?という風に思っていました。
退会済みユーザー

退会済みユーザー

2020/11/17 04:10 編集

> 今少し書いてみたのですがDateTime型はカラムとRowの定義がないとエラーが出たのですがどうやって定義してあげればいいのでしょうか showLogs メソッドの DataTable の「日付と時刻」列の定義で、 table.Columns.Add("日付と時刻", typeof(string));  ↓↓↓ table.Columns.Add("日付と時刻", typeof(DateTime)); のように変更して、その列だけには row[j] = values[j].Trim(); のところで values[j].Trim() の値を DateTime 型に Parse してから代入するようにしてはいかがですか? そうすれば、DataTable から Linq to Objects で特定の日付けを検索する際に、DataTime 構造体に備わっている種々プロパティを利用できるので、「日付のみの部分(前方)一致での検索機能を付けるのに苦戦」などの検索するのがいろいろと容易になるのではと思いました。 > 一度調べて試したのですがBindingSourceってデータベースに接続しないと使えないのかな? そんなことはないです。 DataGridView ⇔ BindingSource ⇔ DataTable という構造にするのは普通に行うべきことです。Microsoft の DataGridView.DataSource プロパティのドキュメントにも以下のように書いてあります。 "通常、BindingSource コンポーネントにバインドし、BindingSource コンポーネントを別のデータ ソースにバインドするか、このコンポーネントにビジネス オブジェクトを設定します。データ ソースには BindingSource コンポーネントを使用することをお勧めします。このコンポーネントを使用することで、さまざまなデータ ソースにバインドできるほか、データ バインディングに関する各種の問題を自動的に解決できます"
guest

回答2

0

ベストアンサー

質問のコメント欄で書いたことですが、言葉だけではピンとこないでしょうから、参考にサンプルコードを書いておきます。

まずコメント欄で書いたことの繰り返しですが・・・

今少し書いてみたのですがDateTime型はカラムとRowの定義がないとエラーが出たのですがどうやって定義してあげればいいのでしょうか

showLogs メソッドの DataTable の「日付と時刻」列の定義で、

table.Columns.Add("日付と時刻", typeof(string));
↓↓↓
table.Columns.Add("日付と時刻", typeof(DateTime));

のように変更して、その列だけには row[j] = values[j].Trim(); のところで values[j].Trim() の値を DateTime 型に Parse してから代入するようにしてはいかがですか?

そうすれば、DataTable から Linq to Objects で特定の日付けを検索する際に、DataTime 構造体に備わっている種々プロパティを利用できるので、「日付のみの部分(前方)一致での検索機能を付けるのに苦戦」などの検索するのがいろいろと容易になるのではと思いました。

そのサンプルコードは以下の通りです。デザイン画面で Form に Panel, DataGridView, BindingSource をドラッグ&ドロップし、さらに Panel の中に DateTimePicker, Button をドラッグ&ドロップしています。

using System; using System.Data; using System.Linq; using System.Windows.Forms; namespace WinFormsApp1 { public partial class Form10 : Form { private DataTable table; public Form10() { InitializeComponent(); this.dataGridView1.DataSource = this.bindingSource1; } private void Form10_Load(object sender, EventArgs e) { ShowLogs(); this.bindingSource1.DataSource = table; } protected void ShowLogs() { this.table = new DataTable(); table.Columns.Add("日付と時刻", typeof(DateTime)); table.Columns.Add("ログレベル", typeof(string)); table.Columns.Add("メッセージ", typeof(string)); table.Columns.Add("情報", typeof(string)); var today = DateTime.Now; for (int i = 0; i < 50; i++) { DataRow row = table.NewRow(); row["日付と時刻"] = today.AddDays(i); row["ログレベル"] = "ログレベル" + i; row["メッセージ"] = "メッセージ" + i; row["情報"] = "情報" + i; table.Rows.Add(row); } } private void button1_Click(object sender, EventArgs e) { var result = this.table.AsEnumerable(). Where(row => row.Field<DateTime>("日付と時刻").Date == this.dateTimePicker1.Value.Date). ToArray(); } }

実行結果は以下の画像のようになります。DataTimePicker を開いて 11/19 を選択したところです。

イメージ説明

上のサンプルコードで button1_Click にブレークポイントを置いて Search ボタンをクリックしたときのデバッグ画面が以下の画像です。期待通り 11/19 のデータが選択されています。

イメージ説明

投稿2020/11/17 04:40

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ponkotsuSE

2020/11/17 04:53

ありがとうございます! 非常に助かります。 じっくりやってみます!
ponkotsuSE

2020/11/17 06:31

もともと私が書いてた for (int i = 0; i < lines.Length; i++) { values = lines[i].ToString().Split('/'); string[] row = new string[values.Length]; for (int j = 0; j < values.Length; j++) { row[j] = values[j].Trim(); } table.Rows.Add(row); } の部分と、SurferOnWwwさんのサンプルコードの for (int i = 0; i < 50; i++) { DataRow row = table.NewRow(); row["日付と時刻"] = today.AddDays(i); row["ログレベル"] = "ログレベル" + i; row["メッセージ"] = "メッセージ" + i; row["情報"] = "情報" + i; table.Rows.Add(row); } のうまい結合の仕方?がわかりません。。 ローカル変数rowの名前がかぶってしまっているため片方をrow1にするなどしてみたのですがエラーが出てしまいます。。 また上記の2つのfor文のどちらかをコメントアウトしても例外が発生したりReasAllLinesで呼び出したテキストが出力されなかったりでつまずいています。 ここのfor文の書き方についてもう少しヒントをいただけますか?
退会済みユーザー

退会済みユーザー

2020/11/17 07:09 編集

table.Rows.Add(row); ですが、Add にはオーバーロードが 2 つあって、引数に DataRow を取るものと Object[] を取るものがあります。 私のコードは前者、質問者さんのコードは後者です。違いは、 前者: 引数の DataRow をテーブルに追加。 後者: 引数の Object[] から行を作成し、その行をテーブルに追加。 です。なので、質問者さんのコードを使う場合は row は string[] 型ではなくて object[] 型に変更し、row[0] には values[j].Trim() を DateTime 型に Parse して代入、その他 row[1] ~ row[3] にはそのまま string 型の values[j].Trim() を代入してやるということでうまくいくのではないかと思います。
ponkotsuSE

2020/11/17 09:00

ご丁寧にありがとうございます。 SurferOnWww様のアドバイス通りに書いてみたのですが DateTime dTime = DateTime.ParseExact(strTime, format, null); を定義する際にstrTimeで定義した日にちのみグリッドに表示されてしまったり、AddDaysを書いてstrTimeに1日ずつ追加されてしまったり(当たり前ですが)で、テキストのログ通りの日付が表示されなくてなかなか進まずです、、汗 私の書く場所やそもそものことが間違えてるということが多すぎる可能性があるので引き続き頑張ります!
退会済みユーザー

退会済みユーザー

2020/11/17 09:13

> 私の書く場所やそものことが間違えてる そういうことだと思います。「AddDaysを書いて」とか迷走してませんか? 仕事でやっているようですが、そうであれば上司・先輩に相談してはいかがでしょう。ここのような Q&A サイトでは、書いてないことは回答者・閲覧者には分かりませんので時間がかかるばかりです。
退会済みユーザー

退会済みユーザー

2020/11/17 23:53

DateTime 型を使うのに手間取って前に進めないのであれば、元に戻って、日時も String 型で扱って、Linq の Where メソッドのラムダ式に最初に考えた「ContainsメソッドやIndexOfメソッド」を使った方が早そうです。
ponkotsuSE

2020/11/18 00:22

何度もご丁寧にアドバイスをくださりありがとうございます。 確かに私個人のレベルや知識・経験不足はネット上では補いきれない 部分のが多いですね。。身近な人にもう少し相談してみようと思います。 試行錯誤しながら学習していきたいと思います。 ありがとうございます。
退会済みユーザー

退会済みユーザー

2020/11/18 00:43 編集

こういった質問サイトでは技術的な実現方法のヒント・回答は得られますが、回答者側からは質問者のスキル等は判らず、またスキルが無い人に1から10まで全て説明する訳にもいかないので、質問者側にもある程度回答を理解するための基礎知識を要求されます。言語知識はは勿論のこと、.NETのAPIリファレンスで使用対象のクラス・構造体の説明を熟読したり、サンプルを探したりするとよいでしょう。(今回だとDateTimeの使用方法を理解する必要があります) Webだとどうしてもタイムラグがあるので、身近に聞ける人が居るなら聞いた方が手っ取り早いですね。
ponkotsuSE

2020/11/18 00:58

SurferOnWww様 radian様 技術的な実現方法のアドバイスから、質問の仕方・事前段階のことまで 的確に助言・ご指導してくださり本当にありがとうございます。 初心者ならなおさら、(回答内容を理解するための)ある程度の基礎知識が必要となるネットに頼らず、自分のレベル・ペースを把握している身近な方々と積極的にコミュニケーションをとりながら質問して謙虚に学習に励もうと思いました。
退会済みユーザー

退会済みユーザー

2020/11/18 01:11

自助努力で解決するというのには異論はありませんが、それに時間がかかってこのスレッドは放置状態になるのであれば、その旨書いてこのスレッドはクローズしてください。
guest

0

日時文字列の形式が判っているのであれば、ログから日時文字列を切り出してDateTime.TryParse(Exact)でDateTimeに変換し、DateTimeに対して範囲検索を行えばよいかと思います。

投稿2020/11/17 02:07

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ponkotsuSE

2020/11/17 02:10

やってみます! ありがとうございます。
退会済みユーザー

退会済みユーザー

2020/11/17 02:13 編集

ログのDataTable作成時点で、DateTime型のカラムを作成し、そこに日時を設定しておくと良いかもしれません。DateTime型で持っておくと、検索も容易ですしDataGridView側で日付の出力フォーマットを変更したり出来るので柔軟性が増します。
ponkotsuSE

2020/11/17 02:19

DataTable sub = new DataTable("sub"); sub.Columns.Add("日付と時刻"); とは別に、ということでしょうか?
退会済みユーザー

退会済みユーザー

2020/11/17 03:00

そこをDateTime型カラムにしてもいいと思いますよ
退会済みユーザー

退会済みユーザー

2020/11/18 00:57 編集

範囲検索を考慮してDateTime型への変換をお勧めしましたが、とりあえず部分一致で調べれればいいのであればこれでいいかもしれません。 https://blog.hiros-dot.net/?p=5130 DateTimePicker辺りでDateTime値を取得し、ToStringで検索文字列の書式にフォーマットすれば良いかと思います。
ponkotsuSE

2020/11/18 01:00

ありがとうございます! このサイトはまだ見ていませんでした。 やってみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問