Coder Social home page Coder Social logo

mvvm-helpers's Introduction

MVVM Helpers

Collection of MVVM helper classes for any application.

Build Status:

NuGets

Name Info
MvvmHelpers NuGet
Development Feed MyGet

Get Started

Checkout this awesome video I made introducing you to MVVM Helpers :)

What's included?

I wanted to keep this library really small and just created it for myself, but I hope others find it useful. Here is what I added in and feel free to request new things in the Issues tab.

ObservableObject

Simple implementation of INotifyPropertyChanged that any class can inherit from.

/// <summary>
/// Sets the property.
/// </summary>
/// <returns><c>true</c>, if property was set, <c>false</c> otherwise.</returns>
/// <param name="backingStore">Backing store.</param>
/// <param name="value">Value.</param>
/// <param name="propertyName">Property name.</param>
/// <param name="onChanged">On changed.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
protected bool SetProperty<T>( ref T backingStore, T value,
    [CallerMemberName]string propertyName = "",
    Action onChanged = null)
// <summary>
/// Raises the property changed event.
/// </summary>
/// <param name="propertyName">Property name.</param>
protected void OnPropertyChanged([CallerMemberName]string propertyName = "")

BaseViewModel

Your base view model! It implements INotifyPropertyChanged and a bunch of default properties such as Title, SubTitle, Icon, IsBusy, IsNotBusy, CanLoadMore.

Grouping

Best way to group items into a Key/Value pair ObservableCollection for managing groups of data. See my blog post: Enhancing Xamarin.Forms ListView with Grouping Headers

ObservableRangeCollection

A super awesome ObservableCollection that adds important methods such as: AddRange, RemoveRange, Replace, and ReplaceRange.

Utils

Any and all extension methods that are nifty. Here are the current ones:

/// <summary>
/// Task extension to add a timeout.
/// </summary>
/// <returns>The task with timeout.</returns>
/// <param name="task">Task.</param>
/// <param name="durationMilliseconds">Duration in Milliseconds.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public async static Task<T> WithTimeout<T>(this Task<T> task, int durationMilliseconds)

AsyncCommand, Command, and WeakEventManager

MVVM Helpers now adds in AsyncCommand and Command under the MvvmHelpers.Commands namespace! It also has a nice WeakEventManager to help your events be garbage collection safe :)

Code & Inspiration from the following:

Want To Support This Project?

All I have ever asked is to be active by submitting bugs, features, and sending those pull requests down! Want to go further? Make sure to subscribe to my weekly development podcast Merge Conflict, where I talk all about awesome Xamarin goodies and you can optionally support the show by becoming a supporter on Patreon.

mvvm-helpers's People

Contributors

adamdiament avatar ahmedalejo avatar azureadvocatebit avatar berrysoft avatar james-alt avatar jamesmontemagno avatar kubaszostak avatar mjfreelancing avatar ravinderjangra avatar thenderson21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mvvm-helpers's Issues

Index out of range exception when calling ReplaceRange on an ObservableRangeCollection

@jamesmontemagno Hi!

I'm getting Index out of range exception on ios(simulator and iphone device). Android works fine!

Nugets:
"Xamarin.Forms" Version="4.8.0.1187-pre2"
"Refractored.MvvmHelpers" Version="1.6.2"

Trace:

    at System.Collections.Generic.List`1[T].get_Item (System.Int32 index) [0x00009] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:161
    at System.Collections.ObjectModel.Collection`1[T].System.Collections.IList.get_Item (System.Int32 index) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/ObjectModel/Collection.cs:266
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.ElementAt (System.Int32 index) [0x0000f] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:254
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.get_Item (System.Int32 index) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:40
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.get_Item (Foundation.NSIndexPath indexPath) [0x00019] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:96
    at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].UpdateTemplatedCell (Xamarin.Forms.Platform.iOS.TemplatedCell cell, Foundation.NSIndexPath indexPath) [0x00012] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:199
    at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].GetCell (UIKit.UICollectionView collectionView, Foundation.NSIndexPath indexPath) [0x00033] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:84
    at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].GetPrototype () [0x0005d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:263
    at Xamarin.Forms.Platform.iOS.ItemsViewLayout.DetermineCellSize () [0x0004e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:201
    at Xamarin.Forms.Platform.iOS.ListViewLayout.ConstrainTo (CoreGraphics.CGSize size) [0x0001e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ListViewLayout.cs:16
    at Xamarin.Forms.Platform.iOS.ItemsViewLayout.UpdateConstraints (CoreGraphics.CGSize size) [0x0003f] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:96
    at Xamarin.Forms.Platform.iOS.ItemsViewLayout.InvalidateLayout () [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:535
    at (wrapper managed-to-native) ObjCRuntime.Messaging.void_objc_msgSend(intptr,intptr)
    at UIKit.UICollectionView.ReloadData () [0x0000d] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.3.2/src/Xamarin.iOS/UICollectionView.g.cs:687
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.Reload () [0x00071] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:142
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.CollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x00198] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:129
    at Xamarin.Forms.Platform.iOS.ObservableItemsSource.CollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x000b7] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:108
    at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1021
    at Foundation.NSAsyncSynchronizationContextDispatcher.Apply () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.3.2/src/Xamarin.iOS/Foundation/NSAction.cs:178 --- End of stack trace from previous location where exception was thrown ---
    at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
    at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.3.2/src/Xamarin.iOS/UIKit/UIApplication.cs:86
    at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.3.2/src/Xamarin.iOS/UIKit/UIApplication.cs:65
    at Mobile.iOS.Application.Main (System.String[] args) [0x00001] in /Main.cs:17 

Debugging Bindings

I'm using Xamarin Forms UWP and I have no problem binding to primitives, but my binding to an object won't show up. In addition, I get the below listed pop-up when debugging:

My Class:

public class ScoreSheetColumn : BaseViewModel
{
public bool ColumnEnabled { get; set; }
public string ColumnName { get; set; }

    int onestotalvalue;
    public int OnesTotalValue
    {
        get { return onestotalvalue; }
        set
        {
            SetProperty(ref onestotalvalue, value);
        }
    }

    string onestotalstring;
    public string OnesTotalString
    {
        get { return onestotalstring; }
        set
        {
            SetProperty(ref onestotalstring, value);
        }
    }

My ViewModel:

class GamePlayViewModel : BaseViewModel
{
ScoreSheetColumn player1Col1;
public ScoreSheetColumn Player1Col1
{
get { return player1Col1; }
set { SetProperty(ref player1Col1, value); }
}

My Xaml:

<ContentPage.BindingContext>
<ViewModels:GamePlayViewModel />
</ContentPage.BindingContext>

        <Label Text="{Binding Player1Col1.OnesTotalString}" TextColor="Black" />

My Pop-up:

Locating source for 'C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs'. Checksum: SHA1 {72 d8 5a 44 3e 3a 1e 28 74 3a a 82 f9 9d 23 15 9b 79 38 23}
The file 'C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs' does not exist.
Looking in script documents for 'C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs'...
Looking in the Edit-and-Continue directory 'F:\Yatzy\Yatzy21\enc_temp_folder'...
The file with the matching checksum was not found in the Edit-and-Continue directory.
Looking in the projects for 'C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs'.
The file was not found in a project.
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\include'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\include\cvt'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\include\msclr'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\include\sys'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\include\thr'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\x64'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\arm'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\concrt'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\i386'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\linkopts'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\stl'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\vccorlib'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\crt\src\vcruntime'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\atlmfc\src\mfc'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\atlmfc\src\atl'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\atlmfc\include'...
Searching for documents embedded in the symbol file.
An embedded document was not found.
The debug source files settings for the active solution indicate that the debugger will not ask the user to find the file: C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs.
The debugger could not locate the source file 'C:\projects\mvvm-helpers\MvvmHelpers\ObservableObject.cs'.

ObservableCollection<Grouping> on iOS throws NullReferenceException at third call

Hi James!

I'm having a lot of fun with your helpers so far. However, on iOS I have a really weird problem:
In my solution I use an ObservableCollection of groupings. I have a method that clears and refreshes the Collection (either when the page appears or when the user uses pull-to-refresh).
Everything works great on Android. On iOS however, the method always works two times (initial loading of the page and once more, either by pushing and popping a page or pull-to-refresh) and then fails. A try-catch shows me a NullReferenceException.

var groupings = new List<Grouping<string, ReportRepresentation>>();
if (userReports.Count > 0)
    groupings.Add(new Grouping<string, ReportRepresentation>("Meine Meldungen", userReports));
if (commentedReports.Count > 0)
    groupings.Add(new Grouping<string, ReportRepresentation>("Kommentierte Meldungen", commentedReports));
if (upvotedReports.Count > 0)
    groupings.Add(new Grouping<string, ReportRepresentation>("Positiv bewertet", upvotedReports));
if (downvotedReports.Count > 0)
    groupings.Add(new Grouping<string, ReportRepresentation>("Negativ bewertet", downvotedReports));
            
foreach (var grouping in groupings)
    UserRelatedReports.Add(grouping);

It's thrown when trying to execute the very last line of this excerpt. The ObservableCollection (UserRelatedReports) and Grouping are both fine (not null). Here's the Exception's StackTrace:

at Xamarin.Forms.Platform.iOS.EventTracker.LoadRecognizers () [0x0005d] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\EventTracker.cs:373 
at Xamarin.Forms.Platform.iOS.EventTracker.OnElementChanged (System.Object sender, Xamarin.Forms.Platform.iOS.VisualElementChangedEventArgs e) [0x0004e] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\EventTracker.cs:439 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x0002c] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.ViewRenderer`2[TView,TNativeView].OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x00000] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.LabelRenderer.OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x0003e] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\LabelRenderer.cs:134 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x00118] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.RendererPool.UpdateRenderers (Xamarin.Forms.Element newElement) [0x0008c] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\RendererPool.cs:157 
at Xamarin.Forms.Platform.iOS.RendererPool.UpdateNewElement (Xamarin.Forms.VisualElement newElement) [0x00080] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\RendererPool.cs:78 
at Xamarin.Forms.Platform.iOS.VisualElementPackager.SetElement (Xamarin.Forms.VisualElement oldElement, Xamarin.Forms.VisualElement newElement) [0x00050] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:161 
at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnRendererElementChanged (System.Object sender, Xamarin.Forms.Platform.iOS.VisualElementChangedEventArgs args) [0x0000f] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:144 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x0002c] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x00118] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.RendererPool.UpdateRenderers (Xamarin.Forms.Element newElement) [0x0008c] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\RendererPool.cs:157 
at Xamarin.Forms.Platform.iOS.RendererPool.UpdateNewElement (Xamarin.Forms.VisualElement newElement) [0x00080] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\RendererPool.cs:78 
at Xamarin.Forms.Platform.iOS.VisualElementPackager.SetElement (Xamarin.Forms.VisualElement oldElement, Xamarin.Forms.VisualElement newElement) [0x00050] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:161 
at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnRendererElementChanged (System.Object sender, Xamarin.Forms.Platform.iOS.VisualElementChangedEventArgs args) [0x0000f] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:144 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x0002c] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.FrameRenderer.OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\FrameRenderer.cs:11 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x00118] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in <f321195339234cc7a2f7f1d5fa08167d>:0 
at Xamarin.Forms.Platform.iOS.ListViewRenderer+UnevenListViewDataSource.CalculateHeightForCell (UIKit.UITableView tableView, Xamarin.Forms.Cell cell) [0x00035] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:745 
at Xamarin.Forms.Platform.iOS.ListViewRenderer+UnevenListViewDataSource.GetEstimatedRowHeight (UIKit.UITableView table) [0x00095] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:689 
at Xamarin.Forms.Platform.iOS.ListViewRenderer.UpdateEstimatedRowHeight () [0x0005f] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:399 
at Xamarin.Forms.Platform.iOS.ListViewRenderer.UpdateItems (System.Collections.Specialized.NotifyCollectionChangedEventArgs e, System.Int32 section, System.Boolean resetWhenGrouped) [0x000bc] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:527 
at Xamarin.Forms.Platform.iOS.ListViewRenderer.OnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Renderers\ListViewRenderer.cs:298 
at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000a] in <48a479a3d1104fc6b15657327889ea3c>:0 
at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].OnCollectionChangedGrouped (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x000e3] in <48a479a3d1104fc6b15657327889ea3c>:0 
at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].OnProxyCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e, System.Boolean fixWindows) [0x00008] in <48a479a3d1104fc6b15657327889ea3c>:0 
at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].OnProxyCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00000] in <48a479a3d1104fc6b15657327889ea3c>:0 
at Xamarin.Forms.ListProxy.OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000a] in D:\agent\_work\1\s\Xamarin.Forms.Core\ListProxy.cs:233 
at Xamarin.Forms.ListProxy+<>c__DisplayClass33_0.<OnCollectionChanged>b__0 () [0x00018] in D:\agent\_work\1\s\Xamarin.Forms.Core\ListProxy.cs:206 
at Xamarin.Forms.ListProxy.OnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x000a0] in D:\agent\_work\1\s\Xamarin.Forms.Core\ListProxy.cs:225 
at Xamarin.Forms.ListProxy+WeakNotifyProxy.OnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00031] in D:\agent\_work\1\s\Xamarin.Forms.Core\ListProxy.cs:394 
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000f] in <fc81bc57986f4d1eb3ccf442a0589629>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00009] in <fc81bc57986f4d1eb3ccf442a0589629>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].InsertItem (System.Int32 index, T item) [0x00024] in <fc81bc57986f4d1eb3ccf442a0589629>:0 
at System.Collections.ObjectModel.Collection`1[T].Add (T item) [0x00020] in <bdb3aaa208384edf9f1266721cf8f9c1>:0 `

I'm not sure if this is even related to the helpers, but I thought you might have run into something similar.

I've tried it both on a simulated and a real iPhone X.

Thanks a lot!
Jan

Adding IValueConverters?

Would you want to add some common IValueConverters to this library, such as InverseBooleanConverter? Or does it not fit in this particular library?

If you want them, I can open a PR with it.

InsertRange Help :D

Hi James!. I would like to have a method to insert a collection, would you mind to give me some guidance of how can i help you to build such feature? Thanks :D

Index out of Range, with 1.6.0-beta

Hi James, thanks for this Awesome little library!

Since #56 #nullable enable, 1.6.0-beta:

When doing AddRange to a new, empty ObservableRangeCollection, I get an Index out of range exception.

Many thanks,

ReplaceRange on non empty ObservableRangeCollection with empty collection does not raise event

The following test cases would fail

Given a non empty ObservableRangeCollection A
  And an empty collection B
 When A.ReplaceRange(B)
 Then collection change events should be raised for A, since itยดs now empty
  But no event is raised instead
[TestMethod]
public void ReplaceRange_on_non_empty_collection_should_always_raise_collection_changes()
{
    var collection = new ObservableRangeCollection<int>(new [] { 1 });
    var toAdd = new int[0];
    var eventRaised = false;
                
    collection.CollectionChanged += (s, e) =>
    {
        eventRaised = true;
    };
    
    collection.ReplaceRange(toAdd);
    Assert.IsTrue(eventRaised, "Collection Reset should be raised.")
}

[TestMethod]
public void ReplaceRange_on_empty_collection_should_NOT_raise_collection_changes_when_empty()
{
    var collection = new ObservableRangeCollection<int>();
    var toAdd = new int[0];
                
    collection.CollectionChanged += (s, e) =>
    {
        Assert.Fail("Collection changes should NOT be raised.");
    };
    
    collection.ReplaceRange(toAdd);
}

WPF

Does this library work with a WPF application - Not Xamarin?

Release date for version 1.5

Hi James,

Can you tell me when can we expect a new release for version 1.5 for this NuGet ?
I want to integrate AsyncCommands as a part of my project.
Thanks in advance!

null reference on observable object string property

Hi
Great library!
Weird issue:
I have a simple class. just some string properties. At some point, i cant figure out when exactly, i get an "object reference not set to an instance of an object" when setting the value for a string property. the stack trace leads to line 54 in your observableobject class. on "SetProperty" the error gets thrown...

public class DynaLogItem : ObservableObject { //ommited some proprs for brevity... public string Subtitle { get; set; } // here on set i get the error... }

stack trace points here:
https://github.com/jamesmontemagno/mvvm-helpers/blob/e9d6deb27734664410f6f5382a76ad985368c365/MvvmHelpers/ObservableObject.cs#L54

Its kind of hard to explain whats happening but can you think of any reason why this seems to randomly happen? I can confirm that the "DynaLogItem" is not null...

thanks for any help
Roy

.NET Standard compatibility?

I just started building a new XF solution (iOS, Android, UWP). It's my first solution with .Net Standard 1.4. I tried adding MvvmHelpers but I always get errors when building.

Severity Code Description Project File Line Suppression State
Error Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'MvvmHelpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken='. Perhaps it doesn't exist in the Mono for Android profile?
File name: 'MvvmHelpers.dll'
at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.Resolve(AssemblyNameReference reference, ReaderParameters parameters)
at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.Resolve(AssemblyNameReference reference)
at Xamarin.Android.Tasks.ResolveAssemblies.AddAssemblyReferences(DirectoryAssemblyResolver resolver, ICollection`1 assemblies, AssemblyDefinition assembly, Boolean topLevel)
at Xamarin.Android.Tasks.ResolveAssemblies.Execute(DirectoryAssemblyResolver resolver) Roomplan.Android

I tried cleaning (+ deleting bin&obj folders) and rebuilding, without success. Is the library not ready for Standard or is something wrong on my end?

Greetings and thank you for the work.

Task<T>.WithTimeout() TimeSpan overload should use TotalMilliseconds instead of Milliseconds

https://github.com/jamesmontemagno/mvvm-helpers/blob/master/MvvmHelpers/Utils.cs

TimeSpan.TotalMilliseconds converts the entire TimeSpan to milliseconds, whereas TimeSpan.Milliseconds simply returns the milliseconds portion of the timespan. If I wanted to timeout in 10 seconds, and used

Task task; //...
await task.WithTimeout(TimeSpan.FromSeconds(10));

I would get a timeout of 0 milliseconds instead of 10000 milliseconds.

Q: How to pass generic observablerangecollection

Hi,

I was trying to implement generic listview for dropdown(using listview in details page).

But I am stuck with the approach referred in issue #28 . near the lines "Now when I click on country label in my ProfileSettingsPage it takes me to listview where I select particular country from list provided and when I comeback(Ondisappearing) I am passing this country item back to ProfileSettingPage using messaging center with selectedItem as _parameter(TArgs)."_

I wanted this approach to work for all kinds of listview not just for country. So I have to make observablerangecollection generic.

I tried below approach:

public class SelectListItemsPageViewModel{

public ObservableRangeCollection<SelectList<T>> Data { get; } = new ObservableRangeCollection<SelectList<T>>();

ctor{ 
var result=  GetFromApi_BasedOnParameter_PassedToCtor();
// here return type can be of type IEnumerable<SelectList<T>>  where T can be guid or int or string etc.

Data.ReplaceRange(result);
}
}

and my SelectList is below

public class SelectList<TKey>
   {
       public TKey Value { get; set; }

       public string Text { get; set; }

       public bool IsSelected { get; set; }

       public string PropertyName { get; set; }
   }

image

My questions

1:Why not ObservableRangeCollection is taking generic list(PFA) where all I am doing is just passing the result(which at this time have some type returned) to Data object(generic ORC).

2.How to make this approach generic(not related to MVVMHelper) because I have to pass something to constructor to decide api calls.
Tried making viewmodel generic which in turn caused page to have generic like SelectListPage...
You see how complicated this is becoming when I tried to make generic listview.

Can you help me with this?

UpdateRange?

First, thanks for the nice ObservableCollection class. Very convenient !

I was wondering if you could consider adding an "UpdateRange" and/or "AddAndUpdateRange" method where the collection passed would update any items in the collection if they already exists in it?

We have implemented something like this, but if you could add it to the package, this might be a nice addition. Would not mind a code review also if not. ;)

What are your thoughts?

   public void UpdateRange(IEnumerable<T> collection, Predicate<T> match, bool InsertOnUpdate = true)
    {
        if (collection == null)
            throw new ArgumentNullException("collection");

            CheckReentrancy();

            var oldItems = new List<T>();
            var updatedItems = new List<T>();
            var newItems = new List<T>();

            int startIndex = this.Count;
            var changedItems = collection is List<T> ? (List<T>) collection : new List<T>(collection);
            foreach (var item in changedItems)
            {
                var updated = item;
                var index = ((List<T>) this.Items).FindIndex(match);  //using a Predicate is allowing us to pass the way we want to compare the items, for example, our objects all have a Key property what we want to compare with, so we pass match = o => o.Key == updated.Key

                if (index > -1)
                {
                    oldItems.Add(this.Items[index]);
                    this.Items[index] = updated;
                    updatedItems.Add(updated);
                }
                else
                {
                    if (InsertOnUpdate)
                    {
                        // There are some situation when we do NOT want to insert new items, we just want to update if they are present in the collection.
                        this.Items.Add(updated);
                        newItems.Add(updated);
                    }
                }

            if (newItems.Count > 0)
            {
                OnPropertyChanged(new PropertyChangedEventArgs("Count"));
                OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));  //for all indexes
                                                                            //todo, do this for each index? OnPropertyChanged(new PropertyChangedEventArgs("Item[" + index + "]"));  //for a single item
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems.ToArray(), startIndex));
            }

            if (oldItems.Count > 0)
            {
                if (!(newItems.Count > 0))  //already notified above otherwise
                    OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));  //for all indexes
                                                                                //todo, do this for each index? OnPropertyChanged(new PropertyChangedEventArgs("Item[" + index + "]"));  //for a single item
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, oldItems.ToArray(), updatedItems.ToArray()));
            }
        }
    }

raise ObservableRangeCollection on item propertychanged

hey all
maybe im missing something stupid and im sure its been asked before but for some reason cant find my answer:
if i have a ObservableRangeCollection and a property in MyItem changes (MyItem is an observableobject), how do i get the observablecollection to notice the change?

When using ObservableRangeCollection.AddRange with IEnumerable, CollectionChanged event may be corrupt

I have forked this project and created a unit test to illustrate my concern, see here.

ObservableRangeCollection.AddRange allows for a collection of type IEnumerable<T>. However, if the enumerable is invalidated upon traversal, the CollectionChanged event will yield an invalid NewItems list.

Question is, whether collection should be of type IEnumerable<T>, or if it should be limited e.g. to IList<T>?

'Title' iOS iPhoneSimulator versus iPhone device not appearing

I am working on a sandbox xamarin.forms.map application using databinding(pedley to create bindable objects) and custom renderers(to make pins and locations similar among devices) and using mvvm-helpers nuget package to create observablerangecollections, geolocation (ala Monkey6000 app).

When I deploy the application to the iOS target on the iPhoneSimulator I get the 'Title' appearing.

When I deploy the application to the iOS target on the iPhone device I do not get the 'Title' appearing.

I have tried on a couple different iOS deployment targets 9.3 and 11.0. Maybe I'm missing something in the iOS deployment to the iPhone? Any suggestion is much appreciated. Thank you.

Exposing Items in Grouping?

Hi James,

Was wondering if you could expose the Items property as public in the Grouping class? We have a need for that.

public class Grouping<K, T> : ObservableCollection<T>
{
	public K Key { get; private set; }

            **public IList<T> Items { get { return base.Items; } }**

	public Grouping(K key, IEnumerable<T> items)
	{
		Key = key;
		foreach (var item in items)
			this.Items.Add(item);
	}
}

Thanks and have a good one.

P

Can we have Footer along with Title

Hi,
I have a control template where I am setting bindable footer.

I am inheriting BaseViewModeI and would like to have Footer as well along with Title . I can extend the class but I feel it would be nice if it is already coming from BaseViewModel.

ObservableObject.PropertyChanged event is not weak

Hi,
I see that the implementation of ObservableObject uses the PropertyChanged event, but it is not through the WeakEventManager (see line 47 of ObservableObject.cs).
If this event is not unhooked, it could create memory leaks in applications.
So I would suggest to replace it like in Commands/Command.cs, line 114.
Would you appreciate if I would submit a PR?
Regards, Damiano

Any update on when the code will come out of Beta?

I saw you left a comment that you were waiting on fixing outstanding bugs but looks like some of those bugs have been around for a very long time. My company would like to use the helpers but with it being in beta it's not so easy to convince them.

Q : How to update particular property of BindableObject without again using SetProperty

Hi James,

Today I came with some situation where I need to update only one property of class object(this is set using SetProperty method)


 private ProfileSettings profileSettings;
 public ProfileSettings ProfileSettings
  {
     get { return profileSettings; }
     set { SetProperty(ref profileSettings, value); }
  } 

here is my ProfileSettings class used for binding


 public class ProfileSettings : BaseViewModel
 {
   public string Country { get; set; } 

  //some other properties like timezone,dateformat etc...
 }

Now when I click on country label in my ProfileSettingsPage it takes me to listview where I select particular country from list provided and when I comeback(Ondisappearing) I am passing this country item back to ProfileSettingPage using messaging center with selectedItem as parameter(TArgs).

Problem
If I don't make the Country bindable inside ProfileSettings class like below,it's not updating my label on page.

    private string country;  

    [JsonProperty("cntry")]
    public string Country
    {
      get { return country; }
      set { SetProperty(ref country, value); }
     }  

It's same for all other properties in my ProfileSettings class.

Question: Is there any way to make all the properties inside class bindable automatically... Or Am I doing something wrong with approach?

.net core 3.0 end of life

This release has reached end of life, meaning it is no longer supported.
We recommend moving to a supported release.

AddRange not firing for all Elements added

Whenever I call AddRange and pass an IEnumerable, my bound Listview only gets updated with the first element in the IEnumerable Added. If i replace NotificationMode to NotificationMode.Reset, it updates but the index of the Listview jumps to the Last item. I wonder if I'm doing something differently or wrong

Concurrent collection?

Hi again,

Our ObservableCollection is being updated on background threads from real-time pub-sub connections and it happens (rarely) in some cases that we get 'The collection has changed' type error when (I guess), there are another update that comes trough before the UI has completed its update.

I was wondering if there were any plan to make ObservableCollection thread-safe (ConcurrentObservableCollection?)

Thanks again for the contribution, really appreciate.

Latest stable NuGet package is over 2.5 years old

I'm moving away from my go-to MVVM framework due to compatibility issues with Shell and came across your MvvmHelpers library. I would very much like to leverage many of the features you've added in recent years, but all of the packages you've published since v1.3 have been in beta. Are there specific concerns that have prevented you from publishing recent releases as stable?

ExtendedObservableObject and new attribute

Description

I propose to expand the base class with useful functions.

AutoProperty Description

public int FirstProperty
{
	get => GetValue<int>();
	set => SetValue(value);
}

I think that this method of implementation to simplify the work with properties.

Attributes Description

NotifyProperty
DependsOnProperty
that allow you to keep track of property updates and call PropertyChange for related properties

public class MockExtendedViewModel : ObservableObject
{

	[NotifyProperty(nameof(ThirdProperty))]
	public int FirstProperty
	{
		get => GetValue<int>();
		set => SetValue(value);
	}

	[DependsOnProperty(nameof(FirstProperty))]
	public int SecondProperty
	{
		get => GetValue<int>();
		set => SetValue(value);
	}

	public int ThirdProperty
	{
		get => GetValue<int>();
		set => SetValue(value);
	}
}

If you assign a new value to FristProperty, you will also be instantiated by the OnPropertyChanged event for ThirdProperty.

Also trigger events for SecondProperty because it depends on FirstProperty.

@jamesmontemagno If you are interested in this I will do PR
I also have such a small library, and I think that this code can be useful.

ObservableRangeCollection<T>.ReplaceRange not recognized by Xamarin.Forms CollectionView

Got a Xamarin.Forms CollectionView whose ItemsSource is an ObservableRangeCollection. Items are loaded asynchronously at page appearing. The ViewModel replaces existing items and adds new items to the collection by calling the ReplaceRange. The CollectionView somehow doesn't notice data change and nothing is displayed. Applying one of the following changes does show the items.

Workaround 1: Call ObservableRangeCollection.Clear and afterwards ObservableRangeCollection.AddRange

Workaround 2: Use ObservableCollection, call Clear and add items in a foreach loop using the Add method.

Reproduction Link:
https://github.com/xamadev/ObservableRangeCollectionError
Tested on iPhone simulator only

Thanks to @jamesmontemagno for the great helperclasses!

SetProperty Usage

So is there a Xamarin Forms example of using the mvvm-helpers SetProperty with all parameters. How to do you take advantage of the Action and validate parameters from a model or viewmodel where model inherits from ObservableObject and viewmodel inherits from BaseViewModel with MVVM pattern?

Orgbrat

Custom observableobject

Hi,
This is very useful plugin.I am currently using observable range collection like below
public ObservableRangeCollection Employees{ get; } = new ObservableRangeCollection();

I would like to use observable object(because propertychanged logic is written in it) but of type Employee just like I did for range.
For ex; ObservableObject<Employee>.

Otherwise I have to do something like

public Employee Employee{
get...
set{
SetProperty(....);
}

BTW,I am inheriting from BaseViewModel.

I am quite new to xamarin forms. Am I missing (went through monkey tutorial but could not find things related to this) .

WithTimeout wont stop timed-out tasks

Hi, looking at the implementation -- won't the net result be that; the task itself will not stop running even if the timeout succeeds first?

Is that intentional?

Not practical for models that already derives from another types

In our models instead of deriving from INotifyProperty changed, we derive from ObservableObject. So in many cases where we have models that already derives from another classes, this wont help.
For instance in my models i have class called Tournament that derives from IGrouping because i have another types like Group and Match that shares a lot of functionality. How would i derive from Observable object?

Use ObservableRangeCollection as ring-buffer

Would be possible to extend the functionality for the ObservableRangeCollection to support the implementation of a ring-buffer ?
For instance a new "AddRangeAdjustToMaxCapacity()" method, that checks if the range of items to be added would exceed the ObservableRangeCollection capacity, and remove the neccesary amount of items from the collection, before adding the new ones. I know that this could be reached by calling RemoveRange and after that AddRange, but would be much better to have it in a single call. Of course, an additional ObservableRangeCollection(int capacity) constructor would also be needed, to be able to set the max. capacity of the collection

Please change the ObservableObject.OnChangeProperty and SetProperty to Virtual on Nuget.

MVVM helpers is such an easy to use package! But i did like to have some customization.
I understand that i can download the source code and compile a customized version for myself.
Changing the modifier allows users that uses the NuGet directly able to customize themselves.
If its possible, please change the ObservableObject.OnChangeProperty and SetProperty on the NuGet to Virtual to enable overrides.

Thank you.

Change to MIT-License

Hi James,

could you change the License to MIT please?

I have a collection of all your plugins in my app (they are all MIT). Makes it easier ;-)

BR
Marius

RaiseCanExecuteChanged not included in IAsyncCommand

Hi James - Thanks for the great plugin! I'd like to upgrade to the latest version, but I have a dependency on https://github.com/brminnick/AsyncAwaitBestPractices/ on which I think your implementation is based on?

The interface for IAsyncCommand there has a useful method RaiseCanExecuteChanged. I see that your concrete AsyncCommand implementation has it, but not the interface itself.

I would find this useful, is this something you'd accept a PR for, or is there a reason you'd left it out of the interface definition?

Android.OS.NetworkOnMainThreadException: '' on RefreshCommand

I have the following code:

public ICommand RefreshCommand { get; }

public HomeViewModel()
{
     Title = "Test";
     Youtube = new List<Rank>();
     Task.Run(async () => await LoadRanks());
     RefreshCommand = new AsyncCommand(LoadRanks);
}
Task.Run(async () => await LoadRanks());

Runs through with out any issues, (before i added the Task.Run thing i got the same error i now get if the command gets called).
If i trigger the RefreshCommand by refreshing my CollectionView i get the error:
Android.OS.NetworkOnMainThreadException: ''

Method that the command runs:

async Task LoadRanks()
{
       var client = new RanksClient();

        Youtube = (await client.GetViewsScoreboardAsync(RankViewsPlatform.Youtube, Size.Small)).ToList();
        Instagram = (await client.GetLikesScoreboardAsync(RankLikesPlatform.Instagram, Size.Small)).ToList();
        TikTok = (await client.GetLikesScoreboardAsync(RankLikesPlatform.TikTok, Size.Small)).ToList();
        Twitter = (await client.GetLikesScoreboardAsync(RankLikesPlatform.Twitter, Size.Small)).ToList();
        Twitch = (await client.GetViewersScoreboardAsync(RankViewerPlatform.Twitch, Size.Small)).ToList();
}

If you guys have any idea how to solve this, please let me know.
https://user-images.githubusercontent.com/33844665/103391376-7d192e80-4b19-11eb-87a0-bf31875a5e2a.mp4

Remove Task.Delay in tests

As for now Task,Delay is called in almost every tests.
However task is not beeing awaited and therefore are not used.

For example OnDidntChange in ObservableObjectTests is using delay between change of the property.
When rasing a event in this example propertyChanged the delegate are run, after each other, this delays the execution after the delegate has been executed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.