I'm making a "Preference form" that will hold all the users preferences and when they go to Apply/Save I want the new values to transfer back to the main form and updateand close the form2. In the past I have done this like this:
Private Sub PreferencesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PreferencesToolStripMenuItem.Click
Preferences.Show()
End Sub
and when I click the "Apply/Save" button before it closes I would Transfer all data like this:
form1.textbox.text = form2.textbox.text
Is there anything wrong doing it this way??
What I have been reading is I should be doing it like this:
Private Sub PreferencesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PreferencesToolStripMenuItem.Click
Dim dialog As New Preferences
dialog.ShowDialog()
End Sub
And when when they click "Apply/Save" it would take all the values from Form2 and store them in a private variable (or Property) in Form2 and when that form closes I would then access the value like this:
Private Sub PreferencesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PreferencesToolStripMenuItem.Click
Dim dialog As New Preferences
dialog.ShowDialog()
form1.textbox.text = dialog.variable
End Sub
Why would this be a better way of doing this?
UPDATE....Looking at the code below this is just a SMALL sample of all the options I will have. What is the best way to collect of the data into the object to use when serializing?
<Serializable>
Public Class Preference
#Region "Properties"
Public Property ScaleLowest As String = "5"
Public Property ScaleHighest As String = "200"
Public Property ScaleInc As String = "5"
Public Property ThickLowest As Double = 0.125
Public Property ThickHighest As Double = 4
Public Property ThickInc As Double = 0.125
Public Property WidthLowest As Double = 0.125
Public Property WidthHighest As Double = 0.6
Public Property WidthInc As Double = 0.125
Public Property LengthLowest As Double = 1
Public Property LengthHighest As Double = 96
Public Property LengthInc As Double = 1
Public Property FractionON As Boolean = False
Public Property DecimalON As Boolean = True
Public Property ColorSelection As String = "Colors"
Public Property FinalColor As String = "255, 255, 0"
Public Property roughColor As String = "255, 255, 100"
Public Property SplashON As Boolean = False
Public Property LogInON As Boolean = False
#End Region
Public Sub New()
'for creating new instance for deserializing
End Sub
Public Sub GatherAllData()
'Save Defaults
SaveSerializeObj()
End Sub
Public Sub SaveSerializeObj()
'Get Changes?????
'Serialize object to a text file.
Dim objStreamWriter As New StreamWriter("C:\Users\Zach454\Desktop\test.xml")
Dim x As New XmlSerializer(Me.GetType)
x.Serialize(objStreamWriter, Me)
objStreamWriter.Close()
End Sub
Public Function LoadSerializeObj() As Preference
'Check if new file need created
If File.Exists("C:\Users\454\Desktop\test.xml") = False Then
SaveSerializeObj()
End If
'Deserialize text file to a new object.
Dim objStreamReader As New StreamReader("C:\Users\454\Desktop\test.xml")
Dim newObj As New Preference
Dim x As New XmlSerializer(newObj.GetType)
newObj = CType(x.Deserialize(objStreamReader), Preference)
objStreamReader.Close()
Return newObj
End Function
The best option is to create a class that would have properties for your form controls. Then you can store these properties and then access these when needed.
Also there's really no reason to be passing data back and forth, you can store this data off somewhere (database, file, mysettings etc) and then load this data up into a class. Then you can store and retrieve data from this class. Then if you need to save data back to somewhere you have a class object to use.
Here is a short example to show how you can create another form (Preferences) click save and then show those values back on the other form (calling form).
This is the main form
Public Class Form1
Public _frm2 As Form2
Private Sub btnShowPreferences_Click(sender As Object, e As EventArgs) Handles btnShowPreferences.Click
Using _frm2 As New Form2()
'if we clicked save on the form then show the values in the
'controls that we want to
If _frm2.ShowDialog() = Windows.Forms.DialogResult.OK Then
txtFirstName.Text = _frm2._Preferences.FirstName
txtLastName.Text = _frm2._Preferences.LastName
End If
End Using
End Sub
End Class
Here is an example (Preferences) class
This class would hold all your properties for the preferences. This is an example, you can change anything you need to suit your needs.
Option Strict On
Public Class Preferences
#Region "Properties"
Public Property FirstName As String
Public Property LastName As String
#End Region
Public Sub New()
End Sub
End Class
The second Form could be your (Preference) form with all the controls a user would need to interact with.
Public Class Form2
Public _Preferences As New Preferences 'create class variable you can use for later to store data
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
'set your properties of the class from your form. this will then hold everything you can get from
'the first form...
With _Preferences
.FirstName = txtFirstName.Text
.LastName = txtLastName.Text
End With
Me.DialogResult = Windows.Forms.DialogResult.OK 'this is used to determine if user clicked a save button...
End Sub
End Class
I hope this get's you started, if you do not understand something please let me know.
To directly answer your question, the main difference in your two code samples is that the second uses ShowDialog to open the form modally, vs the first sample which lets you interact with the parent form while the second is open.
The second approach may be better from the view of user flow control. If your real question is whether to push data back to the main form or pull data from the dialog, it is probably better to pull from the dialog. This approach makes the dialog reusable from other forms.
Related
I'm making a program that generates SQL Server code to use it in my VB.NET program.
I have this first form that contains the connection like you see in picture below:
The connection works 100%, but in the second form I have two DataGridViews, one for tables and one for fields.
So when I click on any table of DataGridView1 => DataGridView2 show it fields:
When I click on DataGridView1 to get the value of ComboBox from Form1 to use it in Form2 I have the following error:
Failed to connect to server.
Code:
Dim frm As New Form2
prd.ServerConnection = New ServerConnection(frm.ComboServer.Text) ' here the error
prd.DGVField(MetroGridTables, MetroGridField)
I use Form1 to make connection and Form2 to make operation.
The simplest way to pass a value from one form to another is to implement the New method on the form you want to pass the value to:
Form1:
Public Class Form1
Private Sub btnPass_Click(sender As Object, e As EventArgs) Handles btnPass.Click
Dim form As New Form2(TextBox1.Text)
form.Show()
End Sub
End Class
Form2:
Public Class Form2
Public Sub New(ByVal value As String)
' This call is required by the designer.
InitializeComponent()
Label1.Text = value
End Sub
End Class
Screenshot:
This question is a bit confusing, but this is how I would pass a variable from one form to another.
Create a class /w variable.
Public Class Variables
Public Shared Property imavariable As String
Get
Return m_imavariable
End Get
Set(value As String)
m_imavariable = value
End Set
End Property
Private Shared m_imavariable As String
End Class
Set the variable from form 1... variables.imavariable = string
Read the variable from form2.... string = variables.imavariable
I have searched through the internet and couldn't find the answer to my problem, but, the issue is that I have 2 forms;
frm_bookManeger
and
frm_addBook
The first one is the main form and has a list of books (named listBook), a TreeView and a button to invoke the second form to add a new book.
After filling in all of the TextBoxes and information of a book, I press "Add". Then, the second form will be closed and all info of that book will be kept in an instance of Book class. The problem is: how can I pass this instance to the first form to store it in listBook.
For example:
If I create a constructor in form 1 to get form 2 then in form 2:
Dim f1 As form1 = New form1(me)
f1.Show()
f2.Close()
I can't do it because form 1 will start up instantly when I start program, and the default right now doesn't have any parameter in OnCreateMainForm():
Protected Overrides Sub OnCreateMainForm()
Me.MainForm = Global.WindowsApplication5.frm1
End Sub
How can I do it?
First form:
Public Class frm_bookManeger
'list of Book
Dim listBook As List(Of Book) = New List(Of Book)
Private frm_addBook As frm_addBook
Public Sub New(frm_addBook As frm_addBook) 'got error
Me.frm_addBook = frm_addBook
End Sub
Second form:
Public Class frm_addBook
Dim Public tempBook As Book = New Book()
'add book
Private Sub btn_add_Click(sender As Object, e As EventArgs) Handles btn_add.Click
tempBook.BookName1 = TextBox_name.Text
tempBook.Author1 = TextBox_author.Text
tempBook.Price1 = TextBox_price.Text
tempBook.Genre1 = TextBox_genre.Text
tempBook.EstablishedDay1 = dtp_established.Value.Date
Dim frm_Mngr As frm_bookManeger = New frm_bookManeger(Me)
End Sub
End Class
Dim frm As New form1
frm.textbox.Text = Me.passing value.Text
frm.Show()
or you can try
Public Class Form1
Private loginLabel As String
Public Sub New(ByVal loginParameter As String)
InitializeComponent()
Me.loginLabel = loginParameter
End Sub
End Class
dim frm as new Form1(label.Text)
Your frm_addBook needs a reference to the instance of frm_bookManeger so that it can use methods in the latter.
That can be done by passing a reference to the current instance of frm_bookManeger to the New constructor of frm_addBook.
Also, you probably want the book adding form to be a dialog form rather than an ordinary form.
I made a simple "Book" class and used a TextBox to display the books, so the first form is this:
Imports System.Text
Public Class frm_BookManager
Dim bookList As List(Of Book)
Public Class Book
Property Name As String
Property Author As String
End Class
Public Sub AddBook(b As Book)
If bookList Is Nothing Then
bookList = New List(Of Book)
End If
bookList.Add(b)
End Sub
Private Sub ShowBooks()
Dim sb As New StringBuilder
For Each b In bookList
sb.AppendLine(b.Name & " by " & b.Author)
Next
TextBox1.Text = sb.ToString()
End Sub
Private Sub btn_add_Click(sender As Object, e As EventArgs) Handles btn_add.Click
Using addBook As New frm_addBook(Me)
Dim result = addBook.ShowDialog()
If result = DialogResult.OK Then
ShowBooks()
End If
End Using
End Sub
Private Sub frm_BookManager_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddBook(New Book With {.Name = "Wuthering Heights", .Author = "Emily Brontë"})
ShowBooks()
End Sub
End Class
For the form to add a book, I added "Cancel" and "OK" buttons.
Public Class frm_addBook
Dim myParent As frm_BookManager
Private Sub bnOK_Click(sender As Object, e As EventArgs) Handles bnOK.Click
Dim b As New frm_BookManager.Book With {.Name = TextBox_name.Text, .Author = TextBox_author.Text}
myParent.AddBook(b)
End Sub
Public Sub New(parent As frm_BookManager)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
myParent = parent
' set the DialogResult for each button so the parent can tell what happened
bnCancel.DialogResult = DialogResult.Cancel
bnOK.DialogResult = DialogResult.OK
End Sub
End Class
Notice that a new Book can be added with myParent.AddBook(b) because myParent refers to an instance of frm_BookManager.
You could modify it so that the dialog stays open and has a button to just add a book and not close the dialog. I made the ShowBooks() method Private so you can't call it from outside the class it is in - you could modify that.
There are many possibilities for small modifications to the code I showed to achieve greater functionality. And I could not resist correcting the spelling of "Maneger" to "Manager" ;)
I think the easiest way would be to have the frm_addBook form have a property which will contain the book that was added. In the frm_bookManager form, show that form using ShowDialog and if the user clicks OK on that form, the property will contain the book added. Be sure to dispose the frm_addBook form after you get the book from the public property.
Public Class Book
Public Property Name As String
Public Property Author As String
End Class
Public Class frm_bookManager
Dim bookList As New List(Of Book)()
Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
Using addBookForm As New frm_addBook()
If addBookForm.ShowDialog() = DialogResult.OK Then
bookList.Add(addBookForm.BookToAdd)
End If
End Using
End Sub
End Class
Public Class frm_addBook
Public Property BookToAdd As Book
Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles
'User filled in the fields and clicked this OK button
Me.BookToAdd = New Book()
Me.BookToAdd.Name = txtName.Text
Me.BookToAdd.Author = txtAuthor.Text
End Sub
End Class
I would not pass the main form instance into the add book form because it would create a tight coupling between the two forms and the add book form would only be usable by the main form. You might wish to use the add book form from other forms in the app.
Here's my problem.
I'm making a project in VB.NET that (currently) exists out of 1 class (let's call it User.vb here) and 2 WinForms (frmDisplay & frmMain).
Let's say User.vb is currently looking like this:
Public Class User
Private mName As String
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Property Name As String
Get
Return mName
End Get
Set(value As String)
mName = value
End Set
End Property
End Class
Let's also say the form frmDisplay is just a form with a textfield txtString and a button btnSend.
Public Class frmDisplay
Dim usr As New User()
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
usr.Name = txtString.Text
frmMain.Show()
Me.Hide()
End Sub
End Class
On the form frmMain I want to reach the value in the property Name that I stored in the class User on the first form.
The basic idea is (I know it doesn't work):
Public Class frmMain
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblStoredString.Text = usr.Name << This is where I'm stuck
End Sub
End Class
I googled my problem and read many posts, but I just can't seem to understand it. Maybe you guys can help me. I am new to VB.NET and WinForm-stuff (about 3 months of exp.), but I have done some programming in the past in C# with webapplications.
Every bit of help is greatly appreciated.
Thanks a lot in advance!
Will there only ever be one User.Name that you are interested in throughout the app?
If yes, then change the class to:
Public Class User
Public Shared Name As String
End Class
Then you can use User.Name from any form (or anywhere in the application) to get/set that value.
Note that you can still wrap the field in a property if you like:
Public Class User
Private Shared _Name As String
Public Shared Property Name As String
Get
Return _Name
End Get
Set(value As String)
If (value.Trim <> "") Then
_Name = value.Trim
End If
End Set
End Property
End Class
My focus is ASP.NET, and I prefer C#, but I'll chime in. There are numerous ways of providing data between the forms. The first one that comes to mind is to use a cache of some kind. The idea is that once the cache is made available to your program, you can add the value to the cache when the button is clicked, and then safely read the value whenever you need it. This can be a static class with a Dictionary, or you can look into using the functionality provided by the System.Web.Caching namespace. http://www.codeproject.com/Articles/8977/Using-Cache-in-Your-WinForms-Applications has an example.
Another way would be to use a shared data source. The concept is similar to the caching, but this would allow you to pass more complex relational data between your forms, assuming your real goal is more complicated than you describe. Here is a walkthrough for that: https://msdn.microsoft.com/en-us/library/ms171925.aspx.
You could be quick and dirty, and write the values to a text file at some location, and then read the values from the second form.
The simplest way is probably to define a custom constructor for the second form, and pass the values you need when you instantiate the second form. This is best suited if the values from the first form can be considered "parameters" to the instance of the second form. Passing a textbox value from one form to another in windows application
Declare the usr variable Friend
Public Class frmDisplay
Friend usr As New User()
It will then be available from the other form
Public Class frmMain
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblStoredString.Text = frmDisplay.usr.Name
End Sub
End Class
It's a quirk of VB.NET that forms are automatically created with a public variable name the same as the class name. That's why you are able to use frmMain without having to create it (e.g. Dim frmMain as New frmMain). You can turn off this behaviour, but it isn't relevant to your problem.
On the other hand, if you want to do it "properly"...
Public Class frmDisplay
Private usr As User
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
usr = New User(txtString.Text)
Dim f As New frmMain(Me, usr)
f.Show()
Me.Hide()
End Sub
End Class
and frmMain...
Public Class frmMain
Private myParent As Form
Private usr As User
Sub New(parent As Form, _usr As User)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
usr = _usr
myParent = parent
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = usr.Name
End Sub
Private Sub frmMain_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
myParent.Show()
End Sub
End Class
Here we instantiate frmMain and pass the User object to its constructor. We also pass the calling form so we can display it again when frmMain is closed.
I am trying to seperate my code logic from my gui as in MVC principles, what I am trying to achieve is quite simple I believe
I have my Form1, which contains a textbox and button, once the button is clicked it loads a function in my controller class which adds a string to a database using entity and then should update the textbox with this name.
I thought what I would need to do is pass the original form through and then databind to the textbox object on the form, this is where I have come unstuck though, as my logic fails...
Public Class Form1
Private mf As New MainForm(Me)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
mf.buttonClick()
End Sub
End Class
Public Class MainForm
Private Property a As Form
Public Sub New(ByVal s As Form)
a = s
End Sub
Function buttonClick() As Boolean
Dim context As TestDBEntities2 = New TestDBEntities2
Dim newCategory As tTable = New tTable
newCategory.Name = "Test1 " & Today.DayOfWeek
context.tTables.Add(newCategory)
context.SaveChanges()
Dim current As String = newCategory.Name
a.DataBindings.Add("text", "TextBox1", current)
Return True
End Function
End Class
and my error:
Cannot bind to the property or column Test1 6 on the DataSource.
Am I looking at this the right way? Or am I so far off that there is an obvious reason this doesn't work?
Any input would be appreciated! Whats the best way to pass data back to a source without returning it in as a result of a function?
You should consider changing your code a bit, so that it reflects more the MVC structure:
use Events to exchange data and indicate action triggers, instead of using the form object
normally the controller has knowledge of the form and not the other way around, so swap this in your project. This reflects also the first point
So a possible solution for a Windows Forms application could look like this:
The form that has one button and one text field, one event to signal the button click and one WriteOnly property to fill the TextBox from outside the form:
Public Class MainForm
Public Event GenerateAndShowEvent()
' allow text box filling
Public WriteOnly Property SetTextBoxContent()
Set(ByVal value)
generatedInputTextBox.Text = value
End Set
End Property
Private Sub generateAndShowButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles generateAndShowButton.Click
' forward message: inform the subscriber that something happened
RaiseEvent GenerateAndShowEvent()
End Sub
End Class
The controller class has knowledge of the form, creates it, binds (listens) to the form's button click event and makes the form ReadOnly for the world (exposes the form):
Public Class MainFormController
' the form that the controller manages
Private dialog As MainForm = Nothing
Public Sub New()
dialog = New MainForm()
' bind to the form button click event in order to generate the text and response
AddHandler dialog.GenerateAndShowEvent, AddressOf Me.GenerateAndShowText
End Sub
' allow the world to access readonly the form - used to start the application
Public ReadOnly Property GetMainForm()
Get
Return dialog
End Get
End Property
Private Sub GenerateAndShowText()
' create the text
Dim text As String = "Test test test"
' access the Database ...
' give the generated text to the UI = MainForm dialog!
dialog.SetTextBoxContent = text
End Sub
End Class
Now what left is to create first the controller, that creates the form and use the form to show it. This can be done like this:
Create an AppStarter module with a Main method:
Module AppStarter
Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
' create the controller object
Dim controller As MainFormController = New MainFormController()
' use the public property to get the dialog
Application.Run(controller.GetMainForm)
End Sub
End Module
In your project settings uncheck the enable application framework setting and set the AppStarter module as the start point of your project:
Now you have a Windows Form Project using the MVC pattern.
If you still want to use DataBinding for the TextBox control, then create a Data Transfer Object or DTO that represents the fields you will transfer from your controller to the form:
Public Class DataContainer
Private t As String
Private i As Integer
Public Property Text() As String
Get
Return t
End Get
Set(ByVal value As String)
t = value
End Set
End Property
Public Property Id() As Integer
Get
Return i
End Get
Set(ByVal value As Integer)
i = value
End Set
End Property
End Class
Then add a BindingSource for your TextBox and configure it to use the DTObject:
Now bind the TextBox control to the DataBinding control:
What left is to add a public setter for the TextBox data binding control in the form:
Public Property TextBoxDataSource()
Get
Return TextBoxBindingSource.DataSource
End Get
Set(ByVal value)
TextBoxBindingSource.DataSource = value
End Set
End Property
and transfer the data from the controller:
Private Sub GenerateAndShowText()
' create the text
Dim text As String = "Test test test"
' access the Database ...
' give the generated text to the UI = MainForm dialog!
'dialog.SetTextBoxContent = text
Dim data As DataContainer = New DataContainer
data.Text = text
data.Id = 1 ' not used currently
dialog.TextBoxDataSource = data
End Sub
The binding can also be set programmatically - instead of doing this over the control property window, add the following code in the constructor of the form:
Public Sub New()
InitializeComponent()
' bind the TextBox control manually to the binding source
' first Text is the TextBox.Text property
' last Text is the DataContainer.Text property
generatedInputTextBox.DataBindings.Add(New Binding("Text", TextBoxBindingSource, "Text"))
End Sub
You seem to misunderstand the Add method.
The first argument is the name of the control's property to which you are binding. This should be "Text", not "text".
The second argument is an object that contains the data you want to bind. You have passed the name of the target control, rather than the source of the data. You are also binding to the form rather than the text box. So what you have said is that you want to bind the form's text property to data that can be extracted from the string "TextBox1".
The third argument says where to go to find the data. For example, if you passed a FileInfo object for the second argument, and you wanted to bind the file's path, you would pass the string "FullName", because that is the name of the property containing the data you want. So you have told the binding to look for a property on the string class called "Test1 6", which is why you have received the error message saying it can't be found.
I think what you want is
a.TextBox1.DataBindings.Add("Text", newCategory, "Name");
I have a subsidiary form where I can enter data and then save it before closing the form and going back to using the main form.
When I re-open the subsidiary form, I cannot see the changes in the data that I had entered earlier.
Can anyone tell me where I'm wrong ?
MainForm.vb
Public Class Maincls
oTestObj as New Testcls
oTestObj.XYZ = "XYZ"
Private Sub SoftwareSettingsToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SoftwareSettingsToolStripMenuItem.Click
Testcls.tbXYZ.Text = oTestObj.m_XYZ
Testcls.Show()
End Sub
End Class
Form_Testcls.vb
Public Class Testcls
Structure Params
Dim m_XYZ as String
End Structure
Dim oParams as Params
Public Sub New ()
InitializeComponent()
End Sub
Private Sub btnOK_Click(sender As System.Object, e As System.EventArgs) Handles btnOK.Click
XYZ = tbXYZ.Text
Me.Hide()
End Sub
Public Property XYZ() As String
Get
Return Me.oparams.m_XYZ
End Get
Set(ByVal value As String)
Me.oparams.m_XYZ = value
End Set
End Property
End Class
I think in windows forms the work around for this is to create a static class and add properties according to your requirement. Then populate these static properties on closing of your form. Now you can use the value set in the static data members, unless otherwise you change them on any other event.
Edit: In vb.net the Static is actually NonInheritable