Monorepo/Controls.LookupGrid/frmLookupGrid.vb

285 lines
10 KiB
VB.net

Imports System.Windows.Forms
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraGrid.Views.Base
Imports DevExpress.XtraGrid.Views.Grid
Public Class frmLookupGrid
Public Property MultiSelect As Boolean
Public Property AddNewValues As Boolean
Public Property PreventDuplicates As Boolean
Public Property DataSource As DataTable
Public Property SelectedValues As List(Of String)
Public Property NewValues As New HashSet(Of String)
Public Const COLUMN_SELECTED = "SELECTED"
Public Const COLUMN_VALUE = "VALUE"
Public Const TABLE_TEMP = "TEMP"
Private _DataColumn As Integer
Private _DataSourceTemp As DataTable
Private _View As GridView
Private _Grid As GridControl
Private ReadOnly _R As Resources.ResourceManager = My.Resources.Strings.ResourceManager
#Region "Form Events"
Private Sub frmLookupGrid_Load(sender As Object, e As EventArgs) Handles Me.Load
_View = viewLookup
_Grid = gridLookup
' Original Datasource soll nicht verändert werden
If DataSource Is Nothing Then
_DataSourceTemp = New DataTable(TABLE_TEMP)
_DataSourceTemp.Columns.Add(New DataColumn(COLUMN_VALUE))
Else
_DataSourceTemp = DataSource.Copy()
End If
If MultiSelect Then
If Not _DataSourceTemp.Columns.Contains(COLUMN_SELECTED) Then
Dim oSelectedColumn = New DataColumn() With {
.ColumnName = COLUMN_SELECTED,
.DataType = GetType(Boolean),
.DefaultValue = False
}
_DataSourceTemp.Columns.Add(oSelectedColumn)
oSelectedColumn.SetOrdinal(0)
End If
End If
' Datasource setzen
_Grid.DataSource = _DataSourceTemp
' Anzeige Eigeschaften setzen
_View.OptionsFind.Condition = DevExpress.Data.Filtering.FilterCondition.Contains
_View.OptionsFind.AlwaysVisible = True
_View.OptionsSelection.MultiSelect = False
If MultiSelect Then
' Selected Spalte anpassen
Dim oCheckboxColumn = _View.Columns.Item(0)
'oCheckboxColumn.Visible = False
oCheckboxColumn.Caption = " "
oCheckboxColumn.MaxWidth = 30
oCheckboxColumn.MinWidth = 30
oCheckboxColumn.OptionsColumn.AllowFocus = False
Text = _R.GetString("PopupForm_Text")
_DataColumn = 1
Else
Text = _R.GetString("PopupForm_TextMultiLine")
_DataColumn = 0
End If
If AddNewValues Then
_View.OptionsBehavior.AllowAddRows = DevExpress.Utils.DefaultBoolean.True
_View.OptionsView.NewItemRowPosition = NewItemRowPosition.Top
Else
_View.OptionsBehavior.AllowAddRows = DevExpress.Utils.DefaultBoolean.False
_View.OptionsView.NewItemRowPosition = NewItemRowPosition.None
End If
If SelectedValues Is Nothing Then
SelectedValues = New List(Of String)
Else
SelectedValues = SelectedValues.Where(Function(v) Not (IsDBNull(v) OrElse String.IsNullOrWhiteSpace(v))).ToList()
End If
' Bereits ausgewählte Werte im grid auswählen
SyncItemsWithView(_View)
' Focus auf Find panel setzen
_View.ShowFindPanel()
' Spaltenbreite anpassen
_View.BestFitColumns()
' Datenspalte zusätzlich in der Breite anpassen
Dim oDataColumn As GridColumn = _View.Columns.Item(_DataColumn)
oDataColumn.BestFit()
End Sub
Private Sub frmLookupGrid_Shown(sender As Object, e As EventArgs) Handles Me.Shown
BringToFront()
End Sub
#End Region
#Region "Button Events"
Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
SaveSelectedValues()
DialogResult = DialogResult.OK
Close()
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
SelectedValues = New List(Of String)
DialogResult = DialogResult.OK
Close()
End Sub
#End Region
#Region "Grid Events"
Private Sub gridLookup_KeyUp(sender As Object, e As KeyEventArgs) Handles gridLookup.KeyUp
HandleCustomKeys(e)
End Sub
Private Sub gridLookup_EditorKeyUp(sender As Object, e As KeyEventArgs) Handles gridLookup.EditorKeyUp
HandleCustomKeys(e)
End Sub
Private Sub HandleCustomKeys(e As KeyEventArgs)
If e.KeyCode = Keys.Escape Then
Close()
ElseIf e.KeyCode = Keys.F2 Then
' Make sure the currently focused row's state is saved
viewLookup.PostEditor()
SaveSelectedValues()
DialogResult = DialogResult.OK
Close()
End If
End Sub
#End Region
#Region "View Events"
Private Sub viewLookup_ShowingEditor(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles viewLookup.ShowingEditor
Dim rowHandleIsNewItemRow = (_View.FocusedRowHandle = GridControl.NewItemRowHandle)
Dim columnIsCheckboxColumn = (_View.FocusedColumn.FieldName = COLUMN_SELECTED)
' Prevent editing of Data Column/allow editing for Checkbox Column and NewValue Row
If rowHandleIsNewItemRow Or columnIsCheckboxColumn Then
e.Cancel = False
Else
e.Cancel = True
End If
End Sub
Private Sub viewLookup_RowClick(sender As Object, e As RowClickEventArgs) Handles viewLookup.RowClick
' If user double-clicks on a row
If e.Clicks = 2 And e.Button = MouseButtons.Left Then
' And clicked row is a normal row
If e.RowHandle >= 0 Then
' If multiselect is true, check the current row
' If multiselect is false, select the current row and close the window
If MultiSelect = True Then
Dim row As DataRow = _View.GetDataRow(e.RowHandle)
row.Item(0) = Not CBool(row.Item(0))
Else
Dim row As DataRow = _View.GetDataRow(e.RowHandle)
Dim value = row.Item(0)
SelectedValues = New List(Of String) From {value}
DialogResult = DialogResult.OK
Close()
End If
End If
End If
End Sub
Private Sub viewLookup_ValidateRow(sender As Object, e As ValidateRowEventArgs) Handles viewLookup.ValidateRow
If e.RowHandle = GridControl.NewItemRowHandle Then
Dim oRowView As DataRowView = viewLookup.GetRow(e.RowHandle)
Dim oValue = GetValueFromRow(oRowView.Row)
NewValues.Add(oValue)
' Automatically select newly added row when MultiSelect is enabled
If MultiSelect Then
oRowView.Row.Item(COLUMN_SELECTED) = True
End If
End If
End Sub
Private Sub viewLookup_RowCellClick(sender As Object, e As RowCellClickEventArgs) Handles viewLookup.RowCellClick
If e.RowHandle = GridControl.InvalidRowHandle Or e.RowHandle = GridControl.NewItemRowHandle Then
e.Handled = False
Exit Sub
End If
' When AllowFocus is used on the SELECTED Column, the checkbox can only be selected with a double click
' This function manually checks/unchecks the clicked cell
If MultiSelect AndAlso e.Column.FieldName = COLUMN_SELECTED Then
Dim row As DataRow = _View.GetDataRow(e.RowHandle)
row.Item(0) = Not CBool(row.Item(0))
End If
End Sub
Private Sub viewLookup_FocusedRowChanged(sender As Object, e As FocusedRowChangedEventArgs) Handles viewLookup.FocusedRowChanged
' Removed because it leads to some weird behaviour where you a locked in the new row forever
'If AddNewValues AndAlso e.PrevFocusedRowHandle = GridControl.NewItemRowHandle Then
' BeginInvoke(Sub() viewLookup.FocusedRowHandle = GridControl.NewItemRowHandle)
'End If
End Sub
#End Region
Private Sub SaveSelectedValues()
' Filter vor dem Auslesen entfernen, damit alle Werte erfasst werden
_View.FindFilterText = String.Empty
If MultiSelect Then
Dim oValues As New List(Of String)
For oIndex = 0 To viewLookup.DataRowCount - 1
Dim oRow As DataRow = _View.GetDataRow(oIndex)
Dim oSelected As Boolean = oRow.Item(0)
Dim oValue As Object = GetValueFromRow(oRow)
If oSelected Then
oValues.Add(oValue)
End If
Next
' Doppelte Werte entfernen, wenn konfiguriert
If PreventDuplicates Then
oValues = oValues.Distinct().ToList()
End If
SelectedValues = oValues
Else
Dim oRowHandle As Integer = _View.GetSelectedRows().ToList().FirstOrDefault()
Dim oRow As DataRow = _View.GetDataRow(oRowHandle)
Dim oValues As New List(Of String)
If oRow IsNot Nothing Then
Dim oValue = GetValueFromRow(oRow)
oValues.Add(oValue)
End If
SelectedValues = oValues
End If
End Sub
Private Function GetValueFromRow(pRow As DataRow) As String
' Converting to string explicitly to prevent DBNull crashing the function
If MultiSelect Then
Return pRow.Item(1).ToString()
Else
Return pRow.Item(0).ToString()
End If
End Function
Private Sub SyncItemsWithView(view As GridView)
' Wenn Vorbelegungen existieren, werden diese angehakt
If SelectedValues.Count > 0 Then
For i = 0 To view.DataRowCount - 1
Dim rowHandle = view.GetRowHandle(i)
Dim rowView As DataRowView = view.GetRow(rowHandle)
If rowView IsNot Nothing Then
Dim row As DataRow = rowView.Row
Dim value = row.Item(_DataColumn)
If Not (IsDBNull(value) OrElse String.IsNullOrWhiteSpace(value)) Then
If SelectedValues.Contains(value) Then
If MultiSelect Then
row.Item(0) = True
Else
view.SelectRow(rowHandle)
End If
End If
End If
End If
Next
End If
End Sub
End Class