-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
View / ViewModel Activation #503
Conversation
The design of this seems like it might be lacking in discoverability. Maybe having Activator = this.WhenActivated(d => {
// d() registers a Disposable to be cleaned up when
// the View is deactivated / removed
d.DisposeWhenDeactivated(UserError.RegisterHandler(x => {
// NB: Stuff
}));
}); And this.WhenActivated(d => {
Console.WriteLine("Helloooooo Nurse!")
d.DisposeWhenDeactived(() => Console.WriteLine("Goodbye, Cruel World")));
}); That's a little more readable and the nice thing is we can have overloads of |
Alright, calling all API designers - here's how this API looks now: public class ActivatingViewModel : ReactiveObject, ISupportsActivation
{
public ViewModelActivator Activator { get; protected set; }
public int IsActiveCount { get; protected set; }
public ActivatingViewModel()
{
Activator = new ViewModelActivator();
this.WhenActivated(d => {
IsActiveCount++;
d(Disposable.Create(() => IsActiveCount--));
});
}
} What could this look like? /cc @reactiveui/owners |
I actually like the suggestion by @haacked. I also think there is value in an Also why do I need the |
To be honest, it seems quite reasonable as it is. Making it an object with a method would make the declarations of things which need disposing a lot more verbose, made more important since you have to do use this construct to dispose of bindings. At least with a lambda you get to choose your level of verbosity. |
This is why I favor just the action and not an object with a method as well. Between mousing over the value and help via IntelliSense, I think it's plenty discoverable. You can also make |
Hmm, this whole discussion started because of error handling registration. It seems to me the real problem is we're calling public static void RegisterErrorHandler(this ISupportsActivation activation) {
// This does it the better way
...
}
public static void RegisterErrorHandler(this ReactiveObject reactiveObject) {
var activatable = reactiveObject as ISupportsActivation;
if (activatable != null) {
activatable.RegisterErrorHandler();
return;
}
// Do it the old way.
UserError.RegisterHandler(...);
} Then in a view model: public class MyFixedViewModel : ReactiveObject, ISupportsActivation
{
public MyBrokenViewModel()
{
this.RegisterErrorHandler(x => {
// NB: Stuff
});
}
} The idea here is you always call |
@haacked That works for the ViewModel and registering error handlers, but you also have to use the same for bindings in the view: public class MyView : IViewFor<MyViewModel>
{
public MyView() {
InitializeComponent();
this.WhenActivated(d => {
d(this.OneWayBind(ViewModel, vm => vm.SomeValue, v => v.SomeTextBlock.Text));
d(this.OneWayBind(ViewModel, vm => vm.SomeOtherValue, v => v.SomeOtherTextBlock.Text));
});
}
//Implementation of gunk for VM dependency property here
} It would be a bit weird if there was a different syntax for activation in the View to the ViewModel (though I agree it might be a good idea to specialise for registering the error handler which likely most VMs will want to do). |
@jen20 yeah, that should be made clear in the issue.
I'm not suggesting that. Let's not push the method of activation to the consumer. Let's focus on providing an easy way to register things that is automatically handled when activation is supported. Underneath the hood, it could be the same approach. But for end users, it's much simpler. For example, what if we did this for all the bind methods (pseudocode)? public static void Bind(this whateverItIs, ....) {
if whateveveritIs is ISupportsActivation then
Bind this in a manner that doesn't leak
} |
@haacked That's actually a pretty nice idea, would silently fix people's binding code :-) |
Actually one of the neat side effects of 5618a7a is that you can have more than one WhenActivated block in the ctor, so these kinds of binding tricks can totally be done. Let's stick with the current design for WhenActivated for now, but I really want to steal @haacked's ideas for Binds and Error Registration stuff. |
View / ViewModel Activation
Hello, What do you recommend to use for activating the view models only when controls are made visible? (other than subscribe on VisibleChanged) By checking the implementations of IactivationForViewFetcher for both winforms and wpf, I can see that activation can happen even if a control does not become visible. Regards |
Consider the following ViewModel constructor:
This is broken because every time we create MyBrokenViewModel, we create another error handler. What Do? What we really want for certain global things like UserError, is for UserError to be subscribed only when the View associated with the ViewModel is visible. However, that information isn't available to ViewModels, and even if it was, it's not super obvious. Let's fix it
How does this work:
Activation allows you, for both Views and ViewModels, to set up the things that should be active when the View is visible. Here's how you do it for ViewModels:
Here's how it works for Views:
Note that calling
WhenActivated
in a View automatically means that the associated ViewModel gets notified for activated / deactivated changes (and in fact, you must callWhenActivated
in the View to get the ViewModel to be notified).TODO: