I've created simple custom control - derived from Component class:
public partial class TrialChecker : Component
{
private int _trialDays;
public int TrialDays
{
get { return _trialDays; }
set { _trialDays = value;}
}
public TrialChecker()
{
InitializeComponent();
MessageBox.Show(TrialDays.ToString());
}
public int GetTrialDays()
{
return _trialDays;
}
}
This control will be used to implement trial functionality in my application. Application (before it starts) should check trial remaining days and display notify dialog containing trial remaining days and textbox to write unlock key.
But I want to minimalise amount of code needed to wirte while using this control. So, my idea is to place trial check code inside my control and - just after control is created, it should display remaining days.
Trial period (TrialDays property) is set on user designer and it should be available to use just afeter control is created. As you can see, I tried to put this to constructor but it does not work, because constructor is called before setting TrialDays to valuje entered in user designer. And MessageBox always displays default value 0.
There is no any OnLoad or OnCreate events abailable to override. So, how can I automatically check trial status using value entered in designer?
The Component class is very simple, it just provides a way to host the component on a form at design time, giving access to its properties with the Properties window. But it has no notable useful events, using a component requires explicit code in the form. Like OpenFormDialog, nothing happens with it until you call its ShowDialog() method.
The constructor is usable but unfortunately it runs too early. The DesignMode property tells you whether or not a component runs at design time but it isn't set yet at constructor time. You'll need to delay the code and that's difficult because there are no other methods or events that run later.
A solution is to use the events of the form that you dropped the component on. Like the Load event. That requires some giddy code to coax the designer to tell you about the form. That technique is used by the ErrorProvider component, it requires exposing a property of type ContainerControl and overriding the Site property setter. Like this:
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
public partial class Component1 : Component {
private ContainerControl parent;
[Browsable(false)]
public ContainerControl ContainerControl {
get { return parent; }
set {
if (parent == null) {
var form = value.FindForm();
if (form != null) form.Load += new EventHandler(form_Load);
}
parent = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
void form_Load(object sender, EventArgs e) {
if (!this.DesignMode) {
MessageBox.Show("Trial");
}
}
}
The code is inscrutable, but you can be pretty sure it is reliable and stable because this is what the ErrorProvider component uses. Be sure to call Environment.Exit() when the trial period has ended, an exception isn't going to work well.
Related
I am creating a user interface for an iOS app and I am looking for the correct way to create a reusable custom control. I got it generally working when running the app, but at design time setting my "exported" properties has no visible effect in the designer. I think I am doing something fundamentally wrong, so perhaps someone could give me guidance
What I am doing:
I have created a subclass of UIControl.
In the constructor I call an Initialize method.
In the Initialize method, I add several subviews and constraints to layout them within my control
Here is some hollowed out code that shows the above:
[Register("RangedValueSelector"), DesignTimeVisible(true)]
public sealed class RangedValueSelector : UIControl
{
public RangedValueSelector(IntPtr p)
: base(p)
{
Initialize();
}
public RangedValueSelector()
{
Initialize();
}
public int HorizontalButtonSpacing
{
get { return _horizontalButtonSpacing; }
set
{
_horizontalButtonSpacing = value;
}
}
[Export("LabelBoxVerticalInset"), Browsable(true)]
public int LabelBoxVerticalInset
{
get
{
return _labelBoxVerticalInset;
}
set
{
_labelBoxVerticalInset = value;
}
}
private void Initialize()
{
//Code that creates and add Subviews
//Code that creates and add the required constraints, some of which should depend on the design time properties
}
}
So the control works perfectly fine if I set the exported properties via the designer, however they do not have an immediate effect in the designer itself.
What is the suggested way of having design-time settable properties that change the constraint values? I would like to avoid having to recreate all the subviews each time someone in the code or in the designer sets a property.
You are missing constructor with RectangleF which is used by designer.
public RangedValueSelector(RectangleF bounds):base(bounds){}
The rest seems to be correct.
I'm trying to work with Windows Forms and User Controls and thus far it's been nothing but a headache. I can't make the form or the controls static because the designer doesn't like that and when I use Singleton on my form and controls, the designer still throws errors at me.
My FormMain:
public partial class FormMain : Form
{
private static FormMain inst;
public static FormMain Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new FormMain();
return inst;
}
}
private FormMain()
{
inst = this;
InitializeComponent();
}
MainScreen.cs:
public partial class MainScreen : UserControl
{
private static MainScreen inst;
public static MainScreen Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new MainScreen();
return inst;
}
}
private MainScreen()
{
inst = this;
InitializeComponent();
}
If the constructor of MainScreen is public the program runs, but when I change it to private I now get an error in FormMain.Designer.cs saying "'Adventurers_of_Wintercrest.UserControls.MainScreen.MainScreen()' is inaccessible due to its protection level". It points to this line:
this.controlMainScreen = new Adventurers_of_Wintercrest.UserControls.MainScreen();
I think this is the instance of the class that the designer makes by default. Should I ditch the designer? Or is there a way around this? Or is there another way to make class properties accessible without using Singleton (since I can't seem to make the form or controls static)? Any help would be greatly appreciated.
You need to keep a reference to each instance of each form if you want to access the public properties of the instantiated form.
One way is to have a class with a static variable for each type of form:
class FormReferenceHolder
{
public static Form1 form1;
public static Form2 form2;
}
This way you would set the static variable whenever you instantiate a form, and then you can access that variable from anywhere in the program. You can go one step further with this and use properties that set up the form if it doesn't already exist:
class FormReferenceHolder
{
private static Form1 form1;
public static Form1 Form1
{
get
{
if (form1 == null) form1 = new Form1();
return form1 ;
}
}
}
...
static void Main()
{
Application.Run(FormReferenceHolder.Form1 );
}
I think I answered a previous question about this, which looks like it is what got you started down this route. The first point is that I wasn't recommending this pattern specifically, just trying to teach you more about how software developers can manage scope.
That said, the problem you are facing isn't insurmountable. You could hobble a public constructor by throwing an exception at runtime and not at design time, for instance, and modify Program.cs to use the static Instance instead of manually constructing the form.
But.
As I said in the other question, the better option would be to change architecture so that you don't need your library code to directly manipulate the GUI in the first place.
You can do this either by just having the GUI ask the library questions when it thinks it needs new data (simple functions) or by letting the GUI be notified when something needs to change. Either method would be better than having the library fiddle with labels directly.
A good place to start would be something like an MVC (model-view-controller) architecture, which I was alluding to in my previous answer. It might be best, though, to give us an idea of what your high-level program structure looks like now on a bit more detail. What are the main classes you are using in your system (not just the ones you've mentioned so far)? What is the main responsibility of each, and where does each live? Then our recommendations could be a little more specific.
EDIT
So, I have mocked up a quick demo of a possible alternative architecture, based on your comment.
I have the following in my project:
FormMain (Form)
TitleScreen (UserControl)
InGameMenu (UserControl)
MainScreen (UserControl)
GameController (Class)
GameModel (Class)
I didn't use Date and LoadSave, for now.
FormMain simply has an instance of each UserControl dropped on it. No special code.
GameController is a singleton (since you tried to use this pattern already and I think it would be helpful for you to try using a working version of it) that responds to user input by manipulating the model. Note well: you don't manipulate the model directly from your GUI (which is the View part of model-view-controller). It exposes an instance of GameModel and has a bunch of methods that let you perform game actions like loading/saving, ending a turn, etc.
GameModel is where all your game state is stored. In this case, that's just a Date and a turn counter (as if this were going to be a turn-based game). The date is a string (in my game world, dates are presented in the format "Eschaton 23, 3834.4"), and each turn is a day.
TitleScreen and InGameMenu each just have one button, for clarity. In theory (not implementation), TitleScreen lets you start a new game and InGameMenu lets you load an existing one.
So with the introductions out of the way, here's the code.
GameModel:
public class GameModel
{
string displayDate = "Eschaton 23, 3834.4 (default value for illustration, never actually used)";
public GameModel()
{
// Initialize to 0 and then increment immediately. This is a hack to start on turn 1 and to have the game
// date be initialized to day 1.
incrementableDayNumber = 0;
IncrementDate();
}
public void PretendToLoadAGame(string gameDate)
{
DisplayDate = gameDate;
incrementableDayNumber = 1;
}
public string DisplayDate
{
get { return displayDate; }
set
{
// set the internal value
displayDate = value;
// notify the View of the change in Date
if (DateChanged != null)
DateChanged(this, EventArgs.Empty);
}
}
public event EventHandler DateChanged;
// use similar techniques to handle other properties, like
int incrementableDayNumber;
public void IncrementDate()
{
incrementableDayNumber++;
DisplayDate = "Eschaton " + incrementableDayNumber + ", 9994.9 (from turn end)";
}
}
Things to note: your model has an event (in this case, just one of type EventHandler; you could create more expressive types of events later, but let's start simple) called DateChanged. This will be fired whenever DisplayDate changes. You can see how that happens when you look at the property definition: the set accessor (which you will NOT call from your GUI) raises the event if anyone is listening. There are also internal fields to store game state and methods which GameController (not your GUI) will call as required.
GameController looks like this:
public class GameController
{
private static GameController instance;
public static GameController Instance
{
get
{
if (instance == null)
instance = new GameController();
return instance;
}
}
private GameController()
{
Model = new GameModel();
}
public void LoadSavedGame(string file)
{
// set all the state as saved from file. Since this could involve initialization
// code that could be shared with LoadNewGame, for instance, you could move this logic
// to a method on the model. Lots of options, as usual in software development.
Model.PretendToLoadAGame("Eschaton 93, 9776.9 (Debug: LoadSavedGame)");
}
public void LoadNewGame()
{
Model.PretendToLoadAGame("Eschaton 12, 9772.3 (Debug: LoadNewGame)");
}
public void SaveGame()
{
// to do
}
// Increment the date
public void EndTurn()
{
Model.IncrementDate();
}
public GameModel Model
{
get;
private set;
}
}
At the top you see the singleton implementation. Then comes the constructor, which makes sure there's always a model around, and methods to load and save games. (In this case I don't change the instance of GameModel even when a new game is loaded. The reason is that GameModel has events and I don't want listeners to have to unwire and rewire them in this simple sample code. You can decide how you want to approach this on your own.) Notice that these methods basically implement all the high-level actions your GUI might need to perform on the game state: load or save a game, end a turn, etc.
Now the rest is easy.
TitleScreen:
public partial class TitleScreen : UserControl
{
public TitleScreen()
{
InitializeComponent();
}
private void btnLoadNew(object sender, EventArgs e)
{
GameController.Instance.LoadNewGame();
}
}
InGameMenu:
public partial class InGameMenu : UserControl
{
public InGameMenu()
{
InitializeComponent();
}
private void btnLoadSaved_Click(object sender, EventArgs e)
{
GameController.Instance.LoadSavedGame("test");
}
}
Notice how these two do nothing but call methods on the Controller. Easy.
public partial class MainScreen : UserControl
{
public MainScreen()
{
InitializeComponent();
GameController.Instance.Model.DateChanged += Model_DateChanged;
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Model_DateChanged(object sender, EventArgs e)
{
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Instance_CurrentGameChanged(object sender, EventArgs e)
{
throw new NotImplementedException();
}
private void btnEndTurn_Click(object sender, EventArgs e)
{
GameController.Instance.EndTurn();
}
}
This is a little more involved, but not very. The key is, it wires up the DateChanged event on the model. This way it can be notified when the date is incremented. I also implemented another game function (end turn) in a button here.
If you duplicate this and run it, you'll find that the game date is manipulated from lots of places, and the label is always updated properly. Best of all, your controller and model don't actually know anything at all about the View-- not even that it's based on WinForms. You could as easily use those two classes in a Windows Phone or Mono context as anything else.
Does this clarify some of the architecture principles I and others have been trying to explain?
In essence the problem is that when the application runs, it's going to try to instantiate the main form-window. But by using the Singleton pattern, you're essentially forbidding the application from doing that.
Take a look at the sample code here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.aspx
You'll notice in particular this section:
[STAThread]
public static void Main()
{
// Start the application.
Application.Run(new Form1());
}
Notice how the program is trying to instantiate Form1. Your code says, nah, I don't really want that since you mark the constructor as private (same holds true for static forms as well). But that's counter to how windows forms is supposed to work. If you want a singleton form-window, just don't make any more. Simple as that.
I would like to retrieve all components which are part of a Form's or UserControl's components collection.
The components collection is added by VS winforms designer. The components variable is private and the problem is how to retrieve all components from all descendants. I would like to have a method which returns list of components throught the type hierarchy. For example let's say I have MyForm (descendant of BaseForm) and BaseForm (descendant of Form). I would like to put method "GetComponents" which returns components of both MyForm and BaseForm.
Do you suggest any other option than using the reflection?
Some time ago I have implemented the solution in which I created custom base form and control implementations, adding one property and overriding the OnLoad method:
public partial class FormBase : Form
{
public FormBase ()
{
this.InitializeComponent();
}
protected ConsistencyManager ConsistencyManager { get; private set; }
protected override void OnLoad(System.EventArgs e)
{
base.OnLoad(e);
if (this.ConsistencyManager == null)
{
this.ConsistencyManager = new ConsistencyManager(this);
this.ConsistencyManager.MakeConsistent();
}
}
}
The ConsistencyManager class finds all controls, components and also supports search of custom child controls within specific control. Copy/paste of code from MakeConsistent method:
public void MakeConsistent()
{
if (this.components == null)
{
List<IComponent> additionalComponents = new List<IComponent>();
// get all controls, including the current one
this.components =
this.GetAllControls(this.parentControl)
.Concat(GetAllComponents(this.parentControl))
.Concat(new Control[] { this.parentControl });
// now find additional components, which are not present neither in Controls collection nor in components
foreach (var component in this.components)
{
IAdditionalComponentsProvider provider = GetAdditinalComponentsProvider(component.GetType().FullName);
if (provider != null)
{
additionalComponents.AddRange(provider.GetChildComponents(component));
}
}
if (additionalComponents.Count > 0)
{
this.components = this.components.Concat(additionalComponents);
}
}
this.MakeConsistent(this.components);
}
If anyone would like full sample or source let me know.
Best regards,
Zvonko
PS: In the same manner I have also created the performance counter that counts number of invocations on main thread.
I'm designing a UI manager class that will manage all my UI elements (this is for an XNA game, so there is no existing UI framework) but I'm wondering how to deal with situations where I want the UI manager to have special access to data in the UI elements that other classes can't access.
For example, I want to have a SetFocus method to focus a specific element and this method needs to ensure that the previously focused element loses focus. The individual UI elements themselves can't handle this because they don't have access to the list of UI elements, which means the manager has to handle it, but how can I allow the manager and only the manager to set the variable on a UI element?
The thought occurs to me to just store the currently focused element on the manager, however I don't particularly like that solution and, given a single UI element, I would like to query it to find out if it has focus. Even if it makes sense to store the currently focused element on the manager since its just a single variable, there are other things I need to deal with that would require arrays to associate the data with the elements if its stored on the manager, and that just seems to defeat the purpose of OOP.
I know I don't need to have it so that the manager is the only one with access to this data, I could just make all the data public, but that's not good design...
What you are looking for is a C# equivalent of the C++ friend concept. As you read in the linked post 'the closest that's available (and it isn't very close) is InternalsVisibleTo' (citing Jon Skeet). But using InternalsVisibleTo in order to accomplish what you want would mean you'd have to break up your complete application into a library per class, which would probably create a DLL hell.
Building upon MattDavey's example got me:
interface IFocusChecker
{
bool HasFocus(Control control);
}
class Manager : IFocusChecker
{
private Control _focusedControl;
public void SetFocus(Control control)
{
_focusedControl = control;
}
public bool HasFocus(Control control)
{
return _focusedControl == control;
}
}
class Control
{
private IFocusChecker _checker;
public Control(IFocusChecker checker)
{
_checker = checker;
}
public bool HasFocus()
{
return _checker.HasFocus(this);
}
}
Whether a Control has focus is now only stored in the Manager and only the Manager can change the focused Control.
A little example how to put things together, for completeness:
class Program
{
static void Main(string[] args)
{
Manager manager = new Manager();
Control firstControl = new Control(manager);
Control secondControl = new Control(manager);
// No focus set yet.
Console.WriteLine(string.Format("firstControl has focus? {0}",
firstControl.HasFocus()));
Console.WriteLine(string.Format("secondControl has focus? {0}",
secondControl.HasFocus()));
// Focus set to firstControl.
manager.SetFocus(firstControl);
Console.WriteLine(string.Format("firstControl has focus? {0}",
firstControl.HasFocus()));
Console.WriteLine(string.Format("secondControl has focus? {0}",
secondControl.HasFocus()));
// Focus set to firstControl.
manager.SetFocus(secondControl);
Console.WriteLine(string.Format("firstControl has focus? {0}",
firstControl.HasFocus()));
Console.WriteLine(string.Format("secondControl has focus? {0}",
secondControl.HasFocus()));
}
}
Having a variable on a control itself which is implicitly relative to the state of other controls is probably a poor design decision. The concept of "focus" is of concern at a much higher level, either a window or better yet, a user (the user is the one doing the focusing). So it's at the window or user level that a reference to the focused control should be stored, but in addition to that, there ought to be a way for controls to be notified when they gain/lose focus from the user - this could be done via events on the user/manager or by any standard notification pattern.
class Control
{
public Boolean HasFocus { get; private set; }
internal void NotifyGainedFocus()
{
this.HasFocus = true;
this.DrawWithNiceBlueShininess = true;
}
internal void NotifyLostFocus()
{
this.HasFocus = false;
this.DrawWithNiceBlueShininess = false;
}
}
class User // or UIManager
{
public Control FocusedControl { get; private set; }
public void SetFocusOn(Control control)
{
if (control != this.FocusedControl)
{
if (this.FocusedControl != null)
this.FocusedControl.NotifyLostFocus();
this.FocusedControl = control;
this.FocusedControl.NotifyGainedFocus();
}
}
}
Disclaimer: I've never written a UI library and I may be talking complete nonsense..
I have a non-visual component which manages other visual controls.
I need to have a reference to the form that the component is operating on, but i don't know how to get it.
I am unsure of adding a constructor with the parent specified as control, as i want the component to work by just being dropped into the designer.
The other thought i had was to have a Property of parent as a control, with the default value as 'Me'
any suggestions would be great
Edit:
To clarify, this is a component, not a control, see here :ComponentModel.Component
[It is important to understand that the ISite technique below only works at design time. Because ContainerControl is public and gets assigned a value VisualStudio will write initialization code that sets it at run-time. Site is set at run-time, but you can't get ContainerControl from it]
Here's an article that describes how to do it for a non-visual component.
Basically you need to add a property ContainerControl to your component:
public ContainerControl ContainerControl
{
get { return _containerControl; }
set { _containerControl = value; }
}
private ContainerControl _containerControl = null;
and override the Site property:
public override ISite Site
{
get { return base.Site; }
set
{
base.Site = value;
if (value == null)
{
return;
}
IDesignerHost host = value.GetService(
typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
IComponent componentHost = host.RootComponent;
if (componentHost is ContainerControl)
{
ContainerControl = componentHost as ContainerControl;
}
}
}
}
If you do this, the ContainerControl will be initialized to reference the containing form by the designer. The linked article explains it in more detail.
A good way to see how to do things is to look at the implementation of Types in the .NET Framework that have behaviour similar to what you want with a tool such as Lutz Reflector. In this case, System.Windows.Forms.ErrorProvider is a good example to look at: a Component that needs to know its containing Form.
I use a recursive call to walk up the control chain. Add this to your control.
public Form ParentForm
{
get { return GetParentForm( this.Parent ); }
}
private Form GetParentForm( Control parent )
{
Form form = parent as Form;
if ( form != null )
{
return form;
}
if ( parent != null )
{
// Walk up the control hierarchy
return GetParentForm( parent.Parent );
}
return null; // Control is not on a Form
}
Edit: I see you modified your question as I was typing this. If it is a component, the constructor of that component should take it's parent as a parameter and the parent should pass in this when constructed. Several other components do this such as the timer.
Save the parent control as a member and then use it in the ParentForm property I gave you above instead of this.
You will have to set the parent container some how. Your component is just a class, that resides in memory just like everything else. It has no true context of what created it unless something tells you that it did. Create a Parent control property and set it.
Or simply derive from control and use FindForm(). Not all controls must have a visible component
If the componenet is managing other visual controls, then you should be able to get to the parent through them.
I found this solution which does not need the input. For C# I implemented it this way:
public partial class RegistryManager : Component, ISupportInitialize
{
private Form _parentForm;
public Form ParentForm
{
get { return _parentForm; }
set { _parentForm = value; }
}
// Etc....
#region ISupportInitialize
public void BeginInit() { }
public void EndInit()
{
setUpParentForm();
}
private void setUpParentForm()
{
if (_parentForm != null) return; // do nothing if it is set
IDesignerHost host;
if (Site != null)
{
host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
if (host.RootComponent is Form)
{
_parentForm = (Form)host.RootComponent;
}
}
}
}
#endregion
}
This way allows the set ParentForm by user, but it is set by parent form as Default.
I hope it helps you.
Try This ....
private Form GetParentForm(Control parent)
{
if (parent is Form)
return parent as Form;
return parent.FindForm();
}
Call GetParentForm(this.Parent) from component
I think you want to use the Site property of the IComponent. It's more or less an equivalent to the Parent property.
Thanks Rob, I used your solution in a VB.Net program, looks like this:
''' <summary>
''' Returns the parent System.Windows.form of the control
''' </summary>
''' <param name="parent"></param>
''' <returns>First parent form or null if no parent found</returns>
''' <remarks></remarks>
Public Shared Function GetParentForm(ByVal parent As Control) As Form
Dim form As Form = TryCast(parent, Form)
If form IsNot Nothing Then
Return form
End If
If parent IsNot Nothing Then
' Walk up the control hierarchy
Return GetParentForm(parent.Parent)
End If
' Control is not on a Form
Return Nothing
End Function
Referenced it on my blog:
http://www.dailycode.info/Blog/post/2012/07/03/How-to-get-a-user-controls-parent-form-(Windows-forms).aspx
If the component related Form is the active Form you may get it by Form.ActiveForm.
A improvement of above is:
public static Form ParentForm(this Control ctrl) => ctrl as Form ?? ctrl.FindForm();