Skip to content
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

[Feature] Microsoft.Toolkit.Mvvm package (Preview 5) #3428

Closed
27 tasks done
Sergio0694 opened this issue Aug 13, 2020 · 30 comments · Fixed by #3429, #3424, #3527 or #3562
Closed
27 tasks done

[Feature] Microsoft.Toolkit.Mvvm package (Preview 5) #3428

Sergio0694 opened this issue Aug 13, 2020 · 30 comments · Fixed by #3429, #3424, #3527 or #3562
Labels
feature request 📬 A request for new changes to improve functionality .NET Components which are .NET based (non UWP specific) open discussion ☎️
Milestone

Comments

@Sergio0694
Copy link
Member

Sergio0694 commented Aug 13, 2020

Overview

This issue is meant to be used to track all the feature requests and discussions regarding API changes or other tweaks for the Microsoft.Toolkit.Mvvm package, which was introduced with #3230 and recently announced. 🎉

Find initial docs and samples here at https://aka.ms/mvvmtoolkit.

Key Tenants

  • Platform and Runtime Independent - .NET Standard 2.0 🚀 (UI Framework Agnostic)
  • Simple to pick-up and use - No strict requirements on Application structure or coding-paradigms (outside of 'MVVM'ness) i.e. flexible usage
  • À la carte - Developer able to choose the components they wish to leverage
  • Reference Implementation - Lean and performant, provides compliments to interfaces and paradigms hinted at in the Base-Class Library, but without provided implementations.

If you want more info on the package, you're welcome to browse our samples and preview documentation (here), watch the initial presentation by @michael-hawker and I (here) or watch Michael's presentation during the UNO Conf (here).

Tracking changes so far

Will be updating this list with all the current (work in progress) changes that are being included into a PR.

Preview 5 (#3562)

  • Added ObservableValidator.ClearErrors method
  • Added ObservableValidator.ValidateProperty method
  • Added ObservableValidator.ValidateAllProperties method
  • Added generic ObservableValidator.GetErrors method
  • Speed/memory optimizations to WeakReferenceMessenger on .NET Standard 2.0

Preview 4 (#3527)

  • Reintroduced Ioc class (see docs)
  • Added new ObservableObject.OnPropertyChanged(PropertyChangedEventArgs) overload
  • Added new ObservableObject.OnPropertyChanging(PropertyChangingEventArgs) overload
  • The OnPropertyChanged and OnPropertyChanging overloads with a string param are no longer virtual
  • Added notification support to IAsyncRelayCommand.CanBeCanceled property
  • Improved notification logic for other IAsyncRelayCommand properties
  • Added notification support to ObservableValidator.HasErrors property
  • Added new TrySetProperty methods to ObservableValidator
  • Minor performance/memory usage improvements and bug fixes

Preview 3 (shipped!) 🚀

ComponentModel, Input, DependencyInjection (#3429)

  • New ObservableValidator class for INotifyDataErrorInfo
  • Changed SetPropertyAndNotifyOnCompletion signature (7-14x faster, 60% memory usage reduction)
  • Changed signature of APIs, ditched Expression<Func<T>> args
  • Added new SetProperty<T, TModel> overload to allow stateless delegates and better performance
  • Added cancelation support to AsyncRelayCommand types (and interfaces)
  • Improved XML docs with info about exceptions being thrown by the various APIs
  • Removed Ioc class and Microsoft.Extensions.DependencyInjection dependency

Messenger (#3424)

  • Added a new WeakReferenceMessenger type
  • Renamed Messenger to StrongReferenceMessenger
  • Memory usage and performance improvements to StrongReferenceMessenger
  • Changed IMessenger.Register signature to remove closures (35% memory usage reduction, no this captured)
  • Added IMessenger.Cleanup API to help with extensibility
  • Changed default messenger for ObservableRecipient to WeakReferenceMessenger
@Sergio0694
Copy link
Member Author

Posting an update here regarding the changes to the SetPropertyAndNotifyOnCompletion method.
The signature now has a custom delegate instead of the ref + Expression<Func<T>> pair, which gives us:

  • Less parameters (just one and with no duplication, so it's less error prone and verbose)
  • Faster performance (no reflection anymore)
  • Less memory usage

Code changes:

private Task myTask;

public Task MyTask
{
    // BEFORE
    set => SetPropertyAndNotifyOnCompletion(ref myTask, () => myTask, value);

    // AFTER
    set => SetPropertyAndNotifyOnCompletion(() => ref myTask, value);
}

And some benchmarks:

image

@Sergio0694
Copy link
Member Author

Sergio0694 commented Aug 23, 2020

Hey @nanney54, let's continue here from your original comment in the issue for the Preview1.

I've come up with a solution I liked to add cancellation support to the async commands, so this new feature should be available in the next preview of the MVVM Toolkit, and of course you can also try it out already through the CI preview build 😄

The changes were added in 06cc520, here's the new IAsyncRelayCommand interface:

/// <summary>
/// An interface expanding <see cref="IRelayCommand"/> to support asynchronous operations.
/// </summary>
public interface IAsyncRelayCommand : IRelayCommand, INotifyPropertyChanged
{
    /// <summary>
    /// Gets the last scheduled <see cref="Task"/>, if available.
    /// This property notifies a change when the <see cref="Task"/> completes.
    /// </summary>
    Task? ExecutionTask { get; }

    /// <summary>
    /// Gets a value indicating whether running operations for this command can be canceled.
    /// </summary>
    bool CanBeCanceled { get; }

    /// <summary>
    /// Gets a value indicating whether a cancelation request has been issued for the current operation.
    /// </summary>
    bool IsCancellationRequested { get; }

    /// <summary>
    /// Gets a value indicating whether the command currently has a pending operation being executed.
    /// </summary>
    bool IsRunning { get; }

    /// <summary>
    /// Provides a more specific version of <see cref="System.Windows.Input.ICommand.Execute"/>,
    /// also returning the <see cref="Task"/> representing the async operation being executed.
    /// </summary>
    /// <param name="parameter">The input parameter.</param>
    /// <returns>The <see cref="Task"/> representing the async operation being executed.</returns>
    Task ExecuteAsync(object? parameter);

    /// <summary>
    /// Communicates a request for cancelation.
    /// </summary>
    /// <remarks>
    /// If the underlying command is not running, or if it does not support cancelation, this method will perform no action.
    /// Note that even with a successful cancelation, the completion of the current operation might not be immediate.
    /// </remarks>
    void Cancel();
}

Both AsyncRelayCommand and AsyncRelayCommand<T> now include additional constructors taking a Func<CancellationToken, Task> delegate, so that you can also wrap asynchronous methods using the token parameter to monitor whether a cancellation has been requested. The commands will take of creating and handling those tokens, so you'll just need to use that Cancel method if you want to request a cancellation, and that request will be relayed to the wrapped method through that token. If you just wrap a method taking no token, the behavior is unchanged compared to commands today.

Here's a small example:

async Task<string> FooAsync(CancellationToken token)
{
    await Task.Delay(10000, token); // Delay with the token
    return "Hello world";
}

// Create a new async command wrapping the async method with
// the token parameter. The C# compiler will automatically pick the
// right constructor depending on the signature of the method we
// are using here (depending on whether it takes a token or not).
var command = new AsyncRelayCommand(FooAsync);

// Use the command as usual...

Let us know what you think! 😊

@nanney54
Copy link

It was fast ! did you have a git stash ready on your PC before my post ? 😁

@ghost ghost added Completed 🔥 and removed In-PR 🚀 labels Sep 24, 2020
@Sergio0694 Sergio0694 linked a pull request Sep 24, 2020 that will close this issue
7 tasks
@Sergio0694 Sergio0694 reopened this Sep 24, 2020
@ghost ghost added in progress 🚧 and removed Completed 🔥 labels Sep 24, 2020
@mysteryx93
Copy link

This rewrite of MvvmLight sounds like an excellent idea! We've been left with no official .NET Core support for quite some time. And IMO, this should have been part of the .NET Framework from the start. WPF/UPF development has been a mess because many required bricks were missing and everybody was hacking around it on their own.

If you rethink a minimalistic support, however, I'd like to question the Messaging feature itself. In my mind, let's say I want a "Notifications" section in my app, I would create a Singleton class that manages those communications in a strongly-typed way. Are there cases where using Messaging is actually a recommended design? Please help me understand.

Another thing that frustrated me with WPF is that lots of required basic bricks were missing and I had to search the web for hacks and solutions all the time until I built a basic library of fundamental tools that should have been in the framework.

I've put those tools here.

PushBinding, Int32Extension, MethodBinding and perhaps a few other classes should be part of the fundamental framework IMO. With the idea of keeping it basic.

@Sergio0694
Copy link
Member Author

Sergio0694 commented Sep 24, 2020

Hey @mysteryx93 - glad to see your enthusiasm for this project! 😊
This library is indeed positioned to help fill those gaps you mentioned in the BCL, as well as providing basic build blocks for people using MVVM. Since we're going full .NET Standard here, the issue of supporting different runtimes is also indirectly solved by this approach.

"In my mind, let's say I want a "Notifications" section in my app, I would create a Singleton class that manages those communications in a strongly-typed way."

That's... Exactly what the messenger is 😄
We're in the process of writing down full docs for all the existing APIs, in the meantime you can check out the preview docs and the sample app at https://aka.ms/mvvmtoolkit.

As for the other components you mentioned, we don't currently plan to include things like that, because the package itself is completely platform agnostic. For instance, that method binding you mentioned for WPF is effectively replaced by just x:Bind to functions on UWP. Or, you could just create a command to wrap the target method, on whatever framework you're using.

Because of that, we will not include any framework-specific APIs in this package, but you're free to integrate it into your own codebase by adding your custom extensions where you feel the need 👍

@mysteryx93
Copy link

mysteryx93 commented Sep 24, 2020

That's... Exactly what the messenger is 😄

My point is... IMO that's a very niche usage that I haven't found a use for yet, and I don't see what it has to do with MVVM either. Perhaps some application can use it, but why is it a core MVVM feature?

We're in the process of writing down full docs for all the existing APIs, in the meantime you can check out the preview docs and the sample app at aka.ms/mvvmtoolkit.

WOW! MVVM Docs!?? That would be a nice supplement!!

(in the meantime I found out that there is some PRISM doc that can serve to understand MvvmLight)

btw the link you posted is broken

@Sergio0694
Copy link
Member Author

Mmh not sure why that link wasn't working, I've fixed it now (also, it was in the first post in this issue too) 😄

My point is... IMO that's a very niche usage that I haven't found a use for yet, and I don't see what it has to do with MVVM either. Perhaps some application can use it, but why is it a core MVVM feature?

You can argue it's not a part of MVVM per se, yes. But it's still a useful feature to have, especially since it's fully self-contained in the library, so we can include it without having to pull other dependencies in, so there's no cost in doing that. Also, MvvmLight offered that too, so it only seemed natural to include a migration path for those users as well. There aren't other exactly equivalent services available right now (not that I'm aware of), so we figured it'd be a good idea to provide an implementation ready to use out of the box for those that are interested. If you don't need it, you can just not use it. All the components in the MVVM Toolkit are completely modular, so you're free to pick up and choose what parts to use without being forced into any of them 👍

@mysteryx93
Copy link

I'm also curious about one thing. MvvmLight had a special RelayCommand for WPF otherwise the default one wouldn't work correctly, and this ugly work-around was the only solution they found.

How would this situation be handled by this framework? I think the problem had to do with command enabled/disabled status being properly updated on the UI.

@Sergio0694 Sergio0694 linked a pull request Nov 12, 2020 that will close this issue
7 tasks
@Sergio0694 Sergio0694 changed the title [Feature] Microsoft.Toolkit.Mvvm package (Preview 3) [Feature] Microsoft.Toolkit.Mvvm package (Preview 5) Nov 13, 2020
@laurentkempe
Copy link

laurentkempe commented Nov 15, 2020

I think you should reconsider the decision to have WeakReferenceMessenger.Default auto magically injected through the ObservableRecipient default constructor.

It seems like a convenience for users which want to use WeakReferenceMessenger.Default everywhere. But for people which are working on more complex application, which will not use WeakReferenceMessenger.Default, it is trap, as it hides the choice of messenger you are doing when you inherit from ObservableRecipient.
We experienced in my team similar issues using MVVMLight which had a quite similar building through a default constructor passing null and then in the Messenger getter it would default to Messenger.Default.
It happened quite often to have developers inheriting from ViewModelBase forgetting to pass the correct Messenger that we ended up implementing a DummyMessenger throwing for all access. It replaced Messenger.Default so that we were sure that the correct Messenger was used or the developer will immediately see at run time.

By having only one constructor for ObservableRecipient in which developers will have to specify IMessenger you apply the principle of least surprise and avoid any problem. So, I would not have any default!
If we continue the discussion even further, then why not StrongReferenceMessenger? Especially, when I read that you recommend "It is still good practice to unsubscribe them though, to improve performances" while using WeakReferenceMessenger.Default. I want to make clear that I don't recommend this neither, I definitely would like that there is no default, again so that developers have no surprise.

@mrlacey
Copy link
Contributor

mrlacey commented Nov 17, 2020

Following on from the comment by @laurentkempe, is it possible to have the best of both worlds by having a single constructor with a default value for the parameter?

protected ObservableRecipient(IMessenger messenger = WeakReferenceMessenger.Default)
{
    ...
}

If I was concerned about developers in a team calling the constructor and not passing a specific messenger, I'd add an analyzer to the project to check for this.


Having the StrongReferenceMessenger forces users to do more work for a benefit they may not see or be able to measure.
Defaulting to using WeakReferenceMessenger.Default means developers get something that works with minimal effort. This also makes migrating from other libraries easier.
If the developer wants to improve performance they can unsubscribe from messages.
If they then want to optimize performance even further they can change to use the Strong Reference version but they have to do more work for those benefits.

@Sergio0694
Copy link
Member Author

Sergio0694 commented Nov 17, 2020

@mrlacey Unfortunately that is not a valid C# signature, as values for default parameters need to be compile-time constants.
In this case WeakReferenceMessenger.Default is just a statically initialized property, so that doesn't qualify 😟

I agree that using the WeakReferenceMessenger type as the default is the right choice though (as much as I like the StrongReferenceMessenger too, for obvious reasons 😄). While that is much faster and more efficient, it does require more attention to use and could result quite tricky for developers migrating an app from eg. MvvmLight, which uses weak references to track message recipients. Developers are still able to manually opt-in into the faster one assuming they'll take the time to make sure it's properly setup - making that a deliberate decision reduces the risk of unwanted surprises (ie. sneaky memory leaks).

@laurentkempe
Copy link

is it possible to have the best of both worlds by having a single constructor with a default value for the parameter?

@mrlacey Even if that would work, and it doesn't because WeakReferenceMessenger.Default is not compile time constant (oh I see now @Sergio0694 replied to it also), it is not a great idea to have those hidden defaults in a framework like MVVM toolkit. I feel the same about WeakReferenceMessenger.Default and StrongReferenceMessenger.Default, why providing a Default, such a singleton could be implemented in user's solution in a couple of minutes. where it is needed.

I agree that using the WeakReferenceMessenger type as the default is the right choice though

My point @Sergio0694 was not about WeakReferenceMessenger.Default or StrongReferenceMessenger.Default I would like to put emphasis on the choices you are making for your users! I don't think it is the role of a toolkit like MVVM Toolkit to make those default choices. Your point to ease developer's life to port from MVVMLight is a valid point, but should we carry, in a new toolkit, the drawbacks of an older one? I was involved in MVVMLight when Laurent Bugnion started it, and I am an old user of it and still use it. I would like that some of the not-so-great design decisions from the past doesn't end up in MVVM Toolkit.
And the two, I currently see, are the default injection of WeakReferenceMessenger.Default behind the user of ObservableRecipient constructor and both WeakReferenceMessenger.Default and StrongReferenceMessenger.Default which are singletons and should not be in the toolkit cause of this doesn't lead developers to make a conscious decision.

@michael-hawker
Copy link
Member

Thanks @laurentkempe, I do like the idea of forcing the decision for those upgrading. I mean there is a benefit to using the new model; we just want to keep it simple as well for those onboarding to MVVM for the first time. Not having to worry about the lifetime of the messenger is a benefit from that standpoint.

This is also not the default case as usually ObservableObject will be used unless they want to add messaging capabilities.

In your cases of using MVVMLight in the past, would you typically have a base class setting up the messenger? If so, then having the extra code only being in one place vs. several for an upgrade path wouldn't be a big overhead. So far our migration guide seems fairly straight-forward.

@jamesmcroft you've done a lot with MVVMLight as well, thoughts?

@laurentkempe
Copy link

laurentkempe commented Nov 17, 2020

You are welcome @michael-hawker I am trying to help!

I totally understand the point easing the onboarding of newcomers and see it has a valid point and has you said the default case is usually ObservableObject! Nvertheless for more complex applications people will be using ObservableRecipient and I those ones need to make a conscious decision about using WeakReferenceMessenger or StrongReferenceMessenger.

In your cases of using MVVMLight in the past, would you typically have a base class setting up the messenger?
Yes, we have a complex application which rely on multiple messengers and we are using ViewModelBase from MVVMLight as our base class. So, yes, all our ViewModels set the Messenger through the base constructor of ViewModelBase. We use the basic principle of dependency injection and compose our application (see one much simpler example here) from the top without relying on service locator or singletons like WeakReferenceMessenger.Default which makes writing tests more complex.

So far our migration guide seems fairly straight-forward.

For sure as you replicate the way MVVMLight was doing it but with its drawback too!

@Insire
Copy link

Insire commented Nov 21, 2020

I recently found out that this is going to be a thing and so i checked out the most recent public preview 4.

I don't really have complains and like what i see, how ever i'd like to see 2 things added, if possible:

  1. I've seen the OnChanged callback in ObservableObject.SetProperty, but i'm missing a OnChanging callback in the same method. I'm aware that i can achieve similar funcionality by subscribing to the corresponding eventhandler that comes with the class. However having it there by default would be nice.
  2. The IMessenger implementations have ways to clean up any resources. I'd like to be able to clean them with something that implements IDisposable, so that it neatly integrates with existing code.

@cirrusone
Copy link

Are you able to make both ObservableObject and ObservableRecipient interfaces as well? It's sometimes difficult to use these due to multiple inheritance so having IObservableObject and IObservableRecipient is much easier.

@Sergio0694
Copy link
Member Author

Sergio0694 commented Jan 22, 2021

The new update for the MVVM Toolkit is ready for review now, posting an update here for those interested.
Other than the general improvements and tweaks you can see in the commits and in the first post here, this new PR includes a number of additions for the ObservableValidator class (ie. our INotifyDataErrorInfo implementation), with changes that have been requested in a number of issues (eg. microsoft/microsoft-ui-xaml#179 and #3665), as well as being discussed on Discord and other channels. I hope with the updated API surface, this class will be a solid base type for developers writing validation forms 😄

For starters, here's the complete API breakdown for the ObservableValidator class (updated to a3c2f63):

namespace Microsoft.Toolkit.Mvvm.ComponentModel
{
    public abstract class ObservableValidator : ObservableObject, INotifyDataErrorInfo
    {
        public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;

        protected ObservableValidator();
        protected ObservableValidator(IDictionary<object, object> items);
        protected ObservableValidator(IServiceProvider serviceProvider, IDictionary<object, object> items);
        protected ObservableValidator(ValidationContext validationContext);

        public bool HasErrors { get; }

        protected bool SetProperty<T>(ref T field, T newValue, bool validate, [CallerMemberName] string? propertyName = null);
        protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, bool validate, [CallerMemberName] string? propertyName = null);
        protected bool SetProperty<T>(T oldValue, T newValue, Action<T> callback, bool validate, [CallerMemberName] string? propertyName = null);
        protected bool SetProperty<T>(T oldValue, T newValue, IEqualityComparer<T> comparer, Action<T> callback, bool validate, [CallerMemberName] string? propertyName = null);
        protected bool SetProperty<TModel, T>(T oldValue, T newValue, TModel model, Action<TModel, T> callback, bool validate, [CallerMemberName] string? propertyName = null) where TModel : class;
        protected bool SetProperty<TModel, T>(T oldValue, T newValue, IEqualityComparer<T> comparer, TModel model, Action<TModel, T> callback, bool validate, [CallerMemberName] string? propertyName = null) where TModel : class;

        protected bool TrySetProperty<T>(ref T field, T newValue, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null);
        protected bool TrySetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null);
        protected bool TrySetProperty<T>(T oldValue, T newValue, Action<T> callback, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null);
        protected bool TrySetProperty<T>(T oldValue, T newValue, IEqualityComparer<T> comparer, Action<T> callback, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null);
        protected bool TrySetProperty<TModel, T>(T oldValue, T newValue, TModel model, Action<TModel, T> callback, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null) where TModel : class;
        protected bool TrySetProperty<TModel, T>(T oldValue, T newValue, IEqualityComparer<T> comparer, TModel model, Action<TModel, T> callback, out IReadOnlyCollection<ValidationResult> errors, [CallerMemberName] string? propertyName = null) where TModel : class;

        protected void ValidateAllProperties();
        protected void ValidateProperty(object? value, [CallerMemberName] string? propertyName = null);

        protected void ClearErrors(string? propertyName = null);

        public IEnumerable<ValidationResult> GetErrors(string? propertyName = null);
        IEnumerable INotifyDataErrorInfo.GetErrors(string? propertyName);
    }
}

In particular, the additions from #3562 include:

  • ValidateAllProperties, which automatically performs validation on all the public properties with validation attributes on the current viewmodel, and updates the errors for all of them, raises the necessary events, etc. Essentially, you can call this method before submitting a form, and it'll automatically perfom the validation on the entire model.
  • ValidateProperty, which performs manual validation on a property. This can be useful when dealing with properties whose validation state depends on other properties, so that you can trigger validation when the other value changes (see [Feature] The new MVVM-Library should allow to run validation manually #3665).
  • ClearErrors, which clears errors either from a specific property, or for the entire entity (similar behavior to GetErrors).

cc. @michael-hawker @timunie @thomasclaudiushuber @stevenbrix

@ghost ghost closed this as completed in #3562 Feb 13, 2021
ghost pushed a commit that referenced this issue Feb 13, 2021
## Follow up to #3428 
<!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. -->
This PR is for tracking all changes/fixes/improvements to the `Microsoft.Toolkit.Mvvm` package following the Preview 4.

<!-- Add a brief overview here of the feature/bug & fix. -->

## PR Type
What kind of change does this PR introduce?
<!-- Please uncomment one or more that apply to this PR. -->

- Feature
- Improvements
<!-- - Code style update (formatting) -->
<!-- - Refactoring (no functional changes, no api changes) -->
<!-- - Build or CI related changes -->
<!-- - Documentation content changes -->
<!-- - Sample app changes -->
<!-- - Other... Please describe: -->

## Overview

This PR is used to track and implement new features and tweaks for the `Microsoft.Toolkit.Mvvm` package.
See the linked issue for more info, and for a full list of changes included in this PR.


## PR Checklist

Please check if your PR fulfills the following requirements:

- [X] Tested code with current [supported SDKs](../readme.md#supported)
- [ ] ~~Pull Request has been submitted to the documentation repository [instructions](..\contributing.md#docs). Link: <!-- docs PR link -->~~
- [ ] ~~Sample in sample app has been added / updated (for bug fixes / features)~~
    - [ ] ~~Icon has been created (if new sample) following the [Thumbnail Style Guide and templates](https:/windows-toolkit/WindowsCommunityToolkit-design-assets)~~
- [X] Tests for the changes have been added (for bug fixes / features) (if applicable)
- [X] Header has been added to all new source files (run *build/UpdateHeaders.bat*)
- [X] Contains **NO** breaking changes
@Sergio0694
Copy link
Member Author

Sergio0694 commented Feb 13, 2021

The MVVM Toolkit Preview 5 is now merged and available in the preview Azure feed from master! 🚀

It features a much improved ObservableValidator class and many other tweaks, optimizations and bug fixes.

Thank you everyone for all the feedbacks throughout all these iterative previews, it's been super helpful and the MVVM Toolkit has improved a lot over time already! I'll keep an eye out for other possible minor tweaks to slip in before the first official release, but this is all looking really great so far - we're almost there! 🎉 🎉

@mrlacey
Copy link
Contributor

mrlacey commented Feb 15, 2021

The MVVM Toolkit Preview 5 is now merged and available in the preview MyGet feed from master! 🚀

Please confirm where this is available from.

The wiki points to a MyGet feed that no longer exists (https://dotnet.myget.org/gallery/uwpcommunitytoolkit) and it appears that support for the use of MyGet was removed in place of using Azure DevOps.

The main Azure DevOps feed only lists preview4.

The Azure DevOps Pull Request feed has a version of this available but as version 7.0.0-build.840.g99bd68412a.

Have I missed something?
Is there a different feed that I should be using?

It seems misleading to say preview 5 is available in that it's not obvious how to get it and try it out.

@Sergio0694
Copy link
Member Author

The wiki points to a MyGet feed that no longer exists (https://dotnet.myget.org/gallery/uwpcommunitytoolkit) and it appears that support for the use of MyGet was removed in place of using Azure DevOps.

Where do you see that link mentioned? It might just be a leftover.
The new feeds for the preview packages are mentioned in this wiki page, and the one with the packages built from pushes/merges into master is this one: https://pkgs.dev.azure.com/dotnet/WindowsCommunityToolkit/_packaging/WindowsCommunityToolkit-MainLatest/nuget/v3/index.json.

It seems misleading to say preview 5 is available in that it's not obvious how to get it and try it out.

I didn't say "Preview 5", I specifically said the "MVVM Toolkit Preview 5", to mean that the changes in my PR called "MVVM Toolkit Preview 5" are now merged and therefore available through CI packages. For instance, you can find those bits in the latest one, which is v7.0.0-build.836.1 (you can check the list of the recent published packages here). I probably should've phrased that sentence to make it clear I wasn't referring to an actual Preview release of the whole Toolkit, that's a fair point, I absolutely didn't mean to be misleding with my message 🙂

Hope this clears things up! 😄

@Panda-Sharp
Copy link
Contributor

Panda-Sharp commented Feb 15, 2021

I probably should've phrased that sentence to make it clear I wasn't referring to an actual Preview release of the whole Toolkit, that's a fair point, I absolutely didn't mean to be misleding with my message 🙂

Hope this clears things up! 😄

Yeah I think the origin of the misunderstanding is here:
"The MVVM Toolkit Preview 5 is now merged and available in the preview MyGet feed from master! 🚀"

@mrlacey
Copy link
Contributor

mrlacey commented Feb 15, 2021

Yes, I didn't think there was a MyGet feed any more and so searched for MyGet in the repo. It found references that I have now raised a PR to correct. (CommunityToolkit/WindowsCommunityToolkit-wiki#19)

@Rosuavio Rosuavio unpinned this issue Mar 9, 2021
@Rosuavio Rosuavio pinned this issue Mar 9, 2021
@michael-hawker michael-hawker unpinned this issue Mar 16, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 16, 2021
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.