Since three is read only and depends on a non property (four). Three should be undefined.
How does props, which does not set four, set three to the correct value?
public sub main
Dim x1 = New one, x2 = New two
x1.one = 3
MoveCorresponding(x1, x2)
end sub
Public Sub MoveCorresponding(a As Object, b As Object, Optional ignoreList As List(Of String) = Nothing)
Dim oType As Type = b.GetType
Dim iType = a.GetType
Dim props = iType.GetProperties()
For Each pInf As PropertyInfo In props
Dim parName = pInf.Name
If pInf.CanWrite Then
Try
Dim val = pInf.GetValue(a, Nothing)
pInf.SetValue(b, val)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
Next
End Sub
End Class
Class one
Public Property one As String = "1"
Dim four As Integer = 1
Public ReadOnly Property three As Integer
Get
Return four * 10
End Get
End Property
End Class
You set four on the same line that you declare it:
Dim four As Integer = 1 '<-- see? it's set to "1".
The property three is simply computed from four:
Return four * 10
Am I not understanding your question?
Related
I'm populating a DataGridView from an Excel file, and trying to sort only ONE column of my choice, other columns should remain as-is. How can it be achieved? Should the component be changed to something else, in case it is not possible in DataGridView?
I Created a List of my custom class, and this class will handle the sorting based on my preference (Randomization in this case)
Public Class Mylist
Implements IComparable(Of Mylist)
Private p_name As String
Private r_id As Integer
Public Property Pname() As String 'This will hold the contents of DGV that I want sorted
Get
Return p_name
End Get
Set(value As String)
p_name = value
End Set
End Property
Public Property Rid() As Integer 'This will be the basis of sort
Get
Return r_id
End Get
Set(value As Integer)
r_id = value
End Set
End Property
Private Function IComparable_CompareTo(other As Mylist) As Integer Implements IComparable(Of Mylist).CompareTo
If other Is Nothing Then
Return 1
Else
Return Me.Rid.CompareTo(other.Rid)
End If
End Function
End Class
Then a Button which will sort the contents:
Dim selcol = xlView.CurrentCell.ColumnIndex
Dim rand = New Random()
Dim x As Integer = 0
Dim plist As New List(Of Mylist)
Do While x < xlView.Rows.Count
plist.Add(New Mylist() With {
.Pname = xlView.Rows(x).Cells(selcol).Value,
.Rid = rand.Next()
})
x += 1
Loop
plist.Sort()
x = 0
Do While x < xlView.Rows.Count
xlView.Rows(x).Cells(selcol).Value = plist.ElementAt(x).Pname
x += 1
Loop
xlView.Update()
plist.Clear()
I'm open to any changes to code, as long as it achieves the same result.
Here is the simpler version. Pass the column index will do like Call SortSingleColum(0)
Private Sub SortSingleColumn(x As Integer)
Dim DataCollection As New List(Of String)
For i = 0 To dgvImport.RowCount - 2
DataCollection.Add(dgvImport.Item(x, i).Value)
Next
Dim t As Integer = 0
For Each item As String In DataCollection.OrderBy(Function(z) z.ToString)
dgvImport.Item(x, t).Value = item
t = t + 1
Next
End Sub
I have trouble rounding some cells from my datatable.
I want this round to 2 decimal places, as you can imagine. I will explain quickly how I charge data to the DataTable :
I have this function stored in a class:
Protected Friend Function cargarPref(ByVal id_Pref As String) As DataTable
Dim cmd As String = "Select Material,Cubicaje,SubTotal,ITBM,Total from Preferencia WHERE Id_Preferencia=#id_Pref"
Dim t As New DataTable
Try
con.Open()
comando = New OleDbCommand(cmd, con)
comando.Parameters.AddWithValue("#id_Pref", id_Pref)
adapter = New OleDbDataAdapter(comando)
adapter.Fill(t)
comando.Dispose()
adapter.Dispose()
con.Close()
Catch ex As Exception
MsgBox("Error en la consulta: " + ex.Message, MsgBoxStyle.Critical)
End Try
Return t
End Function
Ok, now I call it in my windows form:
Private Sub DataCliente_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataCliente.CellContentClick
If (Not IsNothing(DataMate)) Then
DataMate.DataSource = Nothing
mt.Clear()
End If
Dim index As Integer = 0
If (DataCliente.Columns(DataCliente.CurrentCell.ColumnIndex).Name.Equals("Empresa")) Then
index = Me.DataCliente.CurrentRow.Index
lblid.Text = DataCliente.Rows(index).Cells("Id_Cliente").Value
lblempresa.Text = DataCliente.Rows(index).Cells("Empresa").Value
lbldirecc.Text = DataCliente.Rows(index).Cells("Direccion").Value
lblcorreo.Text = DataCliente.Rows(index).Cells("Correo").Value
lbltel.Text = DataCliente.Rows(index).Cells("Telefono").Value
lblpreyd.Text = Math.Round(CDbl(DataCliente.Rows(index).Cells("PrecioYD").Value), 2).ToString("N2")
End If
mt = data.cargarPref(DataCliente.Rows(index).Cells("Id_Preferencia").Value) <--HERE!!!
DataMate.DataSource = mt
PanelMaterial.Enabled = True
End Sub
Now, watch as my values are in my database access, Along With the datagrid of the program!
For some strange reason ... the data I have taken from the database , the program treats them as if they were integers.
How I can then round off those values that are within the datatable, before printing in datagridview?
I finally discovered a solution , and I am going to show you how to solve this problem, if you need it (Before you do this , you must define all the columns you want to see on your datagridview !):
First, I create a class with public properties:
Public Class Preferencia
Public Property Material() As String
Public Property Cubicaje() As String
Public Property SubTotal() As String
Public Property ITBM() As String
Public Property Total() As String
End Class
Second , I create 2 functions and one procedural method :
Private Function setPreferencia(ByVal material As String, ByVal cubicaje As String, ByVal subtotal As String, ByVal itbm As String, ByVal total As String) As Preferencia
Dim item As New Preferencia
item.Material = material
item.Cubicaje = FormatNumber(cubicaje, 2)
item.SubTotal = FormatNumber(subtotal, 2)
item.ITBM = FormatNumber(itbm, 2)
item.Total = FormatNumber(total, 2)
Return item
End Function
Private Function registrarPreferencia() As List(Of Preferencia)
Dim lista As New List(Of Preferencia)
For Each itm In mt.Rows
lista.Add(setPreferencia(itm(0), itm(1), itm(2), itm(3), itm(4)))
Next
Return lista
Protected Friend Sub FillGrid()
DataMate.AutoGenerateColumns = False
DataMate.DataSource = registrarPreferencia()
DataMate.Columns("Material").DataPropertyName = "Material"
DataMate.Columns("Cubicaje").DataPropertyName = "Cubicaje"
DataMate.Columns("SubTotal").DataPropertyName = "SubTotal"
DataMate.Columns("ITBM").DataPropertyName = "ITBM"
DataMate.Columns("Total").DataPropertyName = "Total"
End Sub
Now the only thing is to call the method " FillGrid ()" when you want to print the data. And finaly, I resolved it!
I'm having an issue in VBA where every item in the array is being replaced every time i add something to that array.
I am attempting to go through the rows in a given range and cast every row of that into a custom class (named 'CustomRow' in below example). there is also a manager class (called 'CustomRow_Manager' below) which contains an array of rows and has a function to add new rows.
When the first row is added it works fine:
https://drive.google.com/file/d/0B6b_N7sDgjmvTmx4NDN3cmtYeGs/view?usp=sharing
however when it loops around to the second row it replaces the contents of the first row as well as add a second entry:
https://drive.google.com/file/d/0B6b_N7sDgjmvNXNLM3FCNUR0VHc/view?usp=sharing
Any ideas on how this can be solved?
I've created a bit of code which shows the issue, watch the 'rowArray' variable in the 'CustomRow_Manager' class
Macro file
https://drive.google.com/file/d/0B6b_N7sDgjmvUXYwNG5YdkoySHc/view?usp=sharing
otherwise code is below:
Data
A B C
1 X1 X2 X3
2 xx11 xx12 xx13
3 xx21 xx22 xx23
4 xx31 xx32 xx33
Module "Module1"
Public Sub Start()
Dim cusRng As Range, row As Range
Set cusRng = Range("A1:C4")
Dim manager As New CustomRow_Manager
Dim index As Integer
index = 0
For Each row In cusRng.Rows
Dim cusR As New CustomRow
Call cusR.SetData(row, index)
Call manager.AddRow(cusR)
index = index + 1
Next row
End Sub
Class module "CustomRow"
Dim iOne As String
Dim itwo As String
Dim ithree As String
Dim irowNum As Integer
Public Property Get One() As String
One = iOne
End Property
Public Property Let One(Value As String)
iOne = Value
End Property
Public Property Get Two() As String
Two = itwo
End Property
Public Property Let Two(Value As String)
itwo = Value
End Property
Public Property Get Three() As String
Three = ithree
End Property
Public Property Let Three(Value As String)
ithree = Value
End Property
Public Property Get RowNum() As Integer
RowNum = irowNum
End Property
Public Property Let RowNum(Value As Integer)
irowNum = Value
End Property
Public Function SetData(row As Range, i As Integer)
One = row.Cells(1, 1).Text
Two = row.Cells(1, 2).Text
Three = row.Cells(1, 3).Text
RowNum = i
End Function
Class module "CustomRow_Manager"
Dim rowArray(4) As New CustomRow
Dim totalRow As Integer
Public Function AddRow(r As CustomRow)
Set rowArray(totalRow) = r
If totalRow > 1 Then
MsgBox rowArray(totalRow).One & rowArray(totalRow - 1).One
End If
totalRow = totalRow + 1
End Function
Your issue is using
Dim cusR As New CustomRow
inside the For loop. This line is actually only executed once (note that when you single F8 step through the code it does not stop on that line)
Each itteration of the For loop uses the same instance of cusR. Therefore all instances of manager added to the class point to the same cusR
Replace this
For Each row In cusRng.Rows
Dim cusR As New CustomRow
with this
Dim cusR As CustomRow
For Each row In cusRng.Rows
Set cusR = New CustomRow
This explicitly instantiates a new instance of the class
I'm trying to initialize a class using a DataRow, But when the DataRow item "LOCATION" is a Null value I receive an error. How can I load these variables with their appropriate datatype values when the row item is null?
Public Sub New(ByVal row As DataRow)
intID = row.Item("ID")
strDepartmentCode = row.Item("DEPARTMENT_CODE")
strDepartmentName = row.Item("DEPARTMENT_NAME")
intLocation = row.Item("LOCATION")
End Sub
Something like this:
Dim location As Object = row.Item("LOCATION")
If location Is Convert.DBNull
intLocation = -1
Else
intLocation = Convert.ToInt32(location)
End If
I've done some Googling but can't find anything concrete enough to go forward with, so here I am.
I have date fields that I am running a WHERE clause against, and returning fields based on that. The date fields are encrypted, so I was forced to take an alternative approach.
Dim aEmpList(dt.Rows.Count, 5) As String
Try
lCount = 0
For i As Integer = 0 To dt.Rows.Count - 1
If clsEncrypt.DecryptData(dt.Rows(i)(3)) >= 19500101 Then
aEmpList(lCount, 0) = clsEncrypt.DecryptData(dt.Rows(i)(0))
aEmpList(lCount, 1) = clsEncrypt.DecryptData(dt.Rows(i)(1))
aEmpList(lCount, 2) = clsEncrypt.DecryptData(dt.Rows(i)(2))
aEmpList(lCount, 3) = clsEncrypt.DecryptData(dt.Rows(i)(3))
aEmpList(lCount, 4) = clsEncrypt.DecryptData(dt.Rows(i)(4))
lCount = lCount + 1
End If
Next
Catch ex As Exception
MessageBox.Show(e.ToString())
End Try
clsEncrypt is an encryption/decryption class.
The fields are Employee First Name, Last Name, and Date of Birth - and they are all encrypted.
I am trying to find all Employees born>= 19500101, and return that data as a report.
I created a Structure and put the data as an array into the structure myStructure
'Define a structure to be used as source for data grid view.
Structure mystructure
Private mDim1 As String
Private mDim2 As String
Private mDim3 As String
Private mDim4 As String
Private mDim5 As String
Public Property Dim1() As String
Get
Return mDim1
End Get
Set(ByVal value As String)
mDim1 = value
End Set
End Property
Public Property Dim2() As String
Get
Return mDim2
End Get
Set(ByVal value As String)
mDim2 = value
End Set
End Property
Public Property Dim3() As String
Get
Return mDim3
End Get
Set(ByVal value As String)
mDim3 = value
End Set
End Property
Public Property Dim4() As String
Get
Return mDim4
End Get
Set(ByVal value As String)
mDim4 = value
End Set
End Property
Public Property Dim5() As String
Get
Return mDim5
End Get
Set(ByVal value As String)
mDim5 = value
End Set
End Property
End Structure
I populate the structure to load into a DataGridView for visualization purposes:
'populate structure with aEmpList array
Dim myarr(dt.Rows.Count) As mystructure
Try
For i As Integer = 0 To lCount - 1
myarr(i) = New mystructure With {.Dim1 = aEmpList(i, 0).ToString, .Dim2 = aEmpList(i, 1).ToString, .Dim3 = aEmpList(i, 2).ToString, .Dim4 = aEmpList(i, 3).ToString, .Dim5 = aEmpList(i, 4).ToString}
Next
Catch ex As Exception
MessageBox.Show(e.ToString())
End Try
DataGridView1.DataSource = myarr
Now that I've provided sufficient background, does anyone know what my next move should be?
I'm not sure how, or if, I should load the structure into a DataSet() [if that's even possible] or something of that nature.
As I see it you're trying to create a business class, and thus should use a reference type (Class) instead of a value type (Structure). So, the "next move" would be to change your structure to a class, implement INotifyPropertyChanged, IEditableObject, IChangeTracking, IRevertibleChangeTracking, and create a BindingList(Of T) to hold your items.
So, this kind of sucked to figure out, but I got it. As the question title says - I actually ditched the array portion because all it did was confuse me, and I went with the following solution:
Dim dt As New DataTable
Dim dts As DataSet = New DataSet()
With comm
.CommandText = "SELECT EMPL_ID, EMPL_FIRST_NM, EMPL_LAST_NM, BEG_DT, END_DT FROM EMPL"
End With
Dim adapter As New SqlDataAdapter(comm)
adapter.Fill(dts) 'Fill DT with Query results
dt.Load(dts.CreateDataReader())
Me.reportViewer1.RefreshReport()
Dim dts2 As New DataSet()
dts2 = dts.Clone
Try
Dim m As Integer
m = 0
For i As Integer = 0 To dts.Tables(0).Rows.Count - 1
If clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(3)) >= "20130101" Then
dts2.Tables(0).Rows.Add()
dts2.Tables(0).Rows(m)(0) = clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(0))
dts2.Tables(0).Rows(m)(1) = clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(1))
dts2.Tables(0).Rows(m)(2) = clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(2))
dts2.Tables(0).Rows(m)(3) = clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(3))
dts2.Tables(0).Rows(m)(4) = clsEncrypt.DecryptData(dts.Tables(0).Rows(i)(4))
'dts2.Tables(0).Rows.Add(dts.Tables(0).Rows(i).cl)
m = m + 1
End If
Next
Catch ex As Exception
MessageBox.Show(e.ToString())
End Try
Dim rds As ReportDataSource = New ReportDataSource("DataSetDateOfBirthTest", dts2.Tables(0))
With reportViewer1
.LocalReport.DataSources.Clear()
.LocalReport.DataSources.Add(rds)
.RefreshReport()
End With