2013年5月21日 星期二

[學習] 四捨五入

[SQL]
select round(1.5446,2)
1.5400

select round(round(1.5446,3),2)
1.5500

select CAST(1.5446 AS decimal(9,2))
1.54

select CAST(1.546 AS decimal(9,2))
1.55

*資料型態decimal
  -生產數、工作分鐘 

統計數 =  Convert(Decimal(18,4) , 生產數 / 工作分鐘) * 60

[VB]
Module Module1
    Sub Main()
        Console.WriteLine((0.46).ToString("0"))
        'Console.WriteLine((1.45).ToString("0.0"))
        Console.WriteLine((0.5).ToString("0"))

        Console.WriteLine((0.46).ToString("f"))
        Console.WriteLine((0.5).ToString("f"))

        Console.WriteLine((4.625).ToString("0.00"))
        Console.WriteLine((4.645).ToString("0.00"))

        Console.WriteLine((4.625).ToString("f2"))
        Console.WriteLine((4.645).ToString("f2"))

        'Console.WriteLine((1.5).ToString("0"))
        Dim a As Double = 0.45
        Dim b As Decimal = 0.46
        'Dim c As Decimal = 4.625
        Console.WriteLine(Math.Round(a, 0, MidpointRounding.AwayFromZero))
        Console.WriteLine(Math.Round(b, 0, MidpointRounding.AwayFromZero))
        Console.WriteLine(Math.Round(4.625, 2, MidpointRounding.AwayFromZero))
        Console.WriteLine(Math.Round(CDec(4.645), 2, MidpointRounding.AwayFromZero))
        Console.Read()
    End Sub
End Module

-----------------

1. 整數以下四捨五入
     int(46410*0.05+0.5)=2321

2. 例 : 12.346 四捨五入至小數點以下一位
     int(12.346*10+0.5)/10=12.3

3. 例 : 12.346 四捨五入至小數點以下二位
     int(12.346*100+0.5)/100=12.35

參考:
浮點數計算結果更接近正解? 算錢用浮點,遲早被人扁

access中含四舍五入取值方法的查询sql语句
正確的四捨五入

[WIKI]數值簡化規則
C# Round (四捨五入) 使用 ToString()
利用VB.NET Format函数实现四舍五入功能
格式化输出-数字.ToString
c#中的常用ToString()方法总结
好用的string.Format或ToString()格式化字串的方法
[C#]簡單快速將各種數值字數轉成數字(string to int)
C#,double和decimal数据类型以截断的方式保留指定的小数位数

 '四捨五入
Public Function Round45(ByVal dblValue As Double) As Long
     Round45 = Fix(dblValue + 0.5 * Math.Sign(dblValue))
End Function

C#沒有四捨五入?只有五捨六入的涵數?
只要試試4.625與4.645兩個都對, 那才是真的對了

decimal 小數點位數 四捨五入
[C#]無條件進位,無條件捨去及四捨五入寫法

[ACCESS]單精準數運算Round取到小數位數問題
Round 函數

How To Implement Custom Rounding Procedures

2013年5月17日 星期五

[技巧] DataGridView 當 ReadOnly = True 則跳下一欄位... & 類似VBA的TabStop功能...


用途:
DataGridView 遇到 ReadOnly 則跳過... (不停留 StopTab) 加強版
當設置某些欄位設置 CellStop ,則按 Enter/Tab 時直接跳過
但當用滑鼠點選時依然可以編輯,因為其 ReadOnly = False
粉紅標記

程式:
   Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        '當按enter鍵時 執行tab鍵 -> 實現換行 '不過若是button鍵 就不能tab喔 應該是要Enter事件
        If keyData = Keys.Enter Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                    Return SelectNextCell() 
            End If
        End If

        If keyData = Keys.Tab Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                    Return SelectNextCell() 
            End If
        End If

        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function

    Public Function SelectNextCell() As Boolean
        Dim row As Integer = DataGridView1.CurrentCell.RowIndex
        Dim column As Integer = DataGridView1.CurrentCell.ColumnIndex
        Dim startingCell As DataGridViewCell = DataGridView1.CurrentCell

        Do
            column += 1
            If column = DataGridView1.Columns.Count Then
                column = 0
                row += 1
            End If
            If row = DataGridView1.Rows.Count Then
                row = 0
            End If
         Loop While (CellStop.IndexOf(DataGridView1.Columns(column).Name) <> -1 _
                    OrElse DataGridView1.Columns(column).Visible = False OrElse DataGridView1(column, row).ReadOnly = True) AndAlso DataGridView1(column, row) IsNot startingCell

        If DataGridView1(column, row) Is startingCell Then
            Return False
        End If
        DataGridView1.CurrentCell = DataGridView1(column, row)
        Return True
    End Function

Dim CellStop As New ArrayList()
Private Sub DataGridView1_SelectionChanged(ByVal sender As Object, ByVal e As
        Me.CellStop.Clear()
        If Me.DataGridView1.CurrentRow.Cells("產品編號").Value.ToString.Split("-")(0) = "0" Then
            Me.CellStop.Add("牌價編號")
            Me.CellStop.Remove("尺寸規格名稱")
            Me.CellStop.Remove("材質全名")
        Else
            Me.CellStop.Remove("牌價編號")
            Me.CellStop.Add("尺寸規格名稱")
            Me.CellStop.Add("材質全名")
        End If
End Sub

=========================
備註:
1.
紫色標記處,為避免發生 "無法將目前的儲存格設定為不可見的儲存格" 的錯誤。

 2.
DataGridView 覆寫 ProcessDialogKey 及 ProcessDataGridViewKey 並成一個元件。
黃色標記部份,是為了防止在編輯狀態下鍵入 Tab(Right / Left) 鍵 ,
避免在 ComBoBoxCell 時,在選擇期間鍵入此三鍵,而產生最左邊的RowHead
其三角形變成(並一直處於)編輯狀態(筆的形狀)...


Public Class mydgv
    Inherits DataGridView
    <System.Security.Permissions.UIPermission( _
        System.Security.Permissions.SecurityAction.LinkDemand, _
        Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _
    Protected Overrides Function ProcessDialogKey( _
        ByVal keyData As Keys) As Boolean

        ' Extract the key code from the key value.
        Dim key As Keys = keyData And Keys.KeyCode

        ' Handle the ENTER key as if it were a RIGHT ARROW key.
        If key = Keys.Enter Then
            Return Me.ProcessRightKey(keyData)
        End If

        If (key = Keys.Tab) AndAlso CurrentCell.IsInEditMode Then
            Return False
        End If

        Return MyBase.ProcessDialogKey(keyData)
    End Function

    <System.Security.Permissions.SecurityPermission( _
        System.Security.Permissions.SecurityAction.LinkDemand, Flags:= _
        System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)> _
    Protected Overrides Function ProcessDataGridViewKey( _
        ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean

        ' Handle the ENTER key as if it were a RIGHT ARROW key.
        If e.KeyCode = Keys.Enter Then
            Return Me.ProcessRightKey(e.KeyData)
        End If

        If (e.KeyCode = Keys.Left OrElse e.KeyCode = Keys.Right) AndAlso CurrentCell.IsInEditMode Then
            Return False
        End If

        Return MyBase.ProcessDataGridViewKey(e)
    End Function
End Class

[C#]
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace System.Windows.Forms
{
  class MyDataGridView : DataGridView
  {
    protected override bool ProcessDialogKey(Keys keyData)
    {
      if (keyData == Keys.Enter || keyData == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDialogKey(keyData);
    }

    protected override bool ProcessDataGridViewKey(KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDataGridViewKey(e);
    }

    protected bool MyProcessTabKey(Keys keyData)
    {
      bool retValue = base.ProcessTabKey(Keys.Tab);
      while (this.CurrentCell.ReadOnly)
      {
        retValue = base.ProcessTabKey(Keys.Tab);
      }
      return retValue;
    }
  }
}

參考:
鍵盤輸入的運作方式
DataGridView.ProcessDialogKey 方法
DataGridView.ProcessDataGridViewKey 方法
Control.SelectNextControl 方法
Control.GetNextControl 方法

DataGridView 编辑回车事件
跳到某一格...
.Net 2.0 DataGridView中键盘事件处理方法
DataGridView检查当前单元格是否处于编辑状态
Bypass read only cells in DataGridView when pressing TAB key
C# Enter轉Tab,讓MultiLine可換行
Up/Down - Arrow function
WM_KEYDOWN message
DataGridView 控制項 (Windows Form)

[C#]DataGridViewのCell移動をEnterで
DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする
svn/ trunk/ ExtControls/ 測試專案/ MyDataGridview.cs
Bypass read only cells in DatagridView when pressing TAB key (good)
关于DataGridView中键盘输入时的单元格跳转
svn/ trunk/ PT.Component/ DataGridView.cs
C#的dataGridView控件實現回車右移控制
ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格

How catch Enter Key on EndEdit of Datagridview
DataGridView.ProcessDataGridViewKey 方法

2013年5月6日 星期一

[技巧] DataGridViewComboBoxColumn 資料繫結(數據綁定) 驗證(判斷)值是否為繫結內的值 + 可手動輸入(自動篩選)

簡述:
DataGridViewComboBoxColumn 來源為資料庫dt (OR 自定義的DataTable)


Dim columnProvider As New DataGridViewComboBoxColumn()
        columnProvider.HeaderText = "供應商"
        columnProvider.Name = "供應商"
        columnProvider.DataPropertyName = "供應商編號"
        Dim graphics = CreateGraphics()

        columnProvider.DropDownWidth = (From width In (From item As DataRow In dt供應商.Rows _
                                                  Select Convert.ToInt32(graphics.MeasureString(item("供應商簡稱").ToString, Font).Width)) _
                                                  Select width).Max

        columnProvider.DataSource = dt供應商
        columnProvider.DisplayMember = "供應商簡稱"
        columnProvider.ValueMember = "供應商編號"


目的:
讓使用者可透過 "以下" 來篩選資料,但不可以為繫結資料外的值!


Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing


     If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
            CType(e.Control, ComboBox).DropDownStyle = ComboBoxStyle.DropDown
            CType(e.Control, ComboBox).AutoCompleteSource = AutoCompleteSource.ListItems
            CType(e.Control, ComboBox).AutoCompleteMode = AutoCompleteMode.SuggestAppend

     End If
End Sub


程式: 因為想要把"需要判斷欄位"寫在同一個Sub,因此依這個來解決比較好閱讀!

    Private Sub DataGridView1_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
        If DataGridView1.Columns(e.ColumnIndex).ReadOnly = True Then
            Exit Sub
        End If

        Dim grid As DataGridView = CType(sender, DataGridView)
        grid.Rows(e.RowIndex).ErrorText = ""

        If grid.Columns(e.ColumnIndex).Name = "供應商" Then
            '判斷是否為dt供應商內的值
            Dim num As Integer = 0
            For Each dr As DataRow In dt供應商.Rows
                If grid.Rows(e.RowIndex).Cells("供應商").EditedFormattedValue.ToString.Trim = dr("供應商簡稱").ToString.Trim Then
                    'MsgBox(dr("供應商簡稱").ToString.Trim)
                    num += 1
                    Exit For
                End If
            Next

            If num = 0 Then

                DataGridView1.Rows(e.RowIndex).ErrorText = _
                "不允許自行輸入, 請重新選擇!!"

                MsgBox("不允許自行輸入, 請重新選擇!!")
                e.Cancel = True
            End If
        End If
    End Sub

另解(1):  透過 CType(sender, ComboBox).SelectedIndex(SelectedItem/SelectedText,etc...) 來判斷!
DataGridViewComboBoxColumn 實現 SelectedIndexChanged 事件
How to get the valuemember from a DataGridViewComboBoxCell
Getting the Selected Value of Combo Box in DataGridView

另解(2):
System.ArgumentException:DataGridViewComboBoxCell 值無效 (2) 解決(二)


參考:
DataGridViewComboBoxCell.GetFormattedValue 方法
get value of combobox columns valuemember's value in DataGridView
實作 DataGridViewDropDownColumn
datagridview的combobox控件的添加
真正的DataGridViewComboBoxColumn
DataGridView 控制項 (Windows Form)

DataGridViewComboBoxColumn 可以让用户输入并自动匹配的选项的问题
你指定了ComboBox的DisplayMember和ValueMember后,会按你输入的ValueMember来匹配的,如果输入的如果你说的管理员,它在valueMember中不存在,所以不会选中.这样的话和你设置的就矛盾了,所以应该换种思路,不一定要用comboBox,可以把当前编辑的当元格转换成TextBox,然后在TextBoxChanged里面写,至于下拉列表可以用一个listview来显示,只要把它显示在TextBox的下端坐标值即可.那样根据输入的值,listview自动找匹配的供用户自己选择

ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格
(讓ComboBoxColumn在下拉選項時, 解決出現二種模式...)

2013年5月2日 星期四

[除錯] 並未將物件參考設定為物件的執行個體 DataGridViewComboBox [debug]

錯誤:
DataGridViewComboBox
並未將物件參考設定為物件的執行個體

程式:

            For Each dgvr As DataGridViewRow In DataGridView1.Rows
                'If dgvr.Index = DataGridView1.RowCount - 1 Then
                '    Exit For
                'End If
                'If dgvr.IsNewRow Then
                '    MsgBox("HAHA")
                '    Exit For
                'End If
                MsgBox(dgvr.Cells("供應商").Value.ToString.Trim)
            Next

解決:
因為 AllowUserToAddRows = True
所以 DGV 會自動 NewRow 出來

而 NewRow 在 for-loop 裡也會算作一份(index)
但實質上是 Nothing 的資料型態
當 loop 到 NewRow 時,便會發生如圖的錯誤

因此在 for-loop 時,要排除掉
可利用黃色方法或綠色方法

DataGridView 控制項 (Windows Form)