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.
Related
I recently made a very simple app in WPF that simply reads data from a few TextBoxes and updates records in an SQL Server database. I also put back and forward buttons to allow the user to scroll through the available records. Everytime the user clicks Next on the app, the UI gets updated with the values from the new record through a method I called updateControls(), which looks like this:
private void updateControls()
{
IQueryable<Comment> query = from t in container.Comment
where t.Id == browseIndex
select t;
if (query.Count<Comment>() > 0)
{
currentComment = query.First<Comment>();
txtID.Text = currentThought.Id.ToString();
txtComment.Text = currentComment.thought;
txtDate.DisplayDate = currentComment.date;
txtDate.Text = currentComment.date.ToString();
}
}
This is simple, and it works like a charm. But I recently discovered the world of data-binding, where you can supposedly eliminate all this boilerplate code of manually updating controls and have them update themselves whenever the model changes.
After much experimentation and reading through various tutorials, I find that, for this to work, my data object must implement the INotifyPropertyChanged interface, which means need to use explicit setters on the properties I wish to update on my UI, like this:
public class Comment: INotifyPropertyChanged {
private string comment;
public event PropertyChangedEventHandler PropertyChanged;
public string Comment { get { return this.comment;}
set {
this.comment = value;
NotifyPropertyChanged("Comment");
}
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null ) this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
This is a lot more code than simply manually updating my UI with the data I want. Also, since this class is part of an Entity Model, the INotifyPropertyChanged interface has to be implemented in a class apart from the model classes, since model classes get regenerated when the model is updated. Which leads me to my question: why ever would I want to use data-binding in a real world application when it is much simpler to simply update my UI manually? Or is there an alternative way to do this that I'm not seeing?
The MVVM pattern dissociates the GUI logic from the core logic.
You can have the same model for several totally different controls and on the other way have one complex control leverage on several totally different models (the ViewModel is just the glue).
If you work on a team, you may have one guy working on the GUI part and another one dedicated to databases.
The database (model) is no more enslaved by the way you show the data, as long as the ViewModel notifies its changes, it'll be up to the View to decide to catch it or not (with a simple binding)
when you work with datatemplate, everything will make a lot more sense because it'll be VERY easy to render complex
There are many reasons why this pattern is great, there are plenty of articles on internet
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.
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.
First I'm not mad, because I use MVVM in WinForms-) I know about MVP (Model View Presenter) pattern and its variants. When I started this project I was going to learn WPF and use it, but I'm forced to rush program development, and have no time to learn WPF, so I have to write it in WinForms which I know well.
So in short I have a large data oriented smart client application, which is close to finish, I have all Models and ViewModels done (Infrastructure, Domain, Presentation done) UI is done too, now I only need to wire UI to ViewModels.
First I started wiring it using the standard winforms way (BindingSources, and simple databinding) but when I did 30-50% of binding I found out that my program works very slow, I have like 100-150 bound properties total so far, 30 of them are domain root entity (aggregate root) bindings to its EditForm. So databinding doesn't work well in this situation, lots of unnecessary updates, cascade updates of entire view when something small changes, unclear behavior, and other ugly stuff. It smells like very unreliable code, on which I have little control.
So I began to rewrite wiring as pure clean WinForms code (subscribing to PropertyChange and ListChanged events, and setting ViewModels property on my own from UI). Lot's of code to write but it works much faster, I have full control on this, and it feels much more reliable.
So what's your thoughts on this guys?
Anyone had such experience? What's your verdict on "To DataBind or Not"?
You might want to take a look at Truss. It provides a WPF-style binding manager that works on POCOs. It makes using MVVM with Windows Forms much more effective.
Using data-binding in WinForms is really painful, and subscribing to INotifyPropertyChanged events and doing things manually is overkill. I really like MVVM even on WinForms for it's great testability and maintainability but not at a price of 3X times more code to write. So for new code I use now combined View+ViewModel.
Another possibility is to use a inherited BindingSource component for data-binding in WinForms.
For example: http://ingebrigtsen.info/2010/08/31/mvvm-in-windows-forms/.
It works smoothly even in NET CF Environments.
I have modified the implementation to achieve two goals:
an easy databinding support for my ViewModels through WinForms designer
multithreading support with control.Invoke because the default BindingSource doesn't support it. Now it reacts to PropertyChanged events from a background thread.
Here is my simple ViewModelBindingSource class:
public class ViewModelBindingSource : BindingSource
{
private readonly Control _control = new Control();
private object _viewModel;
private Type _viewModelType;
public ViewModelBindingSource()
{
}
public ViewModelBindingSource(IContainer container)
: base(container)
{
}
public ViewModelBindingSource(object dataSource, string dataMember)
: base(dataSource, dataMember)
{
}
public object ViewModel
{
get { return _viewModel; }
set { _viewModel = value; }
}
public Type ViewModelType
{
get { return _viewModelType; }
set
{
if (value != null)
{
// save the type of our viewmodel
_viewModelType = value;
// create an instance of our viewmodel - so we don't need codebehind
_viewModel = Activator.CreateInstance(_viewModelType);
// add the viewmodel instance to the internal IList collection of the bindingsource
Add(_viewModel);
// move to the first element
MoveFirst();
// set the datasource of the binding source to the first element
// this is necessary for data binding of all windows forms controls
DataSource = this[0];
}
}
}
/// <summary>
/// Pass the call to the main thread for windows forms
/// This is needed for multithreading support.
/// </summary>
/// <param name="e"></param>
protected override void OnListChanged(ListChangedEventArgs e)
{
if (_control != null && _control.InvokeRequired)
_control.Invoke(new Action<ListChangedEventArgs>(OnListChanged), e);
else
{
base.OnListChanged(e);
}
}
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.