MVVM Data Binding across multiple content pages in one application not working (.NET Maui)
*Keep in mind I'm also using the CommunityToolkit.Mvvm package in NuGet
Im watching this video on MVVM and binding commands in a class to interact with the user interface and Im confused on why its not working for me. I used the viewmodel of my MainViewModel class and its DataType connected to the class in multiple different contentpages and for some reason its not creating new controls on the collectionview of the target mainpage when I click the button with the binded add command :') Help please?
https://www.youtube.com/watch?v=5Qga2pniN78
The overall problem is: The problem is the commands are not properly binding through multiple content pages, and thus the controls I want to be added to the mainpage can't be added for some reason.
I have my project on github and I will share it for anyone who wants to look at the problem on why the bindings aren't working. Thanks!
dotnet
YouTube
.NET MAUI Data Binding with MVVM & XAML [5 of 8] | .NET MAUI for Be...
Learn more ā”ļø https://learn.microsoft.com/training/paths/build-apps-with-dotnet-maui/
Welcome to the .NET MAUI for Beginners Series where you will learn the basics of building multi-platform apps with .NET MAUI for iOS, Android, macOS, and Windows from a shared C# code base. In this video, James introduces us to the MVVM (Model-View-ViewModel) ...
171 Replies
A codesample or a link to your project would be helpful.
Ok, on my way
Git username please?
GitHub
GitHub - Morganiscooler/Notepad-Bugged-with-breakpoint-: A randomly...
A randomly generated code keeps popping up and will not let me use the app anymore - Morganiscooler/Notepad-Bugged-with-breakpoint-
I made it public actually, now you can check for the problems
I'm not an expert for MAUI, but isn't your
SwipeView
missing a container element for your actual data to display?
Besides that I would rather use BindingList
over ObservableCollection
since it implements IBindingList
and it's proxying the INotifyPropertyChanged
from it's provided generic type.
Also I cannot find any binding to the command, which should be bound to AddCommand
(autonaming in communitytoolkit).
Plus, I advise to use the attribute [RelayCommand]
instead of [ICommand]
, so the private method Add
becomes actually AddCommand
and can be bound to, like Command={Binding AddCommand}
The add command is in the NotePage xaml
the only button that exists in notepage's xaml binds to the AddCommand. It also has a on click event that leads back to the home page (Mainpage)
What Im trying to do is when you go back to the home page thru the button, not only does it go back to the home page but it binds the newly created note to the collectionview
But that's a different page, with it's very own instance of the viewmodel
ah
how do I tie it into the mainpage?
I was thinking mvvm can do something with this, I want to access the controls of another content page with what I previously did with the other content page
Not out of the box, every
Window
, Page
, etc. has it's own instance of a vm and everytime you display a page, it'll be a fresh instance of the page and the vm. Things need to be cached through a manager, like a page manager/navigation manager.
Besides, if you wanna use a collection throughout the application, you have some options, the easiest I guess would be to create a static collection and manipulate it, like a singleton collection, here you still have the option to directly bind to the singleton, which gotta be of observable type, or use a regular type like List
and display those in an observable type inside the vm. Another approach is through reference from the mainwindows vm.Do you have documentation to support your idea?
so I can look at some done examples of this
the way the datacontext works is, if u set a data context in the Window, it will span to all childs unless a child override it with another datacontext
and yes if u want to share a collection between multiple pages/vms ideally u want an object in common u can access it from, so u can inject that in the vms and easilly have access to it.
Keeping in mind concurrency exists, so if u run into those waters trouble and + code going your way
So I believe I already have the vm made following the tutorial for MVVM, just put my existing code into there so I can access the common controls?
if this works, then will the controls still only exist for the specific contentpages I want them to be on? (Ex: collection view growing only on the mainpage)
Oh, and the third and more MVVM'ish way to achieve this is through services and dependecy injection, in this case a singleton service that lives throughout the applications runtime.
I'm more drawn to break some rules of MVVM, for it seems more straight forward to approach things like it in a more traditional way.
However, imho, it depends of the scope and the application/project which one to choose from.
What do you mean by traditional? now im curious
The reason I prefer MVVM is because I already have the viewmodel set up and everything š
Oh no, that would result in a long discussion about mvc,mvp & mvvm and, imho, the very thin line that separates those.
Ok so just stick to mvvm then since I have it prepared and im going down that path ?
Also, after u answer that
Well well, let's get it this way, since we separate between layers in MVVM, we have the VM, which is the observable layer. I stick to those observable collections and properties only there and I'm using more generic types like
List
in the model layer.
You might see the problem with this traditional approach, so peeps adds another service layer which is somewhere between the VM and the BL. Things gonna start to become way more complex if you need to have the objects inside a collection to notify the view to refresh, you don't wanna mix up(!) the layers here.
But starting with your simple collection of string
, you can create a static class called Globals.cs
in which you store all the application stuff that's processed throughout the runtime, e.g. List<string> Notes
. Accessing it passivly through the VM by creating a new instance of BindingList
or ObservableCollection
on instancing. Every change made to the collection is made through the singleton and the ObservableCollection
is re-created, that also solves the problem of child items not being refreshed in ObservableCollection
.
But you may wanna try the other ways as well so you can decide for yourself which one fits best in your project.or it could be as simple as using https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/messenger
forgot this exist, not sure if its for his use case, but this allows u to communitcate between vms for example.
by subscribing on one end and sending something from another end
it results in triggering an end in the subscriber
Yet another way to rome š
But reading all that it sounds like u went wrong somewhere, u shouldn't have the need to trigger a button from a another vm
u can definitively have events or means to communicate with each other either by having an instance of it or some other way but not in the form of emulating or wanting to emulate a button click in another place, if u fall in the latter here, then yeah something wrong
I want the former
communication through the content pages is all that i want
using what i have which is the MVVM
I think, you need to expand the idea and not just think of the VM and View layer. Since this app is a about some Notes, this means that those will be stored eventually on the disk and loaded on startup. This is all done in BL, and has nothing to do with any VM or View.
The scope of that object is global not just bound to the observable layer.
thats true
but right now I can't even get it to store the newly made notes onto the first home page
So Im thinking of trying this for now
would it be a good idea?
I haven't look at your code, is 3 am, and on phone so... tmr I will give it a look and see... remember me if I forget
Yesyes I will š«” gn
reminder ^
what are the files related to the issue ur trying to solve?
just so I dont have to re-read everything
^
I want to bind controls across multiple contentpages using MVVM
it's not working though, and I followed .NET maui's tutorial
I'm not sure if it is because the data binding can only happen on one content page or if I'm not doing the right action to connect them together
After you take a look at my code, could you let me know if this solution is still appropriate to the project?
what i mean is can u tell which button does not work so I could look at it specifically to tell u what u can do
Oh yeah
CollectionView on mainpage doesn't work at all, NotePage's button is not doing the addcommand when it goes back to the mainpage, and Create_newnote's entry box probably isn't storing the string either
continue button?
this page
click that, then there will be a button called Home
up to that button its working?
when you click on home, there is an event action that takes you back to the mainpage, but I also binded the command called AddCommand where it is supposed to automatically add the newly created note, along with the string to the collectionview in the mainpage
I see
The entry isn't working right now, it didn't store the string to the collectionview
just pointing out a few things you are hardly using mvvm
your mostly using code behind
I followed what the guy used in the video, right now just trying to get new collectionview items whenever the addcommand is prompted
so yeah its not that complex right now
I am going thru it slowly as time allows me
another huge misconception u have is
u believe that creating a new object and assigning things to it will remain across instances
it does not
for example
NotePage notePage = new NotePage();
notePage.Title
you literally creating and assinging things to a whole new page
in some places u create multiple instances
what u want to do is use models
not the actual page it self
or
use the navigation parameters
once im done looking and dumping info I will post some code and whatnot
just bear with it for a moment
Thank you so much
Yeah I was thinking of making it the same instance instead of different
at the end I think I'll put NotePage notePage = new NotePage(); on the very outside not in any of the private voids, so then it should be the same notePage being accessed
I also have a question, from create new note, u send it to the note page and only then u register it by clicking home
is note supposed to be a "View Note page" that u just create?
if so then u should be actually creating it from the create page and redirecting it to the View Note page
Yeah I think so
I want the user to be able to type all over it then it automatically gets stored on the mainpage's collection view, to then be clicked on later and viewed based on whatever was saved when they click back to home
ok so the Add button should actually be on the create page instead, something like Create and view note...
which goes to Note Page
and then u have a back button or go back to home button or w/e
Ok
So the continue button should be binded to the addcommand
yeah and the last action of it could be a navigation to view page
in order for the MainViewModel to span thru all pages the way ur working
u also need to add the pages to your DI
which means no more creating instances
and the navigation changes a bit
i.e.:
or if u need to pass a parameter
which u dont actually need to because the mainviewmodel is shared
so u can technically access Title from any of them
Cool, navigation goes last always gotcha
yes for example
also count needs to be outside the method here or it will be always 1
u also need to add you pages to the navigation
AppShell.xaml
Should there be a MainViewModel vm class being passed in the parameters of each page's main()?
yes u would have something like u have in the MainPage
since there's multiple pages being used, or should it only be for the mainpage
Ok, gotcha so repeat for each page since im using all the content pages
would the line highlighted be useless here for navigating back to the homepage or should I keep it
all the 3 lines are useless
from the highlighted and above
they also make no sense
but the original mainpage contained vm as a parameter so i would need to pass it again
creating a new instance of MainViewModel means a clean mainviewmodel that has no idea what has happened before
in the constructor
the constructor is when the object is created
BackHome is not a constructor its an event
that arbritrary happens after the page was created and when u press something
whats the alternative way to not create a new instance but to use the original preexisting mainpage as the directory?
there is no alternative
u do it the same way its being done in the MainPage
you do it via the page constructor
do u know what a constructor is?
Sorry no
I might though if you can tell me what contentpage or class you're referring to
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors
give a look here and then answer it
and then I will explain further
Btw I tried but the ICommand above is giving it an error
I am sure it will, in the navigation part if u dont have the appshell.xaml properly set
like I said above
but focus on the link above
Yeah I added those, appshell should be ok for now
According to the documentation, a constructor is called when a class is created. It allows the programmer to set default values, limit instantiation, and make code easily to read and flexible to change
ok but what piece of code from say NotePage is the constructor
I think an example in my mvvm case would be the auto generated code from the Icommand generator right?
no
look at the page I gave u above it have examples
with code and all
ur talking on the documentation and not the content pages right
yes the documentation above constructors
it has the information and examples
but I want the answer based on your NotePage.xaml.cs file
to make sure u understood what its talking about
let me see if there is a better resource about constructors moment
https://www.geeksforgeeks.org/c-sharp-constructors/
public NotePage(){}
post the actual code its not just that from the NotePage.xaml.cs
and then post me the one from MainPage.xaml.cs
yep
the comments are just plans you may ignore them
that's fine I just needed to make sure we are on the thing
so u know that
š
and u know in code what is the constructor
and u already made the changes to make it look like the MainPage one
(MainViewModel vm)
this is a parameter
and also a dependency NotePage requires to work
and DependencyInjection fullfills those dependencies
that's why u register them in your MauiProgram.cs
so that those dependencies can be resolved
Alright so thats why you sent that screenshot here right, because I added these
exactly
there is a lot more to it, but I wont get much into details for now as its not needed
but there is a lot more behind it that u should look up later and learn
u should also go thru some fundamentals c# course because a lot of the fundamentals is very important to know
so u are not lost
Is notepage's constructor passing in the correct parameter? It should still be the mainviewmodel I believe
what happens is
Ok, for now Im focused on this if you dont mind
I'll definetly go there later
Dependency Injection have a collection of those instances created
and when u have a constructor that requires one
it will provide it with one based on what it has, in this case it has a Singleton, which technically means a unique instance that will live thru the app lifecycle in short
so whenever the constructor asks for MainViewModel it will provide the only one instance of it that exists in your app
if u create a new instance outside of the register service it will be a new and completely different instance of it
brief video on DI
which is why I need to delete the new instance being passed into the already existing mainpage
and use the one we made in mauiapp
right?
which one?
the three lines you said were useless
yes
exactly
and also why I use the GoToAsync
which is able to go thru the existing registered pages
in the routing
š
Ohhhh
wait so just add the routing into the nav asynch
function
huh?
brb food
Oh wait
go to asynch is the function you would use for the route since the route already exists in the appshell
Im using nav.pushasynch() right now '
yeah u would be using gotoasync
I gave some examples of how above
where are the examples?
got it
For the notepage's back home button though, should I sitll use a navigation push asynch since I want it to go back to the main page
for the example you showed above it appears to just automatically add it to the mainpage's directory, which I do need but navigation here is also wanted
just to explain the way its done in the video is not wrong, but imo this fit better the way your going about navigation and using the view model.
normally you have viewmodel per page not shared like that
Whats the alternative to the home button? does it need to use the shell navigation method aswell? or can I just use my per usual mainpage class
im assuming shell method because it needs to store the new note data right
u can't use your per usual mainPage
that is used for when u create a new object
u would just do
Push and Pop are used to include a new page into the stack
Ok so by this logic for the other 2 content pages when they need to navigate to the next page, it would also require shell right?
because its continuous?
mainpage --> create new page --> note page --> back to mainpage
more like
As your current tree stands
if u further add a tab then it could be for example
where notes is the tab
True
for navigation purposes though are we still using await Shell.Current.GoToAsync so it doesn't become a new instance everytime?
yes unless at some point u absolutely want something shortlived
where u PushAsync a new page
and then u hit the back button its removed
and what was done on it lost
https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/shell/navigation?view=net-maui-8.0
and
https://learn.microsoft.com/en-us/dotnet/maui/user-interface/pages/navigationpage?view=net-maui-8.0
so ill make a new shell async function to whatever control is binded to the next page button in the content page, within the viewmodel correct?
new shell?
ur not making a new shell
the function that navigates to the next page
gotoasynch
i forget the function names
you're just calling the statically available instance of Shell
oh
that is why fundamentals are important to know
so this wouldn't work?
if the Route is named CreateNewNote it would
but if u copy pasted what I posted above
I dont have the
Ah lol ok
I use c# naming convention for the most part
so I would not name files with _ etc
So now I have this I just have to search for the bindable command, then bind it to the button I want to bind it to right
https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md
search for the bindable command?
Yeah
because i used icommand it automatically generates a command for going to the desired page i guess
u mean add the command to the button?
yes
yes it generates ToCreationPageCommand
if u hover your mouse over ICommand it explains what it does
also u seem to be using an old version of MVVM Toolkit
these days it uses RelayCommand instead of ICommand
eh to follow the tutorial i had to go back to 8.0.3
I realized but then if i update it i have to change it
Also question: when I click the lets get started/add new note button on the main page (they're supposed to be one instance ill change that), should it create a new instance with a navigation.pushasync method or use the shell method which will store the progress being made?
because for each new note created, it has to be a new note being created, but the new note needs to be saved
its minor changes from what u have in your code
but sure
what do you mean
well you wipe the text of the create new note once u add it
so should be fine to reuse it without create a new
Ok sounds good
im binding the command then
I deleted the old click event for each of these buttons by the way to avoid creating the new instances as you said
So it would also be a smart idea to use shell's gotoasync for the actual notepage because I'm making the notepage on the creation page, then the selected items transfer through shell?
sure
but u would want to pass a parameter to it
so it know which item to load
because I assume it will be more than just a title at some point
which in this case u would be using a model
Like if the note contained an image or something?
I mean I dont know but looking at this I can see a title, a color, a font size at the very minimum
Got it
Now the collection view is growing
What do you mean by parameter?
as in like, the name of the new note so it knows the keywords to finding it?
š
š
this page further down also explain how to use it
imagine u have 100 notes
if u pass the id as parameter then I know u only want that specific note
if u pass the title and 2 titles are the exact the same how does it know which?
Oh yeah I need this
especially for a search function im going for
wait so if I pass in the id into the parameters automatically, then the search engine should also be able to look for the specific note based off its keywords right?
this has nothing to do with search engine
its a parameter ur passing down to your page
I want note with id 1
then in your page u have logic to pull note with id 1 from your database or where ever that comes from
Alright, I'll try doing that and update you on how it goes
just for reference though I do want the id to be literally searchable if that works
that is logic u will write for ur search
whether it looks up the title or id or image or w/e property u want to lookup
Ah alright
Also, is it possible to maybe change the title of the NotePage to the text entered in the entry on the creation page?
I could probably do something with the notepage's title and the Text but im unsure how the title can be accessed for shell pages
no idea, maybe bind the Title of the content page
Alright
Ty for the help im gonna rest for a bit and come back to work on it
Is there a way to add spacing in between the newly added collection view items? I want some spacing inbetween the rows
I know of but it can't be used with it seems?
that's why u use a datatemplate
its used so you can define what u want the entries to look like
u missed part of it from the video u watch and only added the swipe
u can have grid, among other elements in a datatemplate
Data templates - .NET MAUI
.NET MAUI data templates provide the ability to define the presentation of data on supported controls. Data templates can be chosen at runtime, using a DataTemplateSelector, based on the value of a data-bound property.
and
Populate a CollectionView with Data - .NET MAUI
A .NET MAUI CollectionView is populated with data by setting its ItemsSource property to any collection that implements IEnumerable.
Thanks I'll check these out when I'm home
Oh I see
the person used a padding of 0,5 in the grid ah
There's a problem where each time I create a new note, for some reasons it creates two or more notes when it should just be one note being created. Why does this happen?
most likely because you're inserting it twice or doing some behavior that makes it look like so
inserting twice
Thanks š
Is there a way to connect a command to the swipe view?
I want to click on each newly created note that appears in the collectionview, and for them to open to respective note it has saved. I want to then be able to swipe left on each newly created note in the collection view, then be able to delete/favorite the notes.
SwipeView - .NET MAUI
The .NET MAUI SwipeView is a container control that wraps around an item of content, and provides context menu items that are revealed by a swipe gesture.
it shows how to do all that in there
the MAUI documentation is really good u should research a bit about the controls you're using so u understand it better
Does swipeview work for windows
Because I searched it up and it says for touch only and not cursor
In that case would 3 dots with the option of deleting the note be better since this is a primarily windows focused app?
all u have to do is run the app and try
and if it does not work then all u have to do is remove it and add buttons to your datatemplate or something else
Yeah I think I'll switch out the swipeviews for buttons
Im thinking of deleting the "Let's get started!" button when the first item (note) gets added to the mainpage, is there a way you can directly delete a button control from the mainpage xaml when the items are being added in the mainviewmodel.cs?
The reason I ask this is because: when I move the "let's get started!" Button into the collection view, I can no longer access the button's x:Name, and therefore the function that allows the button to randomly change colors won't work
How do I organize it in the collection view so it can still access the function, while being able to be removed when new items are added into the collection view?
u wouldn't place the lets start in the collectionview its not part of it
u could use a collapsible grid or something that when items.count > 0 it hides the lets start
Oh collapse grid is a thing? Let me look at the documentation
How would the collapsible grid be accessible since x:Name wouldn't be in the mainviewmodel?
Or are you saying Items can still be accessed in the code behind the mainpage, where x:Name is used
Bindings
With binding, you can also access the property of the let's get started button? So then I could do like button.hide
you could yes
https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/relative-bindings?view=net-maui-8.0
https://learn.microsoft.com/en-us/dotnet/maui/xaml/fundamentals/data-binding-basics?view=net-maui-8.0
after reading these 2 articles i'm still unsure of how to access the controls in my mainviewmodel
Relative bindings - .NET MAUI
.NET MAUI relative bindings are created with the RelativeSource markup extension, which sets the binding source relative to the position of the binding target.
Data binding basics - .NET MAUI
.NET MAUI data bindings allow properties of two objects to be linked so that a change in one causes a change in the other.
I know I need to data bind to the Isvisible property, and it can only be executed upon items.count > 0
But the x:Name "Notes" is inaccessible
and the articles above seem to be talking about relative databinding, like controls controlling other controls within the same page
Im not sure how to access Notes in short
I dont see why u would need that
also in MVVM which ur not properly using u never use x:Name
its all via bindinds, commands, bahaviors, dps
https://stackoverflow.com/questions/58786536/xamarin-hide-the-button-if-condition-is-false
I found this, but Im wondering how I can adjust it so when the Items.count > 0 it hides the button itself?
Stack Overflow
Xamarin: Hide the button if condition is false
I am new to Xamarin Forms.
I want to know how to hide a button if a specific condition is false.
ex: I need to hide the submit button until the text field has a value.
(if the text field is null,
Binding="{Binding Items.Count}" Value="0"
I created this function below:
I'm trying to set the value where for any value > 0, it deletes the button, but for some reason even though I bind this function to the value, it still does not delete the button
why, u can just use the above
if Items.Count is 0 the button stays
if not it gets collapsed
also was this chatgpt generated?
that looks super weird
no
I copied it from stack overflow
I have this but the button doesn't get removed
whats wrong with this?
thats not working for me
u probably need to set the button to start in collapsed visibility
I did that and it first removed the button, then after I started creating the notes the button came up
When I set the value to 0 and create a new note, the button is still there afterwards
therefore shouldn't creating an int function that returns all the values greater than 0 be the best choice for setting a value?
if not, could you take a look at this problem please? I have no idea where it went wrong š
I am sorry but I will be blunt here as much as I want to help you, you need to properly learn c# and stop trying to copy paste code that u think that solves your problem and will just plug and play to your code...
This code for example that u said u copied from stackoverflow that u have no idea what it does...
it doesn't even use Items which is your list of items to get the count out of it and I doubt u understand it yourself, its a mix of creating a new list to return a list of ints to use linq to see which item inside the list is the biggest and at the end it just uses the count to return the information which is not even using anything outside that block of code.
so I suggest u go back to the bottom and learn c#
https://learn.microsoft.com/en-us/shows/csharp-fundamentals-for-absolute-beginners/
as much as it hurts me, this was my last contribution here, I am not doing research and writing code for u to complete your app
I'll look at the documentation, thank you
It's been a while since I've done C# so I definitely need to look back at the fundamentals š„²but thank you for the help, I greatly appreciate it