Adding a visual behavior to multiple forms - c#

I want to add a specific behavior to multiple forms. In this case its a balloon message that is triggered when a field fails input validation. The easiest solution I could come up with was making it a static class and calling it in the failure condition of each field's onvalidate event.
public static class BalloonMessage
{
private static ToolTip _toolTip = new ToolTip()
{
Active = false,
IsBalloon = true
};
public static void Show(string message,Control control)
{
if (!_toolTip.Active)
{
//4 year old bug in tooltip doesn't place balloon "tail" correctly
// when first attached to a control. Microsoft still hasn't fixed it.
_toolTip.Show(message, control);
_toolTip.Active = true;
_toolTip.Show(message, control);
}
}
public static void Clear()
{
_toolTip.Active = false;
}
}
private void textBox1_Validating(object sender, CancelEventArgs e)
{
if (textBox1.Text.Contains(" "))
{
BalloonMessage.Show(String.Format("Field cannot contain spaces"), textBox1);
e.Cancel = true;
}
else
{
BalloonMessage.Clear();
}
}
This allows me to use the BalloonMessage in any form without requiring an explicit dependency but I'm wondering if this is the best approach. The sample code doesn't show it but the production code uses numerous interrelated MVP triads. The validation is being done in the presenters, which don't have direct access to any of the forms' controls. So I'll have to pass the validation result and any error message back to the view for displaying in a balloonmessage.
By the way, if your wondering why I'm using a tooltip instead of wrapping EM_SHOWBALLOONTIP its because I wanted this functionallity on Windows 2000 and EM_SHOWBALLOONTIP was added in XP. Tooltip can be displayed as a balloon in 2000 as long as IE 5.5 or greater is installed (all my Win2K clients are using IE 6). I'm simply keeping it inactive until needed to inhibit its default on hover behavior.

I would say that this is probably the way to go. It follows the MessageBox functionality built in to .NET.

You could create a base BalloonTipForm that your other forms inherit from with the elements that you need. You still wouldn't be able to handle validation events for specific controls in it, but you could certainly have general methods for displaying it.
And I'm sure there's some sort of way you could rig it to observe your actual validation so that you may not have to explicitly call the balloon show/hide methods. (I don't know whether the actual validation in your presenters would require multiple such calls or can be just a few.)
Your own solution doesn't look too bad, either. You could easily mix the 2.

Related

I want to run a code snippet the first time the form loads

I have a series of Windows Forms that act like a web based application. I have a form that sets a label's text to a random number and I'm trying to pass that number across other forms and be sure it updates everywhere. I don't have the ability to create a database, so that's why I'm doing that.
The issue I have is that when I move around the application and use a button to take me back to the first page that would get the random number, the code runs again and the number changes.
private void goToPage2_Click(object sender, EventArgs e)
{
this.Hide();
var form3 = new FORM3();
form3.ShowDialog();
this.Close();
}
I've commented out the Close and tried Show instead of ShowDialog, but the app crashes.
Basically I just need to figure out how to go about detecting if the form has already been created once in the application's life for that time and only have the random code run that time and not every time I come back to the page via just using the app like I want it used.
I'm using Windows Forms to save time as it's just for demonstrational purposes and don't want to deal with CSS and Bootstrap.
Thanks.
Run it in the Form's Shown event handler.
From the link:
The Shown event is only raised the first time a form is displayed
or the Load event handler.
From that link:
Occurs before a form is displayed for the first time.
Depending on when exactly you want it executed.
If you are creating new Forms every time and just want to know whether something happened during the course of the application execution - have a public static bool variable, set it when that code is executed, and check for it before that. Something like:
if(!Class1.theFlag)
{
Class1.theFlag = true;
//run your code here.
}
If you can't store variables in a database and need to pass those values amongst Windows Forms, simply add a new class to the project.
Name the class whatever you want. I named my class data as well as made it a static class.
Then add methods for get and set.
public static int someNum
{
get; set;
} = 0;
public static string someString
{
get; set;
} = "";
So, now you can just set those values to data.someNum or data.someString instead of having to check this or that. Much quicker than so many examples I've encountered here and much less code.
I would like to thank Ispiro for his educating me here though. Thanks man.

Managing prerequisites with MEF and Caliburn Micro

Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.
I thought about this setup:
class Big
{
[ImportMany]
public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
public void Initialize(){...}
}
and
interface IBigPrerequisite
{
public bool IsBusy {...}
public bool Allow {...}
public void StartChecking();
}
Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.
But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?
EDIT - since the question seemed too vague
I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:
Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
pre.PropertyChanged += (s, args) =>
{
if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
{
allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
count++;
if(count == big.Prerequisites.Count() && allow)
windowManager.ShowWindow(big);
}
}
pre.StartChecking();
}
Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.
I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.
Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.
You are mixing concepts here.
Active view management in Caliburn.Micro is handled by the Conductor class. A Conductor-derived ViewModel can display a large number of Screen-derived ViewModels (or other Conductors). Available items are stored in the Items property.
You can find a much better description at "Screens, Conductors and Composition"
MEF has nothing to do with the Conductors and the composition mechanism, although it can be used to pass a list of items to a conductor. You can define an [ImportMany] constructor parameter or public property that receives the Screens to display during initializations and store them in the conductor's Items property.
Using a constructor parameter is more elegant, as you won't have to copy the items from your property's setter to the Items property.
Finally, you shouldn't display messages when creating your views and viewmodels. This is something that should be left for a later step, eg. during the Activate method. The Conductors and MEF get the parts together and build the UI. Executing actions and talking to the user should be done only after the composition step has finished.
I am going to answer this question myself detailing how I ended up solving this.
I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.
It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.
It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.
The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.
Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.

WPF: property similar to WinForms Modified

In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.

WPF app - how to handle modes/statuses of controls in a window?

What's the best way (in a WPF app, C#) of implementing control behaviour that is based around the current status/mode for the window?
For example let's say the modes might be simply OFFLINE, ONLINE for example. So when OFFLINE you want the configuration entry controls to be active, however as soon as processing starts (ONLINE) then you want these controls to be grey'ed out.
Any suggestions re pattern/approach to manage this? I'm wondering if there is a publish/subscribe approach that would be best, or just create a helper method like "SetStatus" and make all the calls to controls from here.
thanks
I would bind the IsEnabled property of whatever contains your configuration entry controls to a boolean value that inspects the current status/mode.
The downside to this approach is that you will have to make a call to this property every time the Mode is changed. But this can be made easier by using properties that wrap around a member variable
//Assumes your mode enum is defined and named WindowModes
private WindowModes m_CurrentMode;
public WindowModes
{
get { return m_CurrentMode; }
set
{
m_CurrentMode = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CanConfigure"));
}
}
public bool CanConfigure
{
return(WindowMode == WindowModes.Online)
}
Of course if your Mode IS boolean such as ONLINE/OFFLINE. then you could simply wrap that value the same way.
This approach of course has various scalability issues and is quite class restrictive, but I've found it useful in some scenarios.

How can I enable/disable some controls among multiple controls under various different conditions?

How can I enable/disable some controls among multiple controls under various different conditions?
Let's say, there is a GUI with some rows, each represent a person. There are also some buttons, representing some actions, say, "Stand, Sit, Walk, Jump, Eat, Watch TV, Wake, Sleep" and there are some conditions, like if someone is sitting he can eat and watch TV (i.e. enable those button) but can't jump (disable it), if someone is standing he can't sleep, and so on.
Also, the state change is not solely based on a button click. Like, he might just wake up himself after some time or, say, after he is finished eating.
It seems that the most naive way is to write the .Enabled = true/false; code for n states X m buttons times, and check it for every user or non user triggered state change. Is there some better/faster/less-error-prone way to do that?
Also, what are these sorts of things called?
It'll depend on whether you're using WPF or WinForms.
WPF lets you databind the Enabled property, so you can declaratively say when it should be enabled, and as long as the right property-changed events are firing, it'll just happen.
With WinForms, yes, setting .Enabled is the way to go. The simplest thing is to write one method called e.g. UpdateEnabled() that updates Enabled on all of your controls based on your rules (if jumping, then btnEat should be disabled), then call that method whenever the state changes.
Since not all state changes are in response to GUI events, you probably want a model object that maintains state and fires an event whenever the state changes. Then whenever that event fires, you can call your UpdateEnabled() method to refresh the GUI based on the new state.
If your needs are simple, that's all you'd need to do. If your app gets more complicated, you'd want to look into patterns like Model-View-Presenter -- the Presenter would be the class that knows, based on the current state, which actions are enabled and which are disabled.
I would bind the Enabled properties to Can* (CanWalk, CanJump, etc.) properties of the class, implement INotifyPropertyChanged, and check each potentially affected property when the object's state changes.
The advantage of this method is the Person class and the UI don't need to know anything about each other. Also, implementing INotifyPropertyChanged eliminates superfluous polling of the class's properties after every state change.
If you don't want to use complex databinding, you can still listen for the PropertyChanged events and update the UI manually.
For example:
partial class Person : INotifyPropertyChanged
{
bool _IsSleeping, _IsSitting;
public bool IsSleeping
{
get { return _IsSleeping; }
set
{
if(_IsSleeping != value)
{
_IsSleeping = value;
OnIsSleepingChanged();
}
}
}
public bool IsSitting
{
get { return _IsSitting; }
set
{
if(_IsSitting != value)
{
_IsSitting = value;
OnIsSittingChanged();
}
}
}
protected virtual void OnIsSleepingChanged()
{
NotifyPropertyChanged("IsSleeping");
CheckCanJumpChanged();
}
protected virtual void OnIsSittingChanged()
{
NotifyPropertyChanged("IsSitting");
CheckCanJumpChanged();
}
bool CanJump_Old;
public bool CanJump { get { return !(IsSleeping || IsSitting); } }
void CheckCanJumpChanged()
{
if(CanJump != CanJump_Old)
{
CanJump_Old = CanJump;
NotifyPropertyChanged("CanJump");
}
}
//INotifyPropertyChanged helper method
private void NotifyPropertyChanged(String prop)
{
var hand = PropertyChanged;
if (hand != null)
hand(this, new PropertyChangedEventArgs(prop));
}
}
The term you are looking for is state machine.
You can take a look at SimpleStateMachine - C# State Machine Library - Boo and Rhino DSL.

Categories