I am converting a Delphi 7.0 application to .Net(2.0).
In Delphi application there is similar implementation like "User Control", So I too did same in my C# application.
But in Delphi it is possible to code UserControl's events implemantations on main(parent), unlikely in .Net it is a must(not sure) to do it at UserControl level.
My Questions are,
Can't we do same in .Net?
Altenative method(direct) method of doing that
Note: I have achived what I want through delegates/events, But I prefer the way done it in Delphi
You can couple of alternate ways to achieve this:
Make controls members (generated by designer) within user controls as public or internal (possible by setting Modifiers property in control properties). Then you can write code such as UserCtr1.UserCtr2.UserCtrl3.Btn1 to reference the button and attach event handler to it within form code. I won't prefer this approach because it breaks the encapsulation. But if your taking view that user controls are just a UI template (w/o any behavior) then it may work out for you.
Yet another way would be to have local event handlers within control code but make them invoke corresponding methods from Form. This can be accomplished by using TopLevelControl property. For example, in User Ctrl 3 code
private void Btn1_Click(object sender, EventArgs e)
{
((FormMain)this.TopLevelControl).Search(param1);
}
Problem with this approach is tight coupling with form and way to resolve would be to inject some interface to invoke functions from user control. Form can implement the interface. The instance (of interface) can be injected to all user controls via some kind of IoC Container/DI framework.
Related
Currently I'm creating a really big project in Visual Studio 2012, where there are some common settings for each form ("Cancel" and "Save" buttons, Methods that change in every form but have the same name, font sizes and types, form color etc.) it will save me a lot of time if I could do all the design a single windows form and when I edit or modify it, have the changes reflected in the other forms as well.
Let's say I need 10 forms, to create them I would choose this default format and have my menu and basic objects already placed and designed; then after 10 forms I decided to move a button a bit, but don't want to go to every form and move it; just change it in the original format, refresh and all my forms will have that button in the new location.
I used Templates as recommended by Can one set the default properties for new WinForms created in Visual Studio?. But I still have the issue that if I change something in the template it won't refresh in every other form created with the template to that point.
I've already thought of changing the InitializeComponent in the WinForm default format, but this is not recommended and I wouldn't want any errors from this later on.
Any ideas?
Thanks in advance
Inheritance will work for your solution.
Create "base" form with all "common" controls
Create new "derived" form and change form to inherit from your "base" form.
If you have some common logic in base form, which need to be "overridden" in derived forms - put it to the virtual method
// Base form
protected virtual void Close()
{
// Base logic
}
private void CloseButton_Click(object sender, EventArgs e)
{
Close();
}
// In derived form - just override "Close" method
protected override void Close()
{
// custom logic - will be executed when "Close" button clicked
}
In base form leave empty space for custom controls. Because you will not be able access baseform controls through designer in derived form.
Another approach - Model-View-ViewModel(MVVM)
- Introduce own UserControl with common controls(view) which have property - instance of ViewModel.(Viewmodel will contains behaviour logic and possibility to change "base" settings.)
- Add this user control to all "derived" forms and set UserControl.ViewModelProperty to instance which will represent logic for this particular form.
Without knowing "full" context of your goals - difficult to suggest more, but I am pretty sure you can build maintainable relations between forms, which can share common logic and view.
No, there is nothing you can do. Once you use a template to create a project or a file, it becomes a one-off. You have to edit it manually, or use a text editor that is powerful enough to employ a find and replace with pattern matching and capture group insertion.
I have this Usercontrol with a Listview loaded in the Mainwindow:
<Controls:MetroAnimatedSingleRowTabControl Grid.Row="1" x:Name="MainTabControl" Controls:TabControlHelper.IsUnderlined="True" Margin="10,0,0,1">
<TabItem Controls:ControlsHelper.HeaderFontSize="40" Header=" List" Foreground="#CCB5BABB" Controls:ControlsHelper.HeaderFontStretch="UltraExpanded" HorizontalAlignment="Left" VerticalAlignment="Top" >
<load:Usercontrol1 DataContext="{Binding}" />
</TabItem>
From this Usercontrol a ButtonClick calls another form for entering new data. After saving the data to database, I call a method loading the list in Usercontrol by referencing the entire Usercontrol to the entry window :
private readonly Usercontrol1 temp;
public newDataEntry(Usercontrol1 temp2)
{
InitializeComponent();
temp= temp2;
}
private void buttonentry(object sender, RoutedEventArgs e)
{
temp.fillList(); // list in Usercontrol fill
this.Close();
}
Since I want to use the same entry form with different Usercontrols, is there a more effective way to call method in Usercontrol?
Without a good Minimal, Complete, and Verifiable example that shows clearly what you are doing, why you want to call this method, what the method does, and what specific problem you are having generalizing the action, it is impossible to know for sure what the best answer for your scenario is. That said, some discussion can be provided.
First and foremost, it is a mistake for your newDataEntry class to depend on the Usercontrol1 class at all. This should already be apparent, due to the issue you are running into trying to reuse it with other UserControl classes, but it is also a basic OOP concept: a class that exists to support some other class should not itself carry a dependency on that other class. Doing so breaks reusability in a way that is fundamentally opposite a primary goal of OOP.
So how do you get rid of this dependency? Well, the most general way in C# would be for your Usercontrol1 to subscribe to the newDataEntry object's Closed event. Then it can do whatever it wants at that time, including calling its own fillList() event.
Of course, if the newDataEnty window is used modally (i.e. you call ShowDialog()), then subscribing to the Closed event is overkill. You can just call whatever code you need to when the ShowDialog() method returns.
All that said, the name fillList() hints that you're copying list data directly into some list-based control (e.g. the ListView you mentioned). When in fact, in a WPF program, you should be manipulating only view models and letting the UI respond accordingly. Again, without a good MCVE showing context, it's impossible to say for sure that's what you're doing, never mind provide any specific advice along those lines. Suffice to say, it's likely that this code doesn't belong in the Usercontrol1 class at all.
See also these related posts:
How to call method of the main WPF window from the modal window? - this seems most applicable. Unfortunately, the accepted and top-voted answer is one of the worst (introduces exactly the kind of class coupling you're trying to avoid here), but there are other answers with some useful information.
WPF MVVM call ViewModel Save method on Window Close - this discusses doing something similar in the context of using a proper view model. May or may not be directly applicable to your scenario.
Communicate between two windows forms in C# - this is about Winforms, but in this particular scenario the basic techniques are similar. In this particular case, you wouldn't need to declare a new event, because the Closed event already seems to do what you want.
I need to create a non-visual component, FooComponent, that will do some management for all controls of type Bar that resides in its form.
I have the following constraints:
The FooComponent can only be added to forms.
Only one FooComponent per form is allowed.
FooComponent should register to the form closing event, and when it fires and to some function on all Bar's and sent the e.Cancel value based on the returned values.
#1 and #2 above should be enforced on run-time as well as design time.
#3 event registration should be made automatically and not by the FooComponent's users.
I searched Google and MSDN for some help and read about Component and ComponentDesigner classes, but I didn't find anything for the rescue.
What should I do?
(1) To control that the component can only be added to a form, use a FooComponent constructor that is passed a form, and don't define the default constructor. It's called like:
FooComponent component = new FooComponent(this);
where the component is created from within the form itself. By not-defining the default constructor, this:
FooComponent component = new FooComponent();
will not compile.
(2) Expose a FooComponent property on the form itself, and in the constructor of the FooComponent, set the passed form's FooComponent to this.
(3) Same thing, in the constructor for the FooComponent, register with the closing event for the form you passed
Put it all together and you get:
public class MyForm : Form {
public FooComponent OwnedComponent { get; set; }
}
public class FooComponent {
public FooComponent (MyForm OwnerForm) {
OwnerForm.OwnedComponent = this;
OwnerForm.FormClosing += MyCallback;
}
private void MyCallback(object sender, FormClosingEventArgs e) {
...
}
}
EDIT
Unfortunately, if you need the default constructor, and if it has to be a true drop-on-the-form Component, there's no way to enforce that a component is only created on a Form, or that the Form only has one instance of the component (not from within the component, anyway).
The problem is twofold:
(1) Dropping a component doesn't add the component to the form, it adds it to the form's components collection. So even if you could get a handle to the parent/owner, it will never be a form.
(2) As Neil pointed out, dropping a component onto a form calls the default constructor, which passes no parameters, and, of course, none of the component's properties (such as site or container) are populated.
Possibly helpful: A component can be designed to be notified when it is created in a couple of ways:
(1) By implementing a constructor that takes an IContainer parameter. When the component is dropped on a form, the generated code will call this constructor, instead. However, it will only do this at runtime, not design time. But the container will be a handle to the form's components collection.
public FooComponent(IContainer container) {...}
(2) By implementing ISupportInitialize. When the component is dropped on a form, the generated code will additionally call BeginInit() and EndInit(). In EndInit(), you can access properties such as the Site and Container. Again, you'll only get this at runtime, not designtime, and throwing an exception here won't stop the component from being created.
Old, but excellent articles on Components and Controls from MSDN Magazine by Michael Weinhardt and Chris Sells.
April 2003 Building Windows Forms Controls and Components with Rich Design-Time Features
May 2003 Building Windows Forms Controls and Components with Rich Design-Time Features, Part 2
These are now .chm help files. You will need to unblock in the file's property page to enable reading the contents after downloading.
I don't think it's possible to define exactly what a contained class can be contained within. I've certainly never seen an instance where I've gotten an error (or even a warning) for setting up a property of one type in another, even in WinForms.
Something you might be able to do is to define a Form-derived ancestor for your forms that contains a reference to your (internally-visible) FooComponent, initializes one on instantiation, and attaches the handlers. For best results it should be parameterless and the only constructor overload, so it forms the base for any constructor your consumers come up with. Then, just make it a house rule that forms derive from your ancestor class and not directly from Form (you might be able to use a code inspection tool like FxCop or similar to enforce this when code is committed to source control). Your users now get a FooComponent in every Form they create, cannot create their own (it's internal and should be in another project with your Form ancestor) and don't have to do anything other than derive from the new class to make their forms behave the way you want.
You are asking for a lot. In general, making components aware of the form they are dropped on is quite difficult. This answer can help you get the event handler implemented. You'll need to implement ISupportInitialize to get the EndInit() call to setup the event handler.
Preventing multiples is quite hard too, I can only think of a custom designer that can step in early enough to prevent the 2nd one from being added.
I really had no idea what to title this question.
Assume I have a windows form application. The GUI is complex enough to require two custom user controls, "LeftSide" and "Rightside" which each are composed from various buttons, labels, and maybe even another custom user control.
My question:
I am in in the scope of the "Rightside" control. How would I call a method from the "Leftside" control?
I am using Visual Studio 2008.
The simplest solution is to make a property on the RightSide control of type LeftSide, then set it to the LeftSide instance in the form designer.
You can then call public methods on the property.
However, this is poor design.
Each usercontrol should be a self-contained block that doesn't need to directly interact with other usercontrols.
You should consider restructuring your form.
Exact equivalent with standard WF controls: how to keep the text of one text box in sync with another:
private void textBox1_TextChanged(object sender, EventArgs e) {
textBox2.Text = textBox1.Text;
}
Necessary ingredients: an event on your user control that is fired when something interesting happens. And public properties.
I have a Form and a UserControl. The UserControl has a menu, and the form has a tabstrip (General, Food, Vitamins etc).
In the UserControl, I have the following code: (Form name is frmForm, the tab names in the form are tabGeneral,tabFood, tabVitamins)
frmForm fm=new frmForm();
fm.tabMain.Selected=tabVitamins;
I call these line from the UserControl to capture the tab to get selected on the form, but it does not select the vitamins tab.
Where am I going wrong? I have access specifier as Protected Internal for tabs in the form.
Please advice.
Thanks,
Karthick
When you write new frmForm(), you're creating a completely new instance of frmForm, which is then discarded.
To get the frmForm instance that holds your control, call the FindForm() method and cast to frmForm.
For example:
frmForm myForm = FindForm() as frmForm;
if(myForm != null)
myForm.tabMain.SelectedTab = myForm.tabVitamins;
If the control is on some other form, this code won't do anything.
By the way, Hungarian notation is frowned upon in .Net.
Your form should probably be named something like MainForm.
SLaks has correctly pointed out your fundamental error, and given you a valid example of a way, via a call to the method 'FindForm, to get the Form the UserControl is sited on.
It may be valuable to you to keep in mind that a UserControl (and all Controls) also has a 'Parent property, but, of course, a UserControl could be placed inside another Control on a Form (like your UserControl could be inside a Panel on the Form) : in that case the UserControl's Parent would be the control it's inside on the Form (like, a Panel), not the Form itself, but 'FindForm will do the right thing to get you the Form it's on.
However you are calling a Method every time you use 'FindForm, and "best practice" suggests that what you want to do is to "inject" a reference to the Form into the UserControl at run-time so that it can always access its Form property easily, without calling a 'Method.
In your example, on a practical level, this (calling the Method) may make almost no difference in performance, but, imho, as you get to a place with WinForms and .NET where you might have a UserControl that will need access to its Parent Form very frequently, this will pay off, and it's a better way to structure your code in the long run, for maintenance.
Wes showed you one way you can "embed" (inject) the UserControl's hosting Form : using an overloaded constructor for the UserControl. But that requires you to modify the Designer.cs file in standard WinForms, and I strongly advise you against that, even though it will work. Particularly if you are just "getting your feet on the ground" in .NET, I strongly advise you against modifying it, or anything having to do with the Form's constructor and its internal call to : InitializeComponent();
Also, as you progress with WinForms you are going to meet many situations where you are going to want instances of "objects" (a Control, a Form, an instance of a Class) to contain references to other instances of "objects.
If you can understand and use one simple use of "injection" here, you are going to make progress to make yourself ready to handle more complex .Net programming in the future.
Another way is to put a Public Property in the UserControl that can be set in code from the MainForm. In the UserControl something like :
private frmForm ParentForm;
public frmForm UCParentForm
{
set { ParentForm = value; }
}
So then in your main form's code, perhaps in the Load event like this :
private void frmForm_Load(object sender, EventArgs e)
{
TheUserControl.UCParentForm = this;
}
or when you need to, you set the UserControl's 'ParentForm property once. So you have eliminated using the method 'FindForm().
In this case, if you only want access to a specific control on the UserControl's Parent Form, like a TabControl, you might consider that you want to make the Property you set of type TabControl, rather than Form : the same coding technique shown above can be used in the UserControl :
private TabControl mainFormTabControl;
public TabControl MainFormTabControl
{
set { mainFormTabControl = value; }
}
imho, it is when you are creating UserControls dynamically at run-time, using an overloaded constructor, as Wes suggests, is the best strategy. And using overloaded constructors has many, many others uses in .NET that you'll get into.
good luck !
You should not be creating a new frmForm() inside the user control. You could pass a reference to the frmForm to the user control.
In your user control constructor try something like this.
private frmForm fm;
public YourUserControl(frmForm fm)
{
this.fm = fm;
}
Then you could use.
fm.tabMain.Selected=tabVitamins;
Does that help?