Assume your model or view-model needs to display a message but it obviously doesn't want to access UI. So it implements an interface which has Notify(String) method.
Now whoever implements this interface can show the message and that object would typically be UI based class which would need to be passed to the model or view-model.
My question is, will it be frown upon to pass a UI object even though it's only being passed as interface?
I have illustrated this issue with a mock example.
public interface INotify
{
void Notify(String msg);
}
class Model
{
INotify _notify;
public Model(INotify notify )
{
_notify = notify;
}
public void Add(int a, int b)
{
int result = a + b;
_notify.Notify("The result is " + result.ToString());
}
}
class View : INotify
{
public void Notify(String msg)
{
Console.Write("I am the view, I received this: ");
Console.WriteLine(msg);
}
}
class Program
{
static void Main(string[] args)
{
View view = new View();
Model model = new Model(view);
model.Add(4, 7);
}
}
The result is as expected, the key point is that it's printed from the view.
I am the view, I received this: The result is 11
Press any key to continue . . .
In the real world, the view class would be a full blown UI class like windows form or wpf etc but it's only being passed in place for an interface that it implements. Will this be frown upon why the view is being passed as an interface that it implements?
If it will be frown upon, isn't this exactly the job of interface though? In this case, it's derived class will be expected to be some kind of UI class to show the message after all and it will have a lot of other things.
I am trying to understand the practical uses of interfaces and also solve a problem with it when occasionally model view in MVVC or MVVM might want to display a message.
The other variation is to implement full observer pattern but in my case, the model or view-model needs to display message in only in one window (never in multiple) so passing that view for interface logically makes sense.
I really don't think this would be a problem at all, as long as it doesn't affect performance in a bad way that is notable or that it looks strange later on in the project when you start to add more and more on the GUI, etc.
Related
I am writing a simple MVC pattern. My Views implement a simple interface.
public interface IComponentView
{
void Render(ComponentModel componentModel);
}
Here the ComponentModel is an abstract model class. Controllers are the ones responsible for preparing the new component model and call the view's Render() method while passing the new model. As you can imagine the first thing the view does inside it's own Render() function is to downcast the received parent class ComponentModel to its appropriate child class model so that all the properties and such are available for the view to use for rendering. Here is an example.
public SpecialMenuView : IComponentView
{
...
public void Render(ComponentModel componentModel)
{
SpecialMenuModel model = (SpecialMenuModel)componentModel;
// use model to render stuff
}
...
}
Is there a better way to do this rather than keep down casting for every single UI component I have?
I don't know what you're using this interface for, but if you want to transfer type information, why not generics?
public interface IComponentView<TModel> where TModel : ComponentModel
{
void Render(TModel componentModel);
}
public SpecialMenuView : IComponentView<SpecialMenuModel>
{
...
public void Render(SpecialMenuModel componentModel)
{
// use model to render stuff
}
...
}
You can make that interface contravariant for bonus points.
Not sure of an easy way to do it without generics. You can however make is nicer to follow with some pattern matching, which also takes care of ensuring the cast is fine and the model is ready to work with.
public class SpecialMenuView : IComponentView
{
public void Render(ComponentModel componentModel)
{
if (componentModel is SpecialMenuModel model)
{
// use model to render stuff
model.GetType();
}
}
}
I think this question could of already been answered, which if this is the case I will delete immediately. I'm new to WPF (and new to C# really) and I'm trying as hard as possible to follow MVVM but I'm really struggling with finding a way to NOT implement INotifyPropertyChanged on my Model.
My Model contains a collection of predefined objects which are created from another reference. Within the Model, I have properties which are updated as and when the Task is completed.
CustomObject - API
public class CustomObject
{
private string _myTaskOutput;
public CustomObject()
{
_myTaskOutput = MyTaskMethod();
}
//MyTaskMethod()
//Get & Setter for _myTaskOutput;
}
Util - API
public static class Util
{
public IEnumerable<CustomObject> GenerateObjects()
{
var customObjectCollection = SomeHelperMethod();
return customObjectCollection;
}
}
Model
public class CustomObjectCollectionModel
{
private IEnumerable<CustomObject> _customObjectCollection;
public CustomObjectCollectionModel()
{
_customObjectCollection = Util.GenerateObjects();
}
//Get & Setter for IEnumerable<CustomObject>
}
The object reference does not change so I believe having an ObservableCollection is out of the question (is this correct?) and implementing INotifyPropertyChanged on CustomObject works as intended but I understand this not the correct way of doing things.
If CustomObject is some kind of domain or business object, you could wrap it in a view model class in your client application. So instead of binding to an ObservableCollection<CustomObject> you bind to an ObservableCollection<CustomObjectWrapper> where CustomObjectWrapper is a client-specific class that implements the INotifyPropertyChanged interface (provided that you actually need to provide change notifications in your UI).
You will indeed have to create a CustomObjectWrapper for each CustomObject that you receive from your service API - you could do this in your view model class - but at the same time you don't have to pollute your business objects with client-specific code. Binding directly to domain-specific business objects is rarely useful.
After a major edit to this quesiton, I'm hoping it's now clear.
I'm very lost with binding in WPF when 1 change should affect multiple properties.
I regularly use VVM to bind my ViewModel to my View and I would say I'm OK with it.
I am trying to implement a state controller. This means that, what ever settings I made in part of my UI, the reflection is through out.
For example in my part of my UI, I can toggle a feature on or off, such as "show images"
When I make this change, I'd like everything in my application to be notified and act accordingly.
So, my StateController class will have a property
public bool ShowImages
And in my View, I'd likely have something like
<image Visible ="{Binding ShowImages", Converter={StaticConverter ConvertMe}}" />
The problem I have is how I go about making the StateController alert all of my ViewModels of this.
Currently, in each ViewModel I'm assuming I'd have to have the same property repeated
public bool ShowImages
EG
public class StateController : BaseViewModel
{
public bool ShowImages{get;set;}//imagine the implementation is here
}
public class ViewModelB : BaseViewModel
{
public bool ShowImages{}//imagine the implementation is here
}
public class ViewModelB : BaseViewModel
{
public bool ShowImages{}//imagine the implementation is here
}
So, my question is, if I updated ViewModelB.ShowImages, how would I first inform the StateController which in turn updates all ViewModels.
Is this something the INotifyPropertyChanged can do automatically for me since they all share the same propertyName, or do I have to implement the logic manually, eg
public static class StateController
{
public bool ShowImages{get;set;}//imagine the implementation is here
}
public class ViewModelA : BaseViewModel
{
public bool ShowImages
{
get { return StateController.ShowImages; }
set { StateControllerShowImages = value;
OnPropertyChanged("ShowImages"); }
}
}
public class ViewModelB : BaseViewModel
{
public bool ShowImages
{
get { return StateController.ShowImages; }
set { StateControllerShowImages = value;
OnPropertyChanged("ShowImages"); }
}
}
I hate the idea of the above implementation but it does show what I'm trying to achieve. I just hope there is a better way!
The PropertyChange notification is only raised for that one object model.
So raising a change notification of the "Name" property of ClassA will only update the UI in cases where it's bound to that specific ClassA.Name. It won't trigger a change notification for any ClassB.Name, or other instances of ClassA.Name.
I would suggest using a Singleton here for your StateModel, and having your other models subscribe to the StateModel.PropertyChanged event to know if it should update, like this answer.
public ViewModelA
{
public ViewModelA()
{
StateController.Instance.PropertyChanged += StateController_PropertyChanged;
}
void StateController_PropertyChanged(object sender, NotifyPropertyChangedEventArgs e)
{
// if singleton's ShowImages property changed, raise change
// notification for this class's ShowImages property too
if (e.PropertyName == "ShowImages")
OnPropertyChanged("ShowImages");
}
public bool ShowImages
{
get { return StateController.Instance.ShowImages; }
set { StateController.Instance.ShowImages = value; }
}
}
If I understood you correctly, you are looking for a mechanism that allows your different ViewModels to communicate between each other.
One possible way would be to implement the Observer Pattern (a code example can be found here: "Observer pattern with C# 4"). In this way your ViewModel subscribe each other to receive change notifications from a "publisher", i.e. the ViewModel that had its value changed. You have a good control over who receives which notification from which publisher. The downside of this approach is a tight coupling between your models.
My approach would be this:
Use a message dispatcher. Your ViewModels can subscribe to a certain type of message, e.g. ShowImagesChanged. If any of your ViewModels changed the ShowImages property, that ViewModel calls the dispatcher to send out such a ShowImagesChanged message with your current values.
This way you can keep you ViewModels decoupled from each other. Still, although the ViewModels do not know each other this gives a way to exchange data between them.
Personally, I have used the Caliburn Micro MVVM framework several times for this, but there should be enough other MVVM frameworks that provide the same functionality to fit your taste.
The Calibiurn Micro documentation and how easily the dispatcher can be used is here: Event Aggregator
To avoid code repetition you can create a class derived from BaseViewModel that implements your property and have ViewModelA, ViewModelB extend it. However, this does not solve the problem of keeping each instance updated.
In order to do so, you may:
Use a static class (your current solution) or a Singleton as suggested in one of the comments. This is simple but has potential problems such as race conditions and coupling.
Have your ShowImages binding property repeated in each ViewModel and update it by subscribing to a ShowImagesChanged event. This could be published through a Command executed from the UI. I'd say this is the WPF approach and has the benefit of decoupling the ShowImages state management from its consumption.
Assign the ShowImagesupdate responsibility to a single ViewModel and subscribe to the its PropertyChanged in the other ViewModels so that they update accordingly. Better than the first option, but still huge coupling.
Why repeat properties at all? Just bind to StateController itself.
Say we have singleton StateController:
public class StateController : INotifyPropertyChanged
{
private static StateController instance;
public static StateController Instance {
get { return instance ?? (instance = new StateController()); }
}
//here`s our flag
private bool isSomething;
public bool IsSomething
{
get { return isSomething; }
set
{
isSomething = value;
PropertyChanged(this, new PropertyChangedEventArgs("IsSomething"));
}
}
private StateController(){}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
Then in base VM class just make a reference to this controller:
public StateController Controller { get { return StateController.Instance; } }
And where needed bind like this:
<CheckBox IsChecked="{Binding Controller.IsSomething}">
Test
</CheckBox>
This way every binding will work with one property and react to one property. If you need some custom code to work you can subscribe to PropertyChanged of StateController where needed and take action.
I have been reading a lot on MVC/MVP patterns.... I have a simple question....If you have a view with loads of controls....say 10 texboxes and 10 checkboxes....etc etc... Am I expected to specify the properties and events each one of them in my IView interface?....
Definitely not that way.
Your IView Interface will define set of contracts/ methods (it includes properties) that can be accessed by your business layer.
It is totally wrong to exposed your control in interface like this:
public interface IView
{
TextBox UserNameTextBox{get;set;}
}
You should not have interfaces defined in this way. This is really a bad programming.
You should rather expose some contracts that your UI layer will implement.
E.g.
public interface IView
{
public void SetUserName(string Text);
}
You can implement this interface on winform as well as webform.
Similarly, you are also not supposed to expose knowlede of UI in interface(Contract).
Lets assume a scenario where you have to display information of Employee object on UI.
You should pass Employee object to UI through this interface and UI will take care of way of representing this Employee object.
Your BL should never bother about n number of TextBoxes and checkboxes.
public class Employee
{
//first name
//last name
//is manager
//is teamleader
//address
}
public interface IEmployeeView
{
void SetEmployee(Employee employee);
}
public partial class EmployeeForm:WinForm,IEmployeeView
{
public void SetEmployee(Employee employee)
{
ENameTextBox.Text = employee.FirstName+" "+employee.LastName;
}
}
When using the MVP pattern, I often come across methods and members which don't seem to fall nicely within the View or Presenter classes...My question is: What rules do you use to decide what functionality lies which classes? I am relatively new to MVP, so please humour me.
TIA.
I tend to favor the Passive View variant of MVP so this is a non issue for me. In passive view pattern the View pretty much delegates anything more complex than a simple assignment to the presenter.
You wind up with a pattern that looks like this:
public class MyView: IView
{
private MyPresenter Presenter;
private OnEvent()
{
Presenter.DoSomething();
}
public string MyProperty
{
get{ return UIControl.Property;}
set{ UIControl.Property = value}
}
}
public interface IView
{
public string MyProperty{ get; set;}
}
public class MyPresenter
{
private IView view;
public void DoSomething()
{
...
view.MyProperty = something;
}
}
The only trick part is if you have a datagrid on your form. These require a lot of work to fit into a Passive View pattern.
It boils down to how much manipulation of the UI is going on. If the method consist a lot of direct access to individual controls then likely it belongs on the presenter. Otherwise it belongs on the view. The goal is to reduce the interaction between the view and the present to the minimum needed to fulfill the design of the software.
For example
Presenter.SetListTitle MyList.Name
For I = View.MyListStart to View.MyListEnd
Presenter.AddListItem MyList(I)
Next I
Presenter.ShowListAddBUtton
Presenter.ShowListDelButton
Should be placed in the presenter as below
Public Sub UpdateWithList(MyList as AList, View as AView)
Me.SetListTitle MyList.Name
For I = View.MyListStart to View.MyListEnd
Me.AddListItem MyList(I)
Next I
Me.ShowListAddBUtton
Me.ShowListDelButton
End Sub
Later if you decided to change your UI all you have to worry about is implementing UpdateWithList not SetListTitle,AddListItem, etc, etc.