I've been wondering a lot how to have an object act different situationally.
To clarify what I'm wondering:
I want to make a menusystem, and I want to have a "button" class. But the button should behave different depending on what kind of button it is.
One button may close to program, another may start the game, a third may enter settings.
(I was thinking of parsing methods as arguments, but then you still have to write a lot of different methods somewhere in your code)
How do you do this with OOP in mind? I could hardcode the very basic functions of a simple menu using enums and switchcases, but I would want to know if it could be avoided.
I want to avoid things like delegates because games aren't eventbased in such fashion, and also switch-cases, large if/else statements because they are really ugly.
Is there a way to make objects behave like this?
What are other alternatives to making menus, trying to avoid the switch-cases for the commonly used enum. (Not disallowing enums)
I want to avoid things like delegates because games aren't eventbased in such fashion
Aren't they, though? A button click is an event, regardless of whether or not it's a game or a web application. It's by definition something happening that you'd like to react to, such as a button press. What happens when a button is clicked should be loosely coupled from the button in the UI, for the reasons you already encountered (large switch/if-elses are a pain) among others. A C# event field seems like the perfect fit, for this particular case anyway.
At some point, you create the settings button, somewhere, somehow. Why not wire up the event there? Something along the lines of:
class Button
{
public Button(string label) {}
public event Action Clicked;
}
class Program
{
public static void Main(string[] args)
{
var settingsButton = new Button("Settings");
settingsButton.Clicked += () =>
{
// open settings view
};
}
}
I'd avoid things like inheritance for this problem as it adds unnecessary complexity for the wrong reasons. You should (probably) use inheritance if the overriding class changes or supplements the behavior of the class it extends (a logical progression would be object extended by Component extended by Button extended by ToggleButton) but not to create a class hierarchy that's very much tied to how your UI is built up. If you change settings access to a dropdown menu instead of a button press, you don't want to be tied to a SettingsButton class; you want to be simply able to change which event triggers the desired behavior, in this case pulling down the dropdown menu.
Related
This might sound weird, but I am just experimenting with the thought of it. I was wondering about subscribing functions to different classes. So i have a base or static location where my method is held, and without relying on inheritance, am i able to subscribe that function to an object?
For example:
Action class has a method class SendKeys
I have three objects called Textbox and Button and Textarea
Realistically i don't want them all to have access to SendKeys function, just Textbox, and Textarea. But i also don't want to copy paste the SendKeys code over and over again.
I could create a static class that takes the data and the two objects will call that static class, but that just seems like extra work and i would be creating the function anyways in order to call an external function.
The best solution i have is to just copy paste code. but i was wondering if i could subscribe specific functions. Its like the opposite of what an event and delegate can do right? Cause the subscription requires code in the class of the subscriber. I kind of think i want partial classes? I am not sure. Thoughts?
A deeper dive into the issue:
I have a bunch of different elements to work with here are some basic ones, it goes deeper when you take into account custom elements:
Button
Textbox
Textarea
MultiSelect
SingleSelect
RadioButtons
Checkboxes
MenuItems
PasswordTextboxes
ETC
Each one of these would have their own actions that can be applied. For example they all would have the same properties like GetAttribute or GetCssValue but i don't want to be sending keys to a checkbox, so i dont want to have the ability to have that function when creating inheritance. BUT, i do want other objects to have those functions. The code is lengthy and a bunch of copy pasting code is ugly. I was hoping i can subscribe functnions to objects. So i can say something like Actions.Click(Textbox) or Textbox.Click or w.e but i cannot do Actions.SendKeys(button, "fdsaf") or Button.SendKeys("fdsaf")
I'm working on a Unity project. It's a visualisation software, so most of the game mechanics are based on buttons, sliders, color-picker updating my GamesObjects.
I can't figure out how to organise my UI implementation.
Is it a good idea to apply some kind of MVC pattern to unity, any idea how to do it (I found some article about that but they weren't clear to me) ?
Currently I'm adding UI elements in the scene. An empty game objets called UIManager is holding scripts concerning the UI. Those scripts hold references to UI elements, add a listener to them and contain methods called by the event.
My approach is correct? How to improve it?
My UI Manager contain scripts like this one :
public class someMenuGUI : MonoBehaviour {
public Button enable;
public void Start()
{
enable.onClick.AddListener(Enable);
}
public voidEnable()
{
GameObject[] Objs = Object.FindObjectsOfType (typeof(GameObject)) as GameObject[];
// then do something on them
};
That's a very good question without an answer that can be considered to be universally true. However, I would like to share my approach to this.
When I write Unity code, I have two categories of users in mind: players and designers. Essentially, since almost all Unity code is contained in MonoBehaviours, and MonoBehaviours are used in the editor, you're constantly writing a tool for designers that they use to actually create a game.
Even if you don't have a designer and work alone, it's useful to think about code in this terms. This way, you have a clear separation between code space and editor space: code doesn't have to make any assumptions about what happens in the editor; instead, designer has to be able to use your components to build what they want.
So, where do you draw the line? I think that if you're going to use the MVC pattern, the separation is quite clear: the controller logic should be contained in code, but the wiring up of the actual UI elements should be in the hands of the designer. Which, finally, brings us to the code.
A great way to implement the MVC pattern is to use events instead of solid references: this way the controller and the view don't have to know each other's types, they only have to know the model. But since you want the designer to hook events up in the editor, you can't use C# delegate events. Thankfully, there's a new feature of Unity's UI system just for that: UnityEvent.
So, let's say that your script, which plays the role of the controller, has to have two-way communication with the view: from controller to the view to update the information, and from view to controller to run the user's action. Turns out, it's very simple to set up. Create a public UnityEvent (with a correct generic argument) for update of the data, public method for user action, and you're done with the code! All that designer will have to do is to set the Unity event on your script to update the UI, and to set up Unity event of UI element to call your controller's method.
I am creating buttons dynamically for a user-based app. Now I have to tell the new form what text to apply to the buttons via parameters to the form, the form then creates the buttons. Now I have an issue - the events for these buttons: What is the best mechanism to get the button click events through. I cannot access the form from the originating form, and I can only pass simple data types (and arrays).
My first thought is to use a code to reffer to the appropriate method in a static class - basically, pass an array of ints through with the names of the buttons and their onclick handler calls one method - handle(int code) -> where code is used in a giant switch statement to call the appropriate method.
But I doubt this is the best mechanism. I would prefer to create a listener of some sort that simply listens for button clicks, and should the click be unhandled, determine which button was clicked and manage it from there.
I have looked at the observer pattern and I am not entirely convinced this is the best one to follow. The problem is not that there is no solution, the problem is that I want the BEST solution.
This is in C# for monodroid - but the impact of this information should be minimal.
Thanks
Not sure to fully understand what's actually your problem, but here's how you should deal with dynamic controls and event handlers:
Button myNewButton = new Button { Text = "MyCaption" };
myNewButton.Click += (sender, e) =>
{
((Button)sender).Text = "New text here!";
// Another logic could be put here
};
If it was WPF i'd use Commanding but i don't know if it's available for monofroid.
You may look at http://www.codeproject.com/KB/dotnet/EventBroker.aspx
Currently I have two options:
Use reflection - pass a method name to the button and that button can then invoke a method based on the string value passed. Then simply create a static class where all button methods are kept.
Use a switch statement - since I can have delegates that take parameters (one of them being a SENDER object) I can easily send the sender object to a method containing a switch statement which performs an action based on that object.
In my research I have determined that the former (reflection) is preferred, espcially since the number of buttons is rather large.
REFS:
http://embeddedgurus.com/stack-overflow/2010/04/efficient-c-tip-12-be-wary-of-switch-statements/
Large Switch statements: Bad OOP?
Method Factory - case vs. reflection
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.
My question is simple: how bad is the following snippet of code? How would you do it?
CancelEventHandler _windowClosing;
private CancelEventHandler WindowClosing
{
set
{
clearEventHandlerList();
this.Closing += value;
_windowClosing = value;
/*
* if calling the method with null parameters,
* it will set up itself as the primary control on the Window
*/
_windowClosing(null,null);
}
get
{
return _windowClosing;
}
}
private readonly CancelEventHandler[] CONTROLS = null;
private int current = 0;
public InitializerForm()
{
InitializeComponent();
/*
* these are the handlers for the different controls,
* in the order of appereance to the user
*/
STATES = new CancelEventHandler[] { handler1, handler2, etc. };
WindowClosing = CONTROLS[0];
}
private void clearEventHandlerList()
{
foreach (CancelEventHandler c in CONTROLS)
{
this.Closing -= c;
}
}
private void handler1(object obj, CancelEventArgs e)
{
if (obj == null)
{
//hide every other control, but this one, also set up if necessary
}
else
{
//do something
WindowClosing = CONTROLS[++current]; // set the next control to show
e.Cancel = true;
}
}
The point would be that the code wouldn't close a form, but instead show another component on it, and the set the way to handle that (this is mobile platform, so clicking OK button on the top generates a closing event). This is because showing several forms (4 or 5) one after another to the user makes the app blink, and also very annoying, while replacing just components is much smoother. This model works, but seems very nasty, and I would like a cleaner way to handle this.
Update:
I updated the code sample so that variable names are somewhat speaky. Still, I'm convinced this is awful, (a) but not sure how much, and more importantly, (b) how to do it better.
Update 2:
So, it seems that the code is still a bit mysterious.
Now here's what the problem is:
I show the user a form, which instructs him what to do in several languages. He proceeds by clicking OK on the window. Next, I ask for his language, and then a few questions (where his/her GPS is, etc.) like this. After he could answer the questions (this shouldn't take more than a few seconds each), I show him a splash screen (I load stuff in a separate thread meanwhile), which has a picture. Showing these forms one after another makes the whole application start slow, and filled with UI lags.
Here's what I do to work around the lags: I put the content of the windows into panels, and put those panels one on another, and hide every one of them but the one that should be visible to the user. (current variable) Each of the windows does different things, so I need to change handler of the window closing event in addition. In this code the part which enables the panel is in the same function (handler1, handler2, etc.) with the part which handles the window closing event. If the arguments are null, it does the former, if it isn't (that means it was triggered by the user) it does the latter.
I need an extensible solution to this so that I can insert and remove dialogs anytime I want (the order and the pointers to the functions are stored in the CONTROLS field, and this seems to be very convenient, if you actually understand it. Although it is never easy to change the entire content of a form, there ought to be a simpler way to do this, as well a nicer one, that is what I'm looking for.
I hope this time I could explain how the model works.
I think it might be theoretically possible to make that code more delightfully diverting, perilously puckish, jovially jeopardous, cheerily chancy and unwarily whimsical but it would require some serious thought.
somehow your code makes me want to cry, i´m sorry. i read it twice and all i know about it is that it "doesStuff" with "STATES".
if you really want some help on this one you will have to work on it yourself first...
Use, XML! It's human-readable!
More seriously-
It seems like you're trying to create some sort of configuration wizard, so I'd start by researching that. Regarding your particular solution, I generally advocate very strongly against the "layered panel" approach. I do so because I maintain apps written by people who found this approach, or the related "hidden tabs on a tab control" approach, to be a good idea. It's not, and maintainers will curse your name for years to come.
That being said, what alternatives are there? Well, one alternative is what you've already dismissed because of its "flicker". I'd say that, in general, the flicker isn't that big of a deal for a quick and dirty application. It might be a good idea to make sure that your new window is called up before closing the old one, for example. (I'm assuming this is possible, I haven't developed on a mobile device.)
Another possibility might be a less-evil version of your layered panels. Instead of throwing a half-dozen panels into one form, create a separate user control for each wizard page and then add/remove the user controls to a containing form. This can avoid your flicker and will prove to be much easier to maintain because each page is in a different control. This might also ease any subsequent "Back" button functionality and make your data structures more naturally defined because those user controls will be associated with a specific logical bit of data. It's still not ideal, but it's probably good enough for a one-off solution.
A third technique, if you foresee extensive wizard modification as the product matures, might be to generalize the creation of your user controls by defining them in a more logical/declarative manner (e.g. via XML). If you dynamically generate sensible controls based on XML, then modifying the panels might be as easy as diving into your XML and doing something like:
<Questions>
<Question type="Text"> <!-- generate a textbox for the answer field -->
Favorite Color:
</Question>
<Question type="Number" range="0-255"> <!-- Maybe this is a spinner -->
The answer to life, the universe, and everything:
</Question>
</Questions>
That's just off the top of my head, and completely overkill for any one-off application, but it's a possibility.
Now, let me caveat this by saying this might work, but it may not be the answer to your real problem - that of a slow and unresponsive UI when you have a lot of forms. The real answer may be to just go ahead and do all separate forms, but have each form load its child forms in a background thread while the user is staring at the first form.
But assuming you're still set on this, I'd start off by making a separate class just to handle the Panel stacking/hierarchy. Call it PanelManager. You would instantiate the PanelManager and associate it with the main form, then add Panels to it (perhaps keyed to a String) and set the order. In the main form, have the closing handler call PanelManager.CloseCurrentPanel() and if there are no more Panels to show then it's time to close the main form.
Time for pseudo-code! Here's a quick idea for the class, i'll leave it to you to implement it:
public class PanelManager {
// constructor
public PanelManager (Form ownerForm);
// short-cut properties
public Panel this[int idx]
{ get; set; }
public int Index
{ get; set; }
// main functionality
public int AddPanel (Panel p);
public void SetPanelOrder (Panel p, int idx);
public void RemovePanel (Panel p);
public void RemovePanelAt (int idx);
// shows the first Panel
public void Show ();
// shows Panel[idx]
public void Show (int idx);
// adds the panel to the top of the stack and displays it
// returns the index of the panel
public int AddPanelAndShow (Panel p);
// hides the current panel, displays the one underneath it
// returns false if there are no more panels
public bool HideCurrentPanel ();
}
in the constructor for the main form, instantiate it by new PanelManager (this), then in the closing event handler, call panelManager.HideCurrentPanel () and then figure out whether or not you need to close it after that.