ラベル LINQ の投稿を表示しています。 すべての投稿を表示
ラベル LINQ の投稿を表示しています。 すべての投稿を表示

ガントチャート作成日記

あいかわらずのんびりと作成中。
タスクの削除を付けたが、チャートの削除をまだつけていないことに気づいた。
っていうかそれ以前にデータの保存処理を付けてないし、初期の日付範囲とかも一切つけていない。



プロジェクトの初期設定として、プロジェクトの開始日・終了日を変更できるようにすることから始めるべきかな・・・。

頑張ったところとしては、左側のタスクの一番左側のタスクの縦幅を広げて、大きいグループの範囲を広げた時に、濃い線をタスクの一覧とガントチャートの一覧に表示して、どこまでがグループに属しているかをわかりやすくしたことと、マウスで複数のチャートを選択・移動できるようにした。

グループを表現する線についてはGanttGridTemplateSelecter.csとGanttGridTaskViewTemplateSelecter.csにパターンを追加して、DataTemplateを新しく定義してこちゃこちゃすればできるけど、マウスでの移動については一苦労した。
CanvasコントロールをGridコントロールの下に張り付けて、Rectを新たに描画している。

Canvasコントロールを追加したことでスクロールバーがうまく出なくなってしまったので、SizeChangeイベントで変更するようにした。

マウスの範囲選択でGridコントロール上のチャートを選択するのもネットで調べてみるといろいろとサンプルがある。
世の中にはすごい人がいるなぁ。

<ソース>
        #region 右側のCanvasのサイズを合わせる

        // マウスで複数選択をさせるためにCanvasコントロールを利用しているがCanvasコントロールはScrollBarが出しずらい
        // ガントチャートの上にCanvasをTransportで重ねることも考えたが、チャートをクリックできなくなってしまう。
        // Canvasコントロールをクリックしたときの通知などをチャート側に伝えるようにすればよいが、さすがに手間なので
        // Canvasコントロールのサイズを変更しScrollBarが出るようにした。

        /// <summary>
        /// 幅を合わせる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridCalender_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Grid grid = (Grid)sender;
            CalenderBaseCanvas.Width = e.NewSize.Width;
        }

        /// <summary>
        /// 高さはタスク一覧側と同じになるので合わせる
        /// gridCalender側と合わせるとタスクが少ないときにスクロールバーが上に出てしまう
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void icTaskGrid_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            CalenderBaseCanvas.Height = icTaskGrid.ActualHeight;
        }
        #endregion

<DownLoad>

LINQ to Objectについて

今日はLINQ to Objectをクエリ形式で利用してGroupBy句を作成。
GroupByで集計単位を指定しinto句でGroupオブジェクトを生成。

SQLと違ってまとまったGroupオブジェクトをループで取得できるので帳票を作りるときや総合計を出しつつ、明細を表示する場合などに便利。

WPFのDataGridでGroupingしたりTreeListViewなどで表示するといい感じに見える。

販売管理システムとかだと請求書などで鏡の部分を作成しつつ、明細の部分も表示するようなときに使いやすい。

    Private Sub btnGroup_Click(sender As Object, e As EventArgs) Handles btnGroup.Click
        Dim dtUri As New DataTable
        Dim drUriSample As DataRow

        ' ▼ 売上データ
        dtUri.Columns.Add(New DataColumn("売上No", GetType(Integer)))
        dtUri.Columns.Add(New DataColumn("売上日", GetType(String)))
        dtUri.Columns.Add(New DataColumn("得意先CD", GetType(String)))
        dtUri.Columns.Add(New DataColumn("商品名", GetType(String)))
        dtUri.Columns.Add(New DataColumn("売上数量", GetType(Decimal)))
        dtUri.Columns.Add(New DataColumn("売上金額", GetType(Decimal)))

        '   テストデータ
        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "パソコン"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 150000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 2
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00002"
        drUriSample("商品名") = "マウス"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 3000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "モニター"
        drUriSample("売上数量") = 2
        drUriSample("売上金額") = 30000
        dtUri.Rows.Add(drUriSample)

        Dim lnqGroup = From drUri In dtUri.AsEnumerable
                       Group By TokCD = drUri("得意先CD")
                           Into grp = Group
                       Select New With {
                             .得意先CD = TokCD,
                             .grp = grp
                             }



        Dim strMsg As String = ""

        For Each lnqdr In lnqGroup
            strMsg += "得意先CD:" & lnqdr.得意先CD & vbCrLf
            strMsg += "合計金額:" & lnqdr.grp.Sum(Function(drChild) drChild("売上金額")) & vbCrLf

            'まとまった単位
            For Each drGrpChild In lnqdr.grp
                strMsg += "商品名:" & drGrpChild("商品名") & " 数量:" & drGrpChild("売上数量") & " 金額:" & drGrpChild("売上金額") & vbCrLf
            Next

            MsgBox(strMsg)
            strMsg = ""

        Next

    End Sub


LINQ to Objectについて

LINQ to Objectはとても便利だけど、DataTableとかDataSetを使ったサンプルがあんまりないので、メモ。
DataTable自体があまり使われないのかもしれないけど、データベースからとってきた値をとりあえず入れて使う分には使いやすいのでよく使う。
プログラマーによってクラスの作り方がバラバラだったり、共通関数に渡すときに統一できたりとか、Webサービスからデータを渡すときに簡単に渡せたりするんで結構重宝している。

CSVとデータベースの値を結合したり、CSVとCSVを結合したりするときにもSQLみたいに書きたい要望があったりするのでそのサンプル。
※まれにデータが数百万行あったりして、SQLよりもLINQで処理したほうが早いケースがあったりするときに書き直したりする。

VB.NET ====

    ''' <summary>
    ''' Left Join
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub btnLeftJoin_Click(sender As Object, e As EventArgs) Handles btnLeftJoin.Click
        Dim dtUri As New DataTable
        Dim drUriSample As DataRow

        ' ▼ 売上データ
        dtUri.Columns.Add(New DataColumn("売上No", GetType(Integer)))
        dtUri.Columns.Add(New DataColumn("売上日", GetType(String)))
        dtUri.Columns.Add(New DataColumn("得意先CD", GetType(String)))
        dtUri.Columns.Add(New DataColumn("商品名", GetType(String)))
        dtUri.Columns.Add(New DataColumn("売上数量", GetType(Decimal)))
        dtUri.Columns.Add(New DataColumn("売上金額", GetType(Decimal)))

        '   テストデータ
        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "パソコン"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 150000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 2
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00002"
        drUriSample("商品名") = "マウス"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 3000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "モニター"
        drUriSample("売上数量") = 2
        drUriSample("売上金額") = 30000
        dtUri.Rows.Add(drUriSample)


        ' ▼ 得意先データ
        Dim dtTok As New DataTable
        Dim drTokSample As DataRow

        dtTok.Columns.Add(New DataColumn("得意先CD", GetType(String)))
        dtTok.Columns.Add(New DataColumn("得意先名", GetType(String)))
        dtTok.Columns.Add(New DataColumn("備考", GetType(String)))

        '   テストデータ
        drTokSample = dtTok.NewRow
        drTokSample("得意先CD") = "00001"
        drTokSample("得意先名") = "株式会社 システム作ろう"
        drTokSample("備考") = ""
        dtTok.Rows.Add(drTokSample)

        drTokSample = dtTok.NewRow
        drTokSample("得意先CD") = "00002"
        drTokSample("得意先名") = "株式会社 いろいろ販売"
        drTokSample("備考") = ""
        dtTok.Rows.Add(drTokSample)

        Dim dtUriIchiran As New DataTable
        Dim drIchiran As DataRow

        ' ▼ 売上一覧
        dtUriIchiran.Columns.Add(New DataColumn("売上No", GetType(Integer)))
        dtUriIchiran.Columns.Add(New DataColumn("売上日", GetType(String)))
        dtUriIchiran.Columns.Add(New DataColumn("得意先CD", GetType(String)))
        dtUriIchiran.Columns.Add(New DataColumn("得意先名", GetType(String)))
        dtUriIchiran.Columns.Add(New DataColumn("売上数量", GetType(Decimal)))
        dtUriIchiran.Columns.Add(New DataColumn("売上金額", GetType(Decimal)))

        Dim lnqIchiran = From drUri In dtUri.AsEnumerable
                         Group Join drTok In dtTok
                         On drUri("得意先CD") Equals drTok("得意先CD")
                         Into grp = Group
                         From drTokEmpty In grp.DefaultIfEmpty
                         Select New With {
                             .売上No = drUri("売上No"),
                             .売上日 = drUri("売上日"),
                             .得意先CD = drUri("得意先CD"),
                             .得意先名 = If(drTokEmpty("得意先名") Is Nothing, "", drTokEmpty("得意先名")),
                             .売上数量 = drUri("売上数量"),
                             .売上金額 = drUri("売上金額")
                             }

        For Each lnqdr In lnqIchiran
            drIchiran = dtUriIchiran.NewRow
            drIchiran("売上No") = lnqdr.売上No
            drIchiran("売上日") = lnqdr.売上日
            drIchiran("得意先CD") = lnqdr.得意先CD
            drIchiran("得意先名") = lnqdr.得意先名
            drIchiran("売上数量") = lnqdr.売上数量
            drIchiran("売上金額") = lnqdr.売上金額
            dtUriIchiran.Rows.Add(drIchiran)
        Next

    End Sub


C# ====


        private void btnLeftJoin_Click(object sender, EventArgs e)
        {
            DataTable dtUri = new System.Data.DataTable();
            DataRow drUriSample = null;

            // ▼ 売上データ

            dtUri.Columns.Add(new DataColumn("売上No", typeof(int)));
            dtUri.Columns.Add(new DataColumn("売上日", typeof(string)));
            dtUri.Columns.Add(new DataColumn("得意先CD", typeof(string)));
            dtUri.Columns.Add(new DataColumn("商品名", typeof(string)));
            dtUri.Columns.Add(new DataColumn("売上数量", typeof(decimal)));
            dtUri.Columns.Add(new DataColumn("売上金額", typeof(decimal)));

            //   テストデータ
            drUriSample = dtUri.NewRow();
            drUriSample["売上No"] = 1;
            drUriSample["売上日"] = "20171031";
            drUriSample["得意先CD"] = "00001";
            drUriSample["商品名"] = "パソコン";
            drUriSample["売上数量"] = 1;
            drUriSample["売上金額"] = 150000;
            dtUri.Rows.Add(drUriSample);

            drUriSample = dtUri.NewRow();
            drUriSample["売上No"] = 2;
            drUriSample["売上日"] = "20171031";
            drUriSample["得意先CD"] = "00002";
            drUriSample["商品名"] = "マウス"; ;
            drUriSample["売上数量"] = 1;
            drUriSample["売上金額"] = 3000;
            dtUri.Rows.Add(drUriSample);

            drUriSample = dtUri.NewRow();
            drUriSample["売上No"] = 1;
            drUriSample["売上日"] = "20171031";
            drUriSample["得意先CD"] = "00001";
            drUriSample["商品名"] = "モニター";
            drUriSample["売上数量"] = 2;
            drUriSample["売上金額"] = 30000;
            dtUri.Rows.Add(drUriSample);


            // ▼ 得意先データ
            DataTable dtTok = new DataTable();
            DataRow drTokSample = null;

            dtTok.Columns.Add(new DataColumn("得意先CD", typeof(string)));
            dtTok.Columns.Add(new DataColumn("得意先名", typeof(string)));
            dtTok.Columns.Add(new DataColumn("備考", typeof(string)));

            //   テストデータ
            drTokSample = dtTok.NewRow();
            drTokSample["得意先CD"] = "00001";
            drTokSample["得意先名"] = "株式会社 システム作ろう";
            drTokSample["備考"] = "";
            dtTok.Rows.Add(drTokSample);

            drTokSample = dtTok.NewRow();
            drTokSample["得意先CD"] = "00004";
            drTokSample["得意先名"] = "株式会社 いろいろ販売";
            drTokSample["備考"] = "";
            dtTok.Rows.Add(drTokSample);


            DataTable dtUriIchiran = new DataTable();
            DataRow drIchiran = null;

            // ▼ 売上一覧
            dtUriIchiran.Columns.Add(new DataColumn("売上No", typeof(int)));
            dtUriIchiran.Columns.Add(new DataColumn("売上日", typeof(string)));
            dtUriIchiran.Columns.Add(new DataColumn("得意先CD", typeof(string)));
            dtUriIchiran.Columns.Add(new DataColumn("得意先名", typeof(string)));
            dtUriIchiran.Columns.Add(new DataColumn("売上数量", typeof(decimal)));
            dtUriIchiran.Columns.Add(new DataColumn("売上金額", typeof(decimal)));

            var lnqIchiran = from drUri in dtUri.AsEnumerable()
                             join drTok in dtTok.AsEnumerable()
                             on drUri["得意先CD"] equals drTok["得意先CD"]
                             into tokGroup
                             from drTokEmpty in tokGroup.DefaultIfEmpty()
                             select new
                             {
                                 売上No = drUri["売上No"],
                                 売上日 = drUri["売上日"],
                                 得意先CD = drUri["得意先CD"],
                                 得意先名 = (drTokEmpty == null) ? "" : drTokEmpty["得意先名"],
                                 売上数量 = drUri["売上数量"],
                                 売上金額 = drUri["売上金額"]
                             };

            foreach (var lnqdr in lnqIchiran)
            {
                drIchiran = dtUriIchiran.NewRow();
                drIchiran["売上No"] = lnqdr.売上No;
                drIchiran["売上日"] = lnqdr.売上日;
                drIchiran["得意先CD"] = lnqdr.得意先CD;
                drIchiran["得意先名"] = lnqdr.得意先名;
                drIchiran["売上数量"] = lnqdr.売上数量;
                drIchiran["売上金額"] = lnqdr.売上金額;
                dtUriIchiran.Rows.Add(drIchiran);
            }

        }

===========

on句で結合するときに別の関数を間に挟んだりできるので結構便利

例)Private MaeZero(string Value,int Keta) As String   ->前ゼロ梅する関数


        Dim lnqIchiran = From drUri In dtUri.AsEnumerable
                         Group Join drTok In dtTok
                         On MaeZero(drUri("得意先CD"),5) Equals MaeZero(drTok("得意先CD"),5)
                         Into grp = Group
                         From drTokEmpty In grp.DefaultIfEmpty
                         Select New With {
                             .売上No = drUri("売上No"),
                             .売上日 = drUri("売上日"),
                             .得意先CD = drUri("得意先CD"),
                             .得意先名 = If(drTokEmpty("得意先名") Is Nothing, "", drTokEmpty("得意先名")),
                             .売上数量 = drUri("売上数量"),
                             .売上金額 = drUri("売上金額")
                             }

ただ、プロジェクト単位である程度書き方を統一しておかないとプログラマさんによっては書き方が全然違うので保守とか考えるときは注意したほうがいい。

みんなが知識ある人ばっかりだったらそんなに気にしなくてもいいかもしれないけど、開発の後半になって仕様変更とかで危なそうな個所を探すときにも書き方が一緒じゃないとGrepしても引っかからなかったりする。

パッと見でもわからないし・・・。

PowerShellでWPFアプリケーションをBindingするときの注意点

 1.PowerShellでWPFアプリケーションのBindingについて マニアックだけどPowerShellでWPFアプリケーションを作っている。INotifyChangedを実装したいけど、PowerShellにはgetterやsetterがないので通知が発行できない。 そ...