Windows Forms : Custom Events vs. Exposed Properties for composite controls - c#

Say I have a composite control in which I have a ListBox control which lists, for example, employees, and another control which contains multiple TextBox controls that will contains the employee's details.
When an employee is selected from the ListBox control, I need to pass an Employee object to the "detail" control, then assign the Text property of every TextBox control to their relative property of the Employee object.
I have two solutions to pass the Employee object to the "detail" control but I am not sure of which is the best.
Solution 1 : Expose a Employee property in the "detail" control so when an employee is selected, I could do detailControl.Employee = selectedEmployee.
Solution 2 : Expose an event in the main control and trigger it when an employee is selected. The "detail" control would subscribe to that event and receive the Employee object through the event's eventargs.
I know that both method will work just fine. I am just unsure of what is best to use.
Some say that you should pass data between controls with custom events, that it is a best loosely-coupled approach.
Some say that implementing custom events takes more time because you have to create them, add the properties to it, etc. so going with exposed properties is faster and simpler.
What do you suggest ?

Well, in my ideal world you would have a controller of some kind.
The main control would raise an event to which the controller would listen. The controller would then decode who should be notified, i.e the detail control.
This decouples the UI components entirely, providing the usual benefits, including facilitated unit testing.

Related

WPF- MEF UX binding

WPF newb here.
Consider the following situation
Parent user control A
Parent control has a placeholder / slot that
these MEF extension User control can be loaded into dynamically.
All MEF extensions that provide a User control implement a specific interface. This includes a boolean that they can set to indicate an operation is complete.
Parent A has a button that needs to be enabled when the specific property(mentioned in the point above) is set to true.
Is this possible? If yes , how?
Is binding + INotifyPropertyChanged the way to go?
We've also thought of passing in Actions that can be used to update the state of the parent.
Are there any other alternatives?
So let me explain;
if dynamically loaded user control has no data context (no view model is set), then user control uses view model of parent.
But if you define a view model for each user control, you can import these view models and manage them in parent view model.
Consider also using a BaseViewModel (BindableBase for MEF)

Conditionally validate Dynamically generated Controls in Silverlight

I am having a form with different type of controls like Text Box, Drop downs, Check box, Radio buttons etc. All these controls are loaded dynamically from database at run time.
I want to perform validation on Text box on conditional basis. For example, If we have selected any value in drop down, then you must have to fill details in Text box. Otherwise text box details are not required.
I am open to use database to perform this task and I am using MVVM pattern in my project.
Any help on this is highly appreciated.
Thanks.
(I started this as a comment, but it ended up being too long).
In theory you have access to all these controls and their values in your ViewModel.
Without knowing the specifics of your program, it's difficult to suggest anything useful, but in essence you need to expose some more properties from your ViewModel (probably boolean) which will be calculated based on the values in your controls. Then you need to bind IsEnabled properties on your controls to these new properties.
Sounds simple, but I think you have some architectural problems which will make it difficult to implement what I suggested above. In order for this to work and automatically update your controls whenever other controls' content change, your ViewModel needs to implement INotifyPropertyChanged and raise PropertyChanged event every time you update one of those boolean properties.
I think what you're trying to do could be achieved with ItemsControl and DataTemplates (and maybe DataTemplateSelectors). This will allow you to store "data" in your ViewModel (say List or something more specific) without referencing the actual Controls and the relevant DataTemplates will add the right controls for different data types you have in your ViewModel.

How to check if a winforms control has been selected/toggled?

How can I check if any control (check box/radio button) of the currently active form has been selected/toggled?
My goal is to create an option called Save changes automatically which would enable saving the current state of check boxes and radio buttons, so I need to know when any control is selected/toggled (to execute the save settings method). I don't want to create a separate event handler for every control, I'm looking for a generic solution if it is possible.
This is not a job for the user interface.
Use databinding to change a Model in code-behind and let the model trigger/escalate changes.
To help you on your way a little:
Your checkboxes and other controls are not where your data is. They should only show the data.
Create an object (the Model) with boolean properties for the checkboxes and int/enum properties for the radioboxes. Set up the databindings from the controls to the properties.
Then you can implement the necessary logic in the Setters of the properties.
As Henk proposed, you could use a Separation of Concerns pattern such as MVC to separate UI and domain logic. As the user makes changes to some UI widget, you update the value in the model, for example by setting a property. The property setters could then update a IsDirty (or HasChanges, ...) field. This property would be read by the UI which would, depending on the value of IsDirty, decide what needs to be done. (Display a MessageBox("Do you want to save your changes") or something else)
I do think that Henk was thinking web while you tagged the question with WinForms. Chances are you are not using a pattern to separate UI and domain logic. (and that UI and domain code are already so intertwined that your current deadline does not allow you to introduce a model right now)
You could achieve the same thing by placing the IsDirty field on your Form and having the Changed EventHandlers set that IsDirty value. By subclassing the Form (ie put the IsDirty on your 'FormBase') and your controls (for example by introducing a watermark), you could have this behavior out of the box for all your forms.

How to synchronize (Model)data between difference Views in MVVM

I am trying to synchronize data between seperate Views in MVVM.
Here is the scenario:
There're two ViewModels and two Views respectively:
ViewModel1: contains a list of "Person" object, named "People", which is defined in Entity Framework and is retrieved via WCF Service.
View1: contains an ItemsControl wich is bound to "People" of ViewModel. Item's color may vary depending on its value, for example: person who is over 60 years old may appear red color, while person under 18 years old may appear green. This is achieved by a Value Converter.
(there is a button named "Show Detail Info" in View1, when it's clicked, a ChildWindow dialog is poped up and detail information of currently selected "Person" is displayed )
ViewModel2: contains a "SelectedPerson" object, and implements a "Save" method.
View2: contains several input fields bound to corresponding fields of "SelectedPerson" object, such as TextBox for "Person.FirstName", DateTimePicker for "Person.Birthday", RadioButton for "Person.Gender", etc.
Problem:
when i changed some fields (i.e. "Name" field) and clicked “Save” button, i can even see that changes have been committed onto Database. However, the corresponding item in View1 failed to update its color.
Is there better way to fix this problem?
You can adress such problems usually in three ways depending on your setup:
1 & 2) If the 2 VMs are instantiated by the same parent object these can be connected via INotifyPropertyChanged or Events for the updated Properties
3) If they are disconnected you can use an EventAggregator to message between the VMs. CaliburnMicro has a pretty good implementation but you can build one yourself with just two classes. For more information see: Caliburn.Micro Soup to Nuts Part 8–The EventAggregator
It's hard to answer without knowing exactly how your SelectedPerson and your People list are related. So I assume that SelectedPerson is one item out of your People list. If this is the case, your problem is that your view control that displays the colour depending on the persons age doesn't get informed about the value change.
This information is usually done with a view model that implements INotifyPropertyChanged. Each time a property changes, in your case the property Age of your PersonViewModel, the PropertyChanged event is raised and thus all bound items know about the value change and therefore will requery their values.

MVVM - what is the ideal way for usercontrols to talk to each other

I have a a user control which contains several other user controls. I am using MVVM. Each user control has a corresponding VM. How do these user controls send information to each other? I want to avoid writing any code in the xaml code behind. Particularly I am interested in how the controls (inside the main user control) will talk to each other and how will they talk to the container user control.
EDIT:
I know that using events-delegates will help me solve this issue. But, I want to avoid writing any code in xaml code-behind.
Typically, it's best to try to reduce the amount of communication between parts, as each time two user controls "talk" to each other, you're introducing a dependency between them.
That being said, there are a couple of things to consider:
UserControls can always "talk" to their containing control via exposing properties and using DataBinding. This is very nice, since it preserves the MVVM style in all aspects.
The containing control can use properties to "link" two properties on two user controls together, again, preserving clean boundaries
If you do need to have more explicit communication, there are two main approachs.
Implement a service common to both elements, and use Dependency Injection to provide the implementation at runtime. This lets the controls talk to the service, which can in turn, keep the controls synchronized, but also keeps the dependency to a minimum.
Use some form of messaging to pass messages between controls. Many MVVM frameworks take this approach, as it decouples sending the message from receiving the message, again, keeping the dependencies to a minimum.
Your conceptual problem is here:
Each user control has a corresponding VM.
Having a separate ViewModel for every view pretty much defeats the concept of a ViewModel. ViewModels should not be one-to-one with views, otherwise they are nothing but glorified code-behind.
A ViewModel captures the concept of "current user interface state" -- such as what page you are on and whether or not you are editing -- as opposed to "current data values'.
To really reap the benefits of M-V-VM, determine the number of ViewModel classes used based on distinct items that need state. For example, if you have a list of items each of which can be displayed in 3 states, you need one VM per item. Contrarily, if you have three views all of which display data in 3 different ways depending on a common setting, the common setting should be captured in a single VM.
Once you have strucutred your ViewModels to reflect the requirements of the task at hand you generally find there is no need nor desire to communicate state between views. If there is such a need, the best thing to do is to re-evaluate your ViewModel design to see if a shared ViewModel could benefit from a small amount of additional state information.
There will be times when the complexity of the application dictates the use of several ViewModels for the same model object. In this case the ViewModels can keep references to a common state object.
There are many differenct mechanisms for this, but you should first find out in what layer of your architecture this communication belongs.
One of the purposes of the MVVM framework is that different views can be made over the same viewmodel. Would those usercontrols talk to each other only in the view you are currently implementing, or would they have to talk to each other in other possible views? In the latter case, you want to implement it below the view level, either in the viewmodel or the model itself.
An example of the first case may be if your application is running on a very small display surface. Maybe your user controls have to compete for visual space. If the user clicks one usercontrol to maximize, the others must minimize. This would have nothing to do with the viewmodel, it's just an adaption to the technology.
Or maybe you have different viewmodels with different usercontrols, where things can happen without changing the model. An example of this could be navigation. You have a list of something, and a details pane with fields and command buttons that are connected to the selected item in the list. You may want to unit test the logic of which buttons are enabled for which items. The model isn't concerned with which item you're looking at, only when button commands are pressed, or fields are changed.
The need for this communication may even be in the model itself. Maybe you have denormalized data that are updated because other data are changed. Then the various viewmodels that are in action must change because of ripples of changes in the model.
So, to sum up: "It depends...."
I think the best solution would be using Publisher/Subscriber pattern. Each control registers some events and attaches delegetes to events exposed by other controls.
In order to expose events and attach to them you would need to use some kind of Mediator/EventBroker service. I found a good example here
The best way to do this in my opinion is via Commanding (Routed Commands / RelayCommand, etc).
I want to avoid writing any code in the xaml code behind.
While this is a laudable goal, you have to apply a bit of practicality to this, it shouldn't be applied 100% as a "thou shalt not" type of rule.
You can communicate between elements on the UI by using element binding, so assuming a user control you created exposes a property, the other user controls could bind to it. You can configure the binding, use dependency properties instead of basic properties / implement INotifyPropertyChanged but it is in theory possible, but does require some forethought to enable to communication this way.
You will probably find it far easier using a combination of events, code and properties than try a pure declarative way, but in theory possible.
You can share some View Model objects between controls as well as Commands...
For example, you have some main control, which contains two other controls. And you have some filtering functionality in the main control, but you want to allow user to set some part of the filter in the first sub-control (like "Full filter") and some part of the filter in another (like "Quick filter"). Also you want to be able to start filtering from any of sub-controls. Then you could use code like this:
public class MainControlViewModel : ObservableObject
{
public FirstControlViewModel firstControlViewModel;
public SecondControlViewModel firstControlViewModel;
public ICommand FilterCommand;
public FilterSettings FilterSettings;
public MainControlViewModel()
{
//...
this.firstControlViewModel = new FirstControlViewModel(this.FilterSettings, this.FilterCommand);
this.secondControlViewModel = new SecondControlViewModel(this.FilterSettings, this.FilterCommand);
}
}
public class FirstControlViewModel : ObservableObject
{
//...
}
public class SecondControlViewModel : ObservableObject
{
//...
}
In the main control XAML you will bind sub-controls DataContext to the appropriate View Models. Whenever a sub-control changes filter setting or executes a command other sub-control will be notified.
As others have said you have a couple of options.
Exposing DepedencyProperties on your user controls and binding to those properties provides a pure XAML solution in most cases but can introduce some UI dependencies in order for the bindings to see each other
The other option is a decoupled messaging pattern to send messages between ViewModels. I would have your user controls bind to properties on thier own VM's and then on the property change inside that VM it can "publish" a message that notifies other "subscribers" that something has happened and they can react to that message however they want to.
I have a blog post on this very topic if it helps: http://www.bradcunningham.net/2009/11/decoupled-viewmodel-messaging-part-1.html
If you're using strict MVVM, then the user-control is a View and should only "talk", or rather, bind, to its ViewModel. Since your ViewModels most likely already implement INotifyPropertyChanged, as long as they have a reference to each other, they can use the PropertyChanged events to be notified when properties change, or they can call methods (better if it's through an interface) to communicate with each other.

Categories