RunningCSharp

.net中心の開発話。記事は個人の見解であり、所属組織を代表するものてはありません。

VB(.net) Windows10 WinForms・DataGridViewのColumnHeaderのソートを示す三角だけ操作する

記のようなコードを実行した際、右側のカラムをクリックした際、ソートはされないがソートを示す三角形が「昇順→降順→ソートなし」の順に変化する。

コード

Imports System.ComponentModel

Public Class Form1
    'ソートの状態を保存する変数
    Dim sordOrder As SortOrder = SortOrder.None

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        '以下はDataGridViewのデータ表示用コード
        Dim table As DataTable = New DataTable()

        table.Columns.Add("col1")
        table.Columns.Add("col2")
        table.Rows.Add({1, 1})
        table.Rows.Add({2, 2})
        table.Rows.Add({4, 4})
        table.Rows.Add({3, 3})
        DataGridView1.DataSource = table

        '自動ソートを停止
        DataGridView1.Columns.Item(1).SortMode = DataGridViewColumnSortMode.Programmatic

    End Sub

    Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
        '右側のカラムでのみ、「ソートなし」処理を実装
        If e.ColumnIndex = 1 Then
            Dim vc As DataGridViewColumn = DataGridView1.Columns.Item(e.ColumnIndex)
            'すでにソート中であれば、次のソート状態を保持
            sordOrder = GetNextOrder(sordOrder)

            '※データの独自ソートを行いたい場合は、ここでデータのソートを実施


            'カラムヘッダーの矢印を現在のソート状態に合わせる
            vc.HeaderCell.SortGlyphDirection = sordOrder

        End If

    End Sub

    'ソート順を受け取り、次のソート順を返す
    Private Function GetNextOrder(sortOrder As SortOrder) As SortOrder
        Dim rtn As SortOrder
        Select Case sortOrder
            Case SortOrder.Ascending
                rtn = SortOrder.Descending
            Case SortOrder.Descending
                rtn = SortOrder.None
            Case SortOrder.None
                rtn = SortOrder.Ascending
        End Select
        Return rtn
    End Function

End Class

f:id:ys-soniclab:20190119215201p:plain
クリック一回目

f:id:ys-soniclab:20190119215217p:plain
クリック二回目

f:id:ys-soniclab:20190119215232p:plain
クリック三回目

VB(.net) Windows10 WinForms・DataGridViewのカラムクリック時、「昇順→降順→ソートなし」の順となるようカスタム

デフォルトのDataGridViewはカラムをクリックすると、「昇順→降順」の順にソートされる。 この挙動を、「昇順→降順→ソートなし」となるようカスタムする。 下記例では、右側のカラムのみカスタムが実装される。

Imports System.ComponentModel

Public Class Form1
    'ソートの状態を保存する変数
    Dim sordOrder As SortOrder = SortOrder.None

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        '以下はDataGridViewのデータ表示用コード
        Dim table As DataTable = New DataTable()

        table.Columns.Add("col1")
        table.Columns.Add("col2")
        table.Rows.Add({1, 1})
        table.Rows.Add({2, 2})
        table.Rows.Add({4, 4})
        table.Rows.Add({3, 3})
        DataGridView1.DataSource = table

    End Sub

    Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
        '右側のカラムでのみ、「ソートなし」処理を実装
        If e.ColumnIndex = 1 Then
            Dim vc As DataGridViewColumn = DataGridView1.Columns.Item(e.ColumnIndex)
            'すでにソート中であれば、次のソート状態を保持
            sordOrder = GetNextOrder(sordOrder)

            If sordOrder = SortOrder.None Then
                'ソート状態をリセット
                DataGridView1.DataSource.DefaultView.Sort = String.Empty
            Else
                'ソートを実行
                DataGridView1.Sort(vc, IIf(sordOrder = SortOrder.Ascending, ListSortDirection.Ascending, ListSortDirection.Descending))
            End If

        End If

    End Sub

    'ソート順を受け取り、次のソート順を返す
    Private Function GetNextOrder(sortOrder As SortOrder) As SortOrder
        Dim rtn As SortOrder
        Select Case sortOrder
            Case SortOrder.Ascending
                rtn = SortOrder.Descending
            Case SortOrder.Descending
                rtn = SortOrder.None
            Case SortOrder.None
                rtn = SortOrder.Ascending
        End Select
        Return rtn
    End Function

End Class

f:id:ys-soniclab:20190119214313p:plain
クリック一回目

f:id:ys-soniclab:20190119214333p:plain
クリック二回目

f:id:ys-soniclab:20190119214349p:plain
クリック三回目

VB(.net) Windows10 WinForms・DataGridViewのColumnHeaderのソートを示す三角が見えなくなる

下記のようなコードを実行した際、右側のカラムにて、ColumnHeaderのソート順を示す三角形が表示されなくなる。

コード

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        DataGridView1.ColumnHeadersHeight = 20

        DataGridView1.Columns.Add("col1", "1")
        DataGridView1.Columns.Add("col2", "2222222222")
        DataGridView1.Rows.Add({1, 3})
        DataGridView1.Rows.Add({2, 4})

       DataGridView1.Columns().Item(1).Width = 110

    End Sub
End Class

実行結果

f:id:ys-soniclab:20190103185521p:plain
左側カラムでソート実施

f:id:ys-soniclab:20190103185545p:plain
右側カラムでソート実施

2枚目のスクリーンショットでは、右側のカラムでソートを実施しているが、ヘッダーに三角形が表示されない。 本問題は、文字がカラムいっぱいに広がることで、ソートを示す三角形が消えてしまうことで発生する。 カラムを広げる調整を行うことで、問題を回避できる。

コード

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        DataGridView1.ColumnHeadersHeight = 20

        DataGridView1.Columns.Add("col1", "1")
        DataGridView1.Columns.Add("col2", "2222222222")
        DataGridView1.Rows.Add({1, 3})
        DataGridView1.Rows.Add({2, 4})

        '以下を追加
        DataGridView1.Columns().Item(1).Width = 110

    End Sub
End Class

実行結果

f:id:ys-soniclab:20190103190025p:plain
コード変更後

VB(.net) Windows10 WinFormsのDataGridViewのカスタム

本記事では、下記の方法をまとめて記載いたします。(挙動はWindows10にて確認済の内容となります)

①DataGridViewのヘッダー背景色変更

②DataGridViewのヘッダー文字色変更

③DataGridViewのヘッダー・項目それぞれのフォント変更

④DataGridViewのヘッダー・項目それぞれの文字の寄せ方変更

変更前のコードと画面は以下の通り。

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.Columns.Add("col1", "漢字1")
        DataGridView1.Columns.Add("col2", "漢字2")
        DataGridView1.Rows.Add({"漢字3", 3})
        DataGridView1.Rows.Add({"漢字4", 4})

    End Sub
End Class

f:id:ys-soniclab:20181231204739p:plain
変更前

変更用コードと変更後画面は以下の通り。

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.Columns.Add("col1", "漢字1")
        DataGridView1.Columns.Add("col2", "漢字2")
        DataGridView1.Rows.Add({"漢字3", 3})
        DataGridView1.Rows.Add({"漢字4", 4})

        '下記設定を行わないと、①と②の設定が反映されない
        DataGridView1.EnableHeadersVisualStyles = False

        '①DataGridViewのヘッダー背景色変更
        DataGridView1.Columns().Item(0).HeaderCell.Style.BackColor = Color.Red
        '②DataGridViewのヘッダー文字色変更
        DataGridView1.Columns().Item(1).HeaderCell.Style.ForeColor = Color.Green

        '③DataGridViewのヘッダー・項目それぞれのフォント変更
        'ヘッダーのフォント変更
        DataGridView1.Columns().Item(0).HeaderCell.Style.Font = New Font("MS 明朝", 8)
        DataGridView1.Columns().Item(1).HeaderCell.Style.Font = New Font("Meiryo UI", 15)
        '項目のフォント変更
        DataGridView1.Columns().Item(0).DefaultCellStyle.Font = New Font("MS ゴシック", 15)
        DataGridView1.Columns().Item(1).DefaultCellStyle.Font = New Font("MS P ゴシック", 8)

        '④DataGridViewのヘッダー・項目それぞれの文字の寄せ方変更
        'ヘッダーの寄せ方変更
        DataGridView1.Columns().Item(0).HeaderCell.Style.Alignment = DataGridViewContentAlignment.TopLeft
        DataGridView1.Columns().Item(1).HeaderCell.Style.Alignment = DataGridViewContentAlignment.BottomLeft

        '項目の寄せ方変更
        DataGridView1.Columns().Item(0).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
        DataGridView1.Columns().Item(1).DefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomRight

        'ヘッダーの高さ変更
        '下記のプロパティ変更を行わないと、ColumnHeadersHeightが正しく反映されない
        DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        DataGridView1.ColumnHeadersHeight = 100

    End Sub
End Class

f:id:ys-soniclab:20190103184425p:plain
変更後

VBでASP.net WebAPIを作る

ASP.net+VBでWebApiを作りたい。WebApiは呼ばれたらバッチを実行し、バッチ処理が完了した後にレスポンスを返してほしい。レスポンスは何でもよい。」とリクエストを受けたので、作ってみました。

WebApiの作り方は、下記の記事内容を引用させて頂きます。

blog.okazuki.jp

本記事は、ほとんど上記記事のコードをVBでやってみただけの記事になります。

プロジェクトを作る

空のASP.netプロジェクトを作成します。

f:id:ys-soniclab:20170204210936p:plain

NuGetで「Microsoft ASP.NET Web API 2 Web Host」を追加

f:id:ys-soniclab:20170204211017p:plain

本記事ではv5.2.3を利用しました。

Global.asaxの追加

プロジェクトを右クリックし、「追加」→「新しい項目を追加」を選択し、ダイアログで「Web」→「グローバル アプリケーション クラス」を選択。

f:id:ys-soniclab:20170204211129p:plain

作成された「Global.asax」を開き、下記のようにコードを追加します。

Imports System.Web.SessionState
'追加ここから
Imports System.Web.Http
'追加ここまで

Public Class Global_asax
    Inherits System.Web.HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' アプリケーションの起動時に呼び出されます
        '追加ここから
        GlobalConfiguration.Configure(
            Sub(config)
                config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}",
                                           New With {.id = RouteParameter.Optional})
            End Sub)
        '追加ここまで
    End SubEnd Class

ControllerフォルダとControllerクラスの追加

プロジェクトを右クリックし、「追加」→「新しいフォルダー」でフォルダを追加、名前を「Controller」に変更します。 「Controller」フォルダを右クリックし、「追加」→「クラス」でクラスを追加する、名前は「ExecBatchController」とします。

f:id:ys-soniclab:20170204212746p:plain

メソッドの実装

ExecBatchControllerを下記のように書き換えます。 なお、C#ではGetのWebAPIを作成する場合「Get」とするが、VBでは「Get」が予約語であるため、「GetValues」とします。

Imports System.Web.Http

Public Class ExecBatchController
    Inherits ApiController

    Public Function GetValues() As String

        'バッチを実行(test.batはtimeout 20を実行する)
        Dim p As System.Diagnostics.Process =
            System.Diagnostics.Process.Start("C:\\test\\test.bat")
        p.WaitForExit()
        '適当な値を返す
        Return "end process"
    End Function

End Class

実行

実行すると、ブラウザにはエラーが表示されるが、WebAPIは起動しています。

f:id:ys-soniclab:20170204214346p:plain

ブラウザのアドレスバーに「http://localhost:(ポートNo)/api/ExecBatch」と入力すると、バッチが実行されます。

f:id:ys-soniclab:20170204214326p:plain

バッチ終了後、"end process"と文字列が返されます。

f:id:ys-soniclab:20170204214747p:plain

C#で書いたラムダ式を用いたコードをVBで書き直してみる

.netのVBを使い慣れない私が、今度はラムダ式を使ったテストコード(コンソールアプリケーション)をC#で書いた後、そのコードVBに書き直してみただけの記事です。

C#

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //文字列を返すだけのFunc
            Func<string> func = () => "returnvalue";
            //数値を3倍にして文字列で返すFunc
            Func<int, string> func2 = (i) =>
            {
                i = i * 3;
                return i.ToString();
            };
            //引数をコンソールに表示するだけのAction
            Action<string,string> action = (str1,str2) => 
            {
                Console.WriteLine(str1);
                Console.WriteLine(str2);
            };
            //Actionを実行
            action(func(), func2(2));

            //下記コードはコンソール画面を表示しておくために追加
            Console.ReadLine();
        }
    }
}

上記処理をVB(Visual Studio 2015)で書き直してみます。

Module Module1
    Sub Main()
        '文字列を返すだけのFunc
        Dim func As Func(Of String) = Function() "returnstring"
        '数値を3倍にして文字列で返すFunc
        Dim func2 As Func(Of String, Integer) =
            Function(i)
                i = i * 3
                Return i.ToString()
            End Function
        '引数をコンソールに表示するだけのAction
        Dim action As Action(Of String, String) =
        Sub(str1, str2)
            Console.WriteLine(str1)
            Console.WriteLine(str2)
        End Sub
        'Actionを実行
        action(func(), func2(2))

        '下記コードはコンソール画面を表示しておくために追加
        Console.ReadLine()
    End Sub
End Module

処理結果はどちらも

returnstring

6

となります。

LinqGUIのイベントにと使い道は非常に多いので、VBでのラムダ式の書き方は押さえておくと便利そうと感じました。 とりあえず書き溜めて、そのうちQiitaとかで纏めようかと思います。

C#で書いたイテレーターを用いたコードをVBで書き直してみる

.netのVBを使い慣れない私が、今度はイテレーターを使ったテストコード(コンソールアプリケーション)をC#で書いた後、そのコードVBに書き直してみただけの記事です。

C#

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (string message in TestList())
            {
                Console.WriteLine(message);
            }
            //下記コードはコンソール画面を表示しておくために追加
            Console.ReadLine();
        }

        static IEnumerable<string> TestList()
        {
            yield return "I";
            yield return "have";
            yield return "a";
            yield return "pen";
        }
    }
}

上記処理をVB(Visual Studio 2015)で書き直してみます。

Module Module1

    Sub Main()
        For Each message In TestList()
            Console.WriteLine(message)
        Next
        '下記コードはコンソール画面を表示しておくために追加
        Console.ReadLine()
    End Sub

    Iterator Function TestList() As IEnumerable(Of String)
        Yield "I"
        Yield "have"
        Yield "a"
        Yield "pen"
    End Function

End Module

イテレーター自体はあまり多用しないので微妙ですが、ジェネリックの書き方の違いが見やすいかなと感じました。 とりあえず書き溜めて、そのうちQiitaとかで纏めようかと思います。