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.
Related
First of all, let me apologize for the super-noob question about WPF and binding. I have started, a few days ago, to get interested in WPF and its implementation with XAML markup and C# code-behind in Visual Studio Express 2013, and I'm trying to bind the contents of a button to a property that is part of a singleton class. And I can't, apparently.
What I want to do is this:
I have a button saying "Start" and I want, on click, to have the button contents change to a timer + stop, something like "00:00:02 -- Stop" and, on click again, to have it change back to "Start".
I have this class that I have designed as a singleton to prevent it from being instantiated more than once, which contains an instance stopwatch of System.Diagnostics.Stopwatch, and a string property which I change either to "Start" or stopwatch.Elapsed.TotalSeconds.ToString () + "Stop" back and forth.
The problem is that when I try to refer to my singleton class in the XAML markup, like so (to be honest, I don't really know what I'm doing, I'm just inspiring myself from diverse examples I've found over the web):
<Window
...
xmlns:local="clr-namespace:myNameSpace">
<Grid>
<local:mySingleton x:Key="myStringProperty" />
...
</Grid>
</Window>
I get a slew of compiler errors (6 total) of which some say: "The type mySingleton does not include any accessible constructors." and "The "Key" attribute can only be used on an element that is contained in "IDictionary"."
I'm clueless as to what to do, knowing that I don't want to make the constructor public (and therefore get rid of the singleton thing).
Any pointers towards the right direction ?
Thank you guys for your help.
At first you have problem in displaying your string property. You have to use text box and then use property for text binding:
<TextBox Text="{Binding Path=myStringProperty}"/>
Also you have to set your class (view model) to the Window.DataContext and your property have to call OnPropertyChanged event (see: WPF: simple TextBox data binding).
Now about singleton. The singleton shouldn't be used for this. You should have window (view) and that window have to work with some class (view model, you have one instance per one window) and if you want to run more windows together and you always want same result, then inside that view model you should have some static object (it can be that timer, or some class which will handle requests about get result from timer which will inside that class what can be singleton). So it could looks like Window (view) -> view model class -> static timer / class which will works with timer inside itself.
I am trying to create a simple onscreen keypad created using buttons (currently a User-control), on those buttons i have a click event, when i click/touch a button i want the value of that button sent to a Text-block in my Main-window.
I can't/don't understand how to make the User-control (keypad) see the Text-block (in Main-window) to add in the value that i need.
I have seen solutions that use command Bindings and solutions that use the visual tree traversing but all of them are the main window accessing the user control, not the other way around.
All the examples are the other way around because that is how a UserControl is supposed to work.
A UserControl is a packaged piece of re-usable functionality. It should not know anything about the code that is using it.
Instead you should expose routed events in your UserControl for things like a when number was selected, and subscribe to them in your main window.
There are many ways to achieve what you want. If your MainWindow.xaml has a UserControl and you want to react to a change from the control in the MainWindow.xaml.cs file, then you could add a delegate to the UserControl code behind and register a handler for it in the MainWindow.xaml.cs file. Implementing new delegates are generally somewhat simpler than implementing RoutedEvents, which is another way that you could handle this situation.
Using a delegate like this will enable you to effectively pass a signal to the main view from the child UserControl code behind, which you can react to in any way you want to. Rather than explain the whole story again here, please see my answers from the Passing parameters between viewmodels and How to call functions in a main view model from other view models? posts here on Stack Overflow for full details on how to achieve this.
I'm trying to perform some actions at my VM just before my Window closes, It mean I need DataContext must be available for my actions.
Actually I'm trying with this:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding _MyCleanUpCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But, at this point all objects on my ViewModel are cleaned and my DataContext = null
What is the propper event to Bind with my command?
There is a way to force one class to execute Automatically a method when this is no needed anymore (Needed mean in my current proccess)?
NOTE: For the second question IDisposable does'nt work due must be called manually. ~ Finalizers doesn´t work inmediatelly.
First of all the objects are not being cleaned.
The name of the event you are trying to listen to is called "Closing" which is being fired before the actual close. The event that signals to you that a window got completely closed is called "Closed". Those are the two events available for you.
I would simply associate the handler in the View constructor
MyWindow()
{
// Set up ViewModel, assign to DataContext etc.
Closing += viewModel.OnWindowClosing;
}
Then add the handler to the ViewModel:
public void OnWindowClosing(object sender, CancelEventArgs e)
{
// Handle closing logic, set e.Cancel as needed
}
In your case, you gain exactly nothing except complexity by using a more elaborate pattern with more indirection (5 extra lines of XML plus command pattern).
The "zero code-behind" mantra is not the goal in itself, the point is do decouple ViewModel from the View. Even when the event is bound in code-behind of the View, the ViewModel does not depend on the View and the closing logic can be unit-tested.
However if you insist on sticking to interaction I recommend you read this link below:
http://msdn.microsoft.com/en-us/library/ms748948.aspx
It will give you an overview about events of Window.
Btw, like I already said DataContext is there for sure so I assume you rather have a bug somewhere in Command pattern (you might have defined the Command wrong). You should have posted us the complete code.
Futhermore giving names to public commands with first letter being an underscore is sooo outdated. I remember using them 20 years ago in pure C to signal a private field. :)
Your DataContext and all other objects shouldn't be already cleaned when you enter into your Closing command. This is not the expected behavior.
Indeed, the main purpose of the Closing event is to provide a way of preventing the application exit without any harm (from msdn):
When a window closes, it raises two events: Closing and Closed.
Closing is raised before the window closes, and it provides a
mechanism by which window closure can be prevented. One common reason
to prevent window closure is if window content contains modified data.
In this situation, the Closing event can be handled to determine
whether data is dirty and, if so, to ask the user whether to either
continue closing the window without saving the data or to cancel
window closure. The following example shows the key aspects of
handling Closing.
Chances are there's a bug with your EventTrigger which triggers the associated command too late in this particular scenario.
Try to simply bind your window to the Closing event in code behind and see what happens.
Currently my main form has a ton of event handlers because there are a lot of controls. It is very similar to a paint application. I have condensed it down quite a bit and I am sharing event handlers whenever possible but the class is still around 1,000 lines of code. I realize that may not be much to all of you but it is considerably larger than the rest of my classes.
I have refactored a lot of code to other classes but all those event handlers still increase the line count by a large amount. I also started using region blocks to separate event handlers in to groups and that is working rather well but I still would like to know SO's opinion on the matter as to best organize a large amount of form event handlers.
Edit: So I've been using partial classes and I must say, I don't really like them that much. I'm not sure what to do at this point.
I may go back to using region blocks as I'm not sure user controls will help my problem at all. Honestly I did not mind the region blocks that much. That class was the only place I used them and it organized the different sections of the code quite nicely (Menu Event Handlers, Toolstrip Event Handlers, Drag and Drop Support, et cetera).
Still, if anyone still has any other ideas or would like to elaborate upon any posted thus far I'd be more than appreciative as I am still looking for a better solution to this problem.
1000 lines of code is nothing, and that should not be the basis for refactoring your code. Refactor your code where it makes sense; not just because a class contains more lines of code than your other classes. Some classes will require more code than others, and that's perfectly okay.
That being said, if it makes sense you can divide the controls into logical sections, and put them in user controls. Make sure that there is a good justification for doing so though, because otherwise you'll only be convoluding your code base.
I must remind you again though, don't split your code up just to reduce the lines of code.
You could either split the functionality into separate classes (e.g. creating UserControls like Ed has suggested), or think about using partial classes (where one class can be split among many files). I have found partial classes handy to group together related chunks of code, when the "main" class file is getting to large. Sometimes this is the first step in refactoring those chunks of code into separate classes and/or controls.
It's hard to make a concrete recommendation without seeing the code, but those are some of your options.
If you haven't already (you don't mention it) I would split out the various individual controls into UserControls. You can handle all of the events from within the UserControl class and only expose those events that the parent form must absolutely handle. These will likely be small in number and will drastically reduce the responsibilities of your main form.
For example, each tool button could live inside of a UserControl. The canvas control can maintain and instance of the tools control and so on. You can keep creating the composite controls where each upper layer becomes less complicated and most of the actual logic is handled below it.
I would suggest of using more OOP solution. Do not add UserControls, as you add more *complexity*. Let's try to maintain complexity you already have, but make things more clear, cause this is what really you're asking for, I believe.
DI like. In practise if you need to handle a lot of events for a lot of contorls, create ControlManagers, which accepts in ctor the control and subscribes to its events.
So for every control you will have it's own manager.
Advantages:
Clear separated code in different classe, so easy recognizable in case of problems and my be more clear from architectural point of view.
You don't break down your architecture with a lot ot delegated events between tons of controls and subcribers (one subscriber per control)
Sure you will need organise, by the way, the data flow between different classes. But it's by my experience, haven't to be a big problem.
EDIT
An example pseudocode:
UserControl1 mycontrol1; UserControl2 mycontrol2;
public class MyControl1Manager {
public MyControl1ManagerFor1 (UserControl1 uc1) {
//subscribe to events of uc
// here all code to handle events
}
public MyControl1ManagerFor2 (UserControl2 uc2) {
//subscribe to events of uc
// here all code to handle events
}
}
and somewhere in code:
MyControl1ManagerFor1 controlManager1 = new MyControl1ManagerFor1 (mycontrol1);
MyControl1ManagerFor2 controlManager2 = new MyControl1ManagerFor2 (mycontrol2);
Something like this.
Hope this helps.
Once I had a form that became really big. It showed the same information in many various ways. To reduce number of code in single file I used an approach similar to UserControls. All the GUI elements were placed on the form, but their initialization and handlers were maintained by helper classes. They were equivalents of UserControls, but without GUI interface. These classes were initialized in main form's constructor:
SideViewHelper sideView = new SideViewHelper(parentForm, gridControlMaster, gridControlDetail, buttonSubmit);
All the logic that handles the gridControl events, button events are handled inside the helper class.
After the initialization the main form (parentForm) may change state of many UI items by single call of ViewHelper's method.
These classes are created for this only form and are as lightweight as possible.
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?