How to notify all guard methods when global changes - c#

Often in my applications built with Caliburn Micro I have a need to store some global data; this could be app specific config, authentication properties, etc. I generally put them in a class called "Session" and inject that via constructor injection so that every view model has a reference to a single instance of Session.
I found a case where I wanted a guard method on two different view models to be linked to a Session variable; the issue is guard methods are generally notified of changes in the setter of the changed variable. Since it's a global, it doesn't know what depends on it. (It occurs to me that this pattern of variables being aware of what guard is hooked into them is bad, but when it's all in the same ViewModel it doesn't matter much.)
I could throw an event, but that's messy and a lot of work for something that should be simple.
I could try to identify every spot where it may have been updated and manually notify, but that's error prone.
public class MyViewModel: Screen{
public MyViewModel(SessionInfo session){
Session = session;
}
public CanTakeAction { get { return !string.isNullOrWhitespace(Session.SomeProperty); } }
}
public class SessionInfo {
public SessionInfo(){}
public string SomeProperty { get; set; }
// this is where I would normally notify a guard method, but this is not going to work
NotifyOfPropertyChange(() => CanTakeAction); // except it doesn't know about CanTakeAction
}

One possible solution would be to introduce a base ViewModel, which has the guard methods (virtual). For Example,
public class ViewModelBase:Screen
{
private SessionInfo _sessionInfo;
public ViewModelBase(SessionInfo sessionInfo)
{
_sessionInfo = sessionInfo;
}
public void NotifyGuardMethods()
{
NotifyOfPropertyChange(nameof(CanTakeAction));
}
public virtual bool CanTakeAction { get; set; } = false;
}
For all the ViewModels that needs to be notified by the change in Session, you could now derieve from the ViewModelBase.
public class ShellViewModel:ViewModelBase
{
public override bool CanTakeAction { get=>//its own logic; set=>//its own logic; };
}
You could now introduce Events to the ViewModelBase, which could use the NotifyGuardMethods defined in the base class to notify all other view models. This ensures the messsy Events part would be restricted to one class alone (base view model).

Related

Activation/Deactivation with ObservableAsPropertyHelper

What is the proper usage of Activation/Deactivation in conjunction with ObservableAsPropertyHelper? Given a view and viewmodel that reflects long lived (hot) observables, the subscription would need to be disposed when the view and viewmodel is unloaded. However ObservableAsPropertyHelper, which is recommended to be readonly is assigned in the constructor of the viewmodel, and cannot be part of the activation/deactivation lifecycle. What is the right way to handle these kind of situations?
public interface ILongLivedObject
{
IObservable<bool> Status { get; }
}
public class TestViewModel : ReactiveObject
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status); //how is the subscription disposed?
}
}
This also gets me into a corner when trying to add commands that depends on this status. In my application, a common use case is to have some hardware that is on some specific status (e.g. IsOpen) and allow commands when it is true.
Without knowing better, this is what I am trying to do:
public class TestViewModel : ReactiveObject
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public ReactiveCommand<Unit, Unit> DoStuff {get;}
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status); //how is the subscription disposed?
DoStuff = ReactiveCommand.CreateFromTask(....., this.WhenAnyValue(this, x => x.Status);
}
}
If I try to move the _status creation into this.WhenActivated, the app will crash as the command is trying to get the value of status before it is created. Am I supposed to (re)create the comand during activation? This seems wrong and pretty costly?
So far, it seems better to have a regular Status property with a protected setter and make a regular subscription in this.WhenActivated - but this is what the handbook tells to avoid for "readonly" properties.
So one thing to be aware of in Reactive programming, disposing often means "unsubscribe".
You often don't need to unsubscribe since the garbage collector will take care of it for you, providing you create ObservableAsPropertyHelper (abbreviated as OAPH) only with observables generated from the current ViewModel.
In your case however, your observable/object, is related to a object outside the current ViewModel. The OAPH itself is a Disposable object.
So you can use ISupportsActivation (shortly going to have a replacement of IActivableViewModel) and pass your OAPH into it's Disposable property.
public class TestViewModel : ReactiveObject, ISupportsActivation
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status);
this.WhenActivated(disposables =>
{
disposables(_status);
}
}
}
The disposables parameter passed into the WhenActivated lambda is a Func that takes a IDisposable
In the view, make sure you derive off IActivatable (soon to be renamed IActivatableView) and use WhenActivated in the constructor of the view as well.

How to make MVVM property changed when my settings also changed?

I have a ViewModel like this
Public class AboutPageViewModel
{
public AboutPageViewModel()
{
AppName = Settings.MyAppName;
}
private string _appName;
public string AppName
{
get{return _appName;}
set{_appName = value; RaisePropertyChanged("AppName");}
}
}
Now in a static class
public static class Settings
{
public static string MyAppName{get;set;} = "LOL"
}
How do I notify the ViewModel everytime MyAppName is changed, and update it to the Binded UI?
Thanks!
As you define it in your question, Settings isn't a static class (ah, I see in comments that was a typo, and it's static in your code). It should not be static. PropertyChanged notifications on a static class are theoretically possible but it's not worth your time to mess with, and there's no need to bother.
Have Settings implement INotifyPropertyChanged, just like your viewmodel. When MyAppName changes, Settings should raise PropertyChanged, just as AboutPageViewModel does when its own AppName property changes.
Now give Settings a static property called Instance:
public static Settings Instance { get; private set; }
static Settings()
{
Instance = new Settings();
}
And handle its PropertyChanged event in AboutPageViewModel:
public AboutPageViewModel()
{
AppName = Settings.Instance.MyAppName;
Settings.Instance.PropertyChanged += (s,e) =>
{
// If you're in C#6:
//if (e.PropertyName == nameof(Settings.MyAppName))
if (e.PropertyName == "MyAppName")
{
AppName = Settings.Instance.MyAppName;
}
}
}
Option Number Two
Arguably a better option; I've done it this way more than once.
In comments, #MikeEason makes the very good point that this could also be done with a custom *Changed event such as MyAppNameChanged, which has two advantages: It lets you go back to a static class, and it lets you skip the check on the property name, which is extra code and also a "magic string". Working with INotifyPropertyChanged we get a little bit numb to the danger of magic strings, but they are in fact bad. If you're in C#6, you can and absolutely should use the nameof() operator, but not all of us are in C#6 just yet. My main responsibility at work is an application that we're hoping to migrate to C#6 this summer.
public static event EventHandler<String> MyAppNameChanged;
private static String _myAppName = "";
public static String MyAppName {
get { return _myAppName; }
set {
if (_myAppName != value)
{
_myAppName = value;
// C#6 again. Note (thanks OP!) you can't pass this for sender
// in a static property.
MyAppNameChanged?.Invoke(null, value);
}
}
}
The drawback of this is that, well, this class is called Settings, not Setting. Maybe it's got a dozen properties changing here and there. That gets to be a real thicket of distinct property-changed events ("so what?" you may ask -- and you may have a point). My tendency is to stick with PropertyChanged if there's a whole sheaf of them, and to add an event if the class has only one or two important properties that somebody needs to keep an eye on. Either way is annoying in my view; try both and you'll eventually settle on a preference.
You don't need to store value in ViewModel if you already have it somewhere (I assume what you are not going to change it in ViewModel itself):
public class AboutPageViewModel : INotifyPropertyChanged
{
public string AppName => Settings.MyAppName;
}
And as for View to know when this property is changed you need 2 things: 1) there should be a way to inform ViewModel when value is changed 2) rise PropertyChanged(nameof(AppName)) (notice INotifyPropertyChanged).
Several possibilities to make it:
Settings should rise event when MyAppName value is changed, ViewModel subscribe to it and rises PropertyChanged;
Store initial value, check periodically if value is changed;
Use another type which implement INotifyPropertyChanged, bind to that type property instead, this will update view automatically if that type rises PropertyChanged.
You have to implement INotifyPropertyChanged interface on Settings class!
then use the same piece of code like this:
private string _myAppName;
public string MyAppName
{
get{return _myAppName;}
set{_appName = value; RaisePropertyChanged("MyAppName");}
}

where to put the checking function for the model (asp.net mvc5)

i know the model should not have any logic , but i don't know where is the good place to put the checking or the update function for a particular model
ex.
public class GuestBook
{
public int money { get; set; }
[Required]
public string name { get; set; }
[Required]
public string email { get; set; }
public DateTime content { get; set; }
public bool rich()
{
if (this.money <3000)
return false;
else
return true;
}
public void earn(GuestBook b)
{
this.money += b.money;
}
}
the function rich() and earn() is only use for this module(GuestBook)
if i didn't put it in this module , then where i should put?
Following good OOP design principles, the only way to really protect your classes' invariants (and not have a maintainability nightmare) is by not allowing them to be changed by anyone other than the class. Typically this is done by NOT exposing public setter methods (public auto properties are evil), making your fields readonly (wherever possible), and initializing them from the constructor.
The whole point of having classes is to group data with behavior. A simple data structure containing ints and strings is not a class in the OOP sense, it's just a struct.
In some cases you are stuck with an even more evil ORM that FORCES you to make all properties public. This is not an issue with Entity Framework (and some others too) though, EF can magically reflect in and access private setters if needed, you just gotta make sure there's also a private default constructor.
According to your class rich method is validating and earn method is applying business logic. You can create AdditionalMetadataAttribute for rich method logic that can fire on ModelState.IsValid and for earn method you need to create BO class that apply your all business logic.
here a link for AdditionalMetadataAttribute

From anemic domain to domain driven

I was trying to find a clear and simple example of what an anemic domain really means. There is a lot of theory around, and also many well answered questions. Still, I could not get a clear picture about to what extent "anemic domain" meaning really goes. Therefore, I believe it would be simpler to see a dummy practical example of an anemic domain design and than ask you how could this be evolved to a domain driven one...
So, let's say we have a data entity of type TaskData:
public class TaskData
{
public Guid InternalId { get; set; }
public string Title { get; set; }
public string Details { get; set; }
public TaskState ExplicitState { get; set; }
public IEnumerable<TaskData> InnerTasks { get; set; }
}
And there is the need of an additional property called "ActualState", which is a computed state: if the Task has inner sub-tasks, the value strictly depends of the children, otherwise, the "ActualState" is equal to "ExplicitState"
If I write this logic in a separate service class (I call them "engines") we have:
internal class TaskStateCalculator
{
public TaskState GetState(TaskData taskData)
{
if (taskData.InnerTasks.Any())
{
if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
return taskData.ExplicitState;
}
}
The first question is:
Does the code above reflect an anemic domain design, even if the TaskStateCalculator service/engine is part of my Domain Layer?
If yes, in order to avoid it, we'll need to move the logic inside the TaskData class (and rename TaskData to Task). Am I right?
The second question is (actually a chain of them):
What if we have a more difficult situation? Let's say there is the need for a property called ComputeSomething inside Task entity, and the logic of this property needs to access the entire Task's repository. In this case, the Task class would have a dependency on TaskRepository. Would this be ok? How would EF construct an instance of such class? What is the alternative?
I was trying to find a clear and simple example of what an anemic domain really means
It's in fact really easy to go from an anemic domain model to a rich one.
Set all property setters to private and then add methods if you want to change state of a model.
Evaluate all Law of Demeter violations and add methods where suitable.
Eventually you will have a correct model.
In your case I would encapsulate that logic inside TaskData as your TaskStateCalculator violate Law of Demeter
public class TaskData
{
public Guid InternalId { get; private set; }
public string Title { get; private set; }
public string Details { get; private set; }
public TaskState ExplicitState { get; private set; }
public IEnumerable<TaskData> InnerTasks { get; private set; }
public TaskState GetState()
{
if (!InnerTasks.Any())
return ExplicitState;
if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
}
another thing is that I would probably not expose InnerTasks collection at all to the outside world (just have it as a member field). But it's hard to say as I do not know how the class is used in other scenarios.
Why private setters
Every time you have to change more than one property it's often better to describe the behavior with a method, as it's then impossible to forget to change all required properties. A method also describes better what you are trying to do than changing a set of properties.
Even if you just change a single property, that property can set the class in an invalid state as the change may not be compatible with the rest of the information in the class. Don't forget that encapsulation is one of the core principles in OOP

Where to create the class

I'm trying to model a production system with "facility" as Class and some subclasses down to "Activity". The facility has a name as only parameter (at the moment), and I'd like to create an instance of the class reading the name as an input from a textbox. Since "activity" is inherit the properties from it's "parent classes" I'll create an instance of the class "activity" and not it's parent.
The problem is that I don't know where to create the class and how to pass it so that when I add the first subclass "Workstation" I can edit the properties of the same "activity" I created earlier.
I don't really have any code to add at this point unfortunately, but please tell me if there's anything special you'd like to see and I'll try to add it to the post.
And by the way, it's in the shape of a WinForm application with a GUI I'm trying to do this.
There are a couple things to note here. First, you'll want to use the Composite pattern to encapsulate the relationships between your classes. (For those who don't understand the OP's type hierarchy, it does make perfect sense in a factory context. There are many activities going on, which can be grouped into workstations and at a higher level into facilities.)
So, you should probably have a base Activity class (that supports the Composite pattern by exposing a collection of child activities), and then your "levels" (like Facility and Workstation) will inherit from Activity. Each of these classes will have unique properties.
The following classes should be created in their respective files, e.g. Activity.cs, Factory.cs, Workstation.cs:
class Activity
{
// An attribute that every Activity may need: a displayable name.
// This might be useful if you have a TreeView, e.g., showing all the activities.
public string Name { get; private set; }
// Every Activity could have child activities - this is the Composite pattern.
// You can loop through these to navigate through the hierarchy of your data.
// (This is often done using recursion; see example below with GetAllWorkstations().)
public List<Activity> ChildActivities { get; private set; }
public Activity()
{
ChildActivities = new List<Activity>();
}
public override string ToString() { return Name; }
}
class Factory : Activity
{
public string City { get; private set; }
public string Address { get; private set; }
}
class Workstation : Activity
{
public string WorkstationNumber { get; private set; }
}
The responsibility of loading your model then has to be handled somewhere. A good place to do it is in your main form. For example, you might write code like this:
class MainForm : Form
{
private readonly List<Factory> topLevelFactoryActivities;
public MainForm()
{
// ... other code
topLevelFactoryActivities = LoadTopLevelFactoryActivities();
}
private IEnumerable<Factory> LoadTopLevelFactoryActivities()
{
var factories = new List<Factory>();
// TODO: Load the factories, e.g. from a database or a file.
// You can load all the child objects for each factory here as well,
// or wait until later ("lazy-loading") if you want to.
// NOTE: If this becomes complex, you can move the LoadTopLevelFactoryActivities()
// method to its own class, which then becomes your "data access layer" (DAL).
return factories;
}
}
Now, if you want to find all the workstations that are part of a particular factory, you would write a method like the following on the Factory class:
class Factory : Activity
{
// ... other code
public IEnumerable<Workstation> GetAllWorkstations()
{
return GetWorkstationsRecursive(this);
}
private IEnumerable<Workstation> WorkstationsIn(Activity parentActivity)
{
foreach (var workstation in parentActivity.ChildActivities.OfType<Workstation>)
{
// Uses a C# feature called 'iterators' - really powerful!
yield return workstation;
}
foreach (var childActivity in parentActivity.ChildActivities)
{
// Using recursion to go down the hierarchy
foreach (var workstation in WorkstationsIn(childActivity))
{
yield return workstation;
}
}
}
}
You would call it like so, e.g. in your main form:
class MainForm : Form
{
// ... other code
public MainForm()
{
// ... other code
// Assume this is assigned to the factory that you want to get all the workstations for
Factory myFactory;
var workstations = myFactory.GetAllWorkstations();
// Now you can use 'workstations' as the items source for a list, for example.
}
}
As an example use case, you might want to show a second form (that belongs to the main form) which shows a list of all the workstations. (In practice you probably shouldn't create too many windows; prefer building a nonoverlapping layout. But just to show how you might pass the model instances around...)
class WorkstationListForm : Form
{
private IEnumerable<Workstation> workstations;
public WorkstationListForm(IEnumerable<Workstation> workstations)
{
this.workstations = workstations;
//TODO: You can now use 'workstations' as the ItemsSource of a list view in this form.
}
}
You could, of course, make topLevelFactoryActivities public on your MainForm and pass the variable this of the MainForm to the WorkstationListForm constructor instead. Then you could access the member on MainForm like this:
public WorkstationListForm(MainForm mainForm)
{
var topLevelFactoryActivities = mainForm.topLevelFactoryActivities;
// Now WorkstationListForm has full access to all the data on MainForm. This may or
// may not be helpful (it's usually best to minimize sharing and public fields).
}
Second, you'll want to use a proper separation between your view (user interface code/classes) and your model (the Activity hierarchy).
Third, if there's going to be any kind of live data being pushed to the user interface then you'll need a databinding mechanism to automatically update the view whenever the model changes.
In general, #2 & #3 are popularly addressed via the Model-View-ViewModel pattern. There is an excellent tutorial here for building an MVVM app using WinForms/C#.
That should get you started, at least. Also see an answer to a similar question. (Sorry about promoting my own answer, but I don't want to type out the whole example twice. Please forgive me. :))

Categories