I have a question about how to setup components in a winforms application so they can interact with each other. But I want to use the visual designer to set this up.
What I have is a component called myDataBase and a component called myDataTable.
Now the component myDataTable has a property of type myDataBase.
So in code I can do
myDataBase db = new myDataBase();
myDataTable dt = new myDataTable();
dt.DataBase = db;
The property DataBase in component myDataTable is public, so I can also use the visual designer to assign the DataBase property.
Now for my problem.
I have many many forms that have one or more components of myDataTable on it.
I only want one instance for myDataBase.
What I do now is I create a component myDataBase dbMain = new myDataBase() on the mainform.
On every form I have to set the property for all myDataTable components to this dbMain.
I have to do this in code because the visual designer cannot see the dbMain component on the mainform.
So the question is, can I create one instance of component myDataBase that is visible to the visual designer on all forms, so I can use the visual designer to set the property of myDataTable components ?
For those that now Delphi, I want something like the DataModule in Delphi.
You can't without some code.
The easiest thing you can do, as far as I am concerned, it to create a base form, deriving from Form, and in that form, you make a property pointing to a singleton instance of your database object. You can bind to that property, and still keep it as simple as possible.
You just need to make your form derive from this one:
public class DatasourceForm : Form
{
public myDataBase DataBase
{
get
{
return myDataBaseFactory.Current;
}
}
}
And the factory in charge of creating the singleton database instance:
public class myDataBaseFactory
{
private static readonly Lazy<myDataBase> lazy =
new Lazy<myDataBase>(() => new myDataBase());
public static myDataBase Current { get { return lazy.Value; } }
}
(Singleton implementation from here)
Related
I'm refactoring my code to implement multi-database work. I use System.Data.Common classes and factory to create Exact objects for currently selected database engine. Some connection definitions in Designed looks like:
private System.Data.Common.DbConnection cn;
and assigment is:
private void InitializeComponent()
{
...
this.cn = SqlFactory.CreateConnection();
...
}
and SqlFactory code looks like:
public DbConnection getConnection()
{
return (TSqlConection)Activator.CreateInstance(typeof(TSqlConection));
}
It works okay at runtime, but when i'm trying to open any form in VS Designer i've got errors like the following:
The variable 'cn' is either undeclared or was never assigned.
And Designer can't display form for editing.
How can i fix it?
The InitializeComponent method should not be touched manually in general, the Form Designer always overwrites its contents once you open it. Visual Studio usually adds an autogenerated comment about that in *.Designer.cs. Also, I would suggest not to try to create any DB connection in the default constructor (the one without parameters), because Visual Studio calls it when you attempt to open your form in the Designer.
So, your options are
Create an additional constructor for your form with parameters, this one can try to initialize your DB connection.
Use the Load event of the form.
Create an additional method called, for instance, InitConnections in the form, this method will perform a necessary initialization. You call it right after your form is created somewhere in your code.
Remove this.cn = SqlFactory.CreateConnection(); and everything about cn from Designer.cs.
Add this part after InitializeComponent();.
Now you can edit form and no errors will occurre.
I am a new self taught programmer and I feel like there is a better way to accomplish this, so here I am asking. Thanks.
I have a c# program I am writing, uses windows forms, I have multiple forms with datagridview on them.
I have created another form that allows the user to set preferences about how the view them
ex: font, background color, alt row color, etc.
So, at each grid I end calling the same code to retrieve these settings, I am just trying to see if there is a more central streamlined approach.
Here is the code I use at each grid to give you a better idea.
//pull the custom user settings for the datagridview
dgvAds.AlternatingRowsDefaultCellStyle.BackColor = Properties.Settings.Default.AltRowColor;
dgvAds.DefaultCellStyle.BackColor = Properties.Settings.Default.RowColor;
dgvAds.Font = Properties.Settings.Default.RowFont;
The most direct way is to call a common function that does these preprarations. You can put it at a level where you can call it from everywhere, like a static Utlities class..:
public static class Utilities
{
public static void loadDGVSettings(DataGridView DGV)
{
if (DGV != null)
{
//pull the custom user settings for the datagridview
DGV.AlternatingRowsDefaultCellStyle.BackColor =
Properties.Settings.Default.AltRowColor;
DGV.DefaultCellStyle.BackColor = Properties.Settings.Default.RowColor;
DGV.Font = Properties.Settings.Default.RowFont;
// ...
}
}
}
You would call it from each Form with the respective DataGridView, after maybe InitializeComponents()..:
public Form1()
{
InitializeComponent();
Utilities.loadDGVSettings(dataGridView1);
}
To create a class: right-click the project, choose add class, give it the name you like and replace the class stub with code like above. You will need to add a using System.Windows.Forms; clause to such a class file.
Environment: Visual Studio 2008, C#, SQL Server, Windows development, Multiuser, New Developer
I have a method in form A that I use to display textbox information there.
Also I have a button that displays another form when clicked (form B).
Form B is created with frm.ShowDialog();
Form B has the same textboxes on it with the same names, they are identical (copied and pasted from form A)
I want to use the method in Form A to display the information in Form B, rather than copying and pasting the method from form A into form B
I made the method in form A public and called it from from B but nothing displays in form B's textboxes. Why? I don't get any errors.
Should I keep it simple and put a copy of form A's method in Form B instead of calling the method in form A from form B? That's the only way I can get it to work.
Form A is for displaying customer information, Form B is for editing customer information.
I'm passing and returning information between the forms and that's all working.
The forms are not identical, i.e., form B doesn't have textbox for the customer's notes, they are edited in a separate form.
Thank you for your input.
you should use an info class and retrieve data from it both in form A and form B
don't use duplicate code, just use another class for logic \ info.
You can read more about it here
Make a model class whose members represent the data to be shown in both forms. In visual studio 2008 I believe there is support to create a project data source based on an object. Create the data source from your model class. Then, in both forms, add a binding source. Set the data type for the source to be the project data source. Then, the designer will let you select bindings for each control from the binding source. Finally, in the form's constructor, accept a model class instance, and set the binding source's data source to be that instance.
Even if you have the same textboxes with same names when you call formA you are just changing the instance of formA which means only the textboxes in formA are changed.
You have to understand that every class has its own instance separate from the other.
That does not mean though that you cannot access formB textboxes in formA. I can see that you want to consolidate; if I'm not mistaken what you have in formA method is something like:
public void methodA(Customer customer)
{
textboxName = customer.Name;
textboxAddress = customer.Address;
}
If you dont want to duplicate this then the other approach that I can think of is:
1.) Create an interface for all the duplicate properties.
public interface ICustomerForm
{
string Name {get; set;}
string Address {get; set;}
}
2.) Have the 2 forms implement the interface.
public class FormA : Form, ICustomerForm
{
public string Name
{
get
{
return _textBoxName.Text;
}
set
{
_textBoxName.Text = value;
}
}
}
Do the same for formB
3.) Create a static helper class where you just pass the customer class. e.g:
public static class FormHelper
{
public static UpdateCustomerInfo(ICustomerForm form, Customer customer)
{
form.Name = customer.Name;
form.Address = customer.Address;
}
}
4.) In your two forms just call the helper class and pass itself as the first parameter and the customer class as the second parameter.
//Method in formA
public void formA()
{
FormHelper.UpdateCustomerInfo(this, customer);
}
//Method in formB
public void formB()
{
FormHelper.UpdateCustomerInfo(this, customer);
}
This way you just have one line of code in your forms and the setting of info is on the consolidated helper class.
I am using VS 2010 and C# windows forms.
I need the user to enter how many objects he has and how much each weights.
I then need to process each one. I typically use for each datarow in row collection.
Question is i tried cleaning up some of my Very Nasty code (this is my first real project ever btw) I have one main class at ~5000 lines of code and would like to break up specific sets of modules into there own classes. The problem is when the user enters info i have to set up a dataset on the main form (DSObjects) and link a table grid view and a couple of entry boxes with an add button to it so the user can add the data they need. The issue I am having is when I run the code and break up the class into sub classes the dataset is wiped out on each new class.
Do not create a new instance of the data set in every class, but pass one instance around, like:
public class AnotherClass
{
private DataSet m_dataSet;
public AnotherClass(DataSet ds)
{
m_dataSet = ds;
}
}
When creating a new instance of AnotherClass use:
AnotherClass ac = new AnotherClass(m_dataSet);
where m_dataSet is again a member variable that references the data set - either passed to the calling class in the constructor, or (in case of the main class) being created somewhere in the code.
Only create the data set once, for example in the main class.
Another approach could be to use a singleton class that holds an instance to the data set. The singleton could then be accessed from lots of different objects.
A non-threadsafe sample would be:
public class DataHolder
{
private DataSet m_dataSet;
private static DataHolder m_instance;
private DataHolder()
{
m_dataSet = ... // Fill/Create it here
}
public static DataHolder Instance
{
get
{
if (m_instance = null)
m_instance = new DataHolder();
return m_instance;
}
}
public DataSet Data
{
get { return m_dataSet; }
}
}
Then, access it using DataHolder.Instance.Data;
You could try passing the dataset into the constructor of each class
var something = new Something(dataset)
Keep in mind that a DataSet is actually a small (but complete) database in memory. While most applications just use it to transfer data from a database server to objects in the application, it has all the parts of a full database: multiple tables, which can be joined be relationships, which can have queries run against them.
With that in mind, just as you wouldn't have separate databases for each class, but instead have one used globally for the whole application, it is similarly quite reasonable to have one DataSet shared by all objects in the application.
I have subclassed Form to include some extra functionality, which boils down to a List<Image> which displays in a set of predefined spots on the form. I have the following:
public class ButtonForm : Form
{
public class TitleButton
{
public TitleButton() { /* does stuff here */ }
// there's other stuff too, just thought I should point out there's
// a default constructor.
}
private List<TitleButton> _buttons = new List<TitleButton>();
public List<TitleButton> TitleButtons
{
get { return _buttons; }
set { _buttons = value; }
}
// Other stuff here
}
Then my actual form that I want to use is a subclass of ButtonForm instead of Form. This all works great, Designer even picks up the new property and shows it up on the property list. I thought this would be great! It showed the collection, I could add the buttons into there and away I would go. So I opened the collection editor, added in all the objects, and lo and behold, there sitting in the designer was a picture perfect view of what I wanted.
This is where it starts to get ugly. For some reason or another, Designer refuses to actually generate code to create the objects and attach them to the collection, so while it looks great in Design mode, as soon as I compile and run it, it all disappears again and I'm back to square one. I'm at a total loss as to why this would happen; if the Designer can generate it well enough to get a picture perfect view of my form with the extra behaviour, why can't/won't it generate the code into the actual code file?
First of all you need to inherit your TitleButton class from Component so that the designer knows it is a component that can be created via designer generated code. Then you need to instruct the designer code generator to work on the contents of the collection and not the collection instance itself. So try the following...
public class TitleButton : Component
{
// ...
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<TitleButton> TitleButtons
{
// ...
}