✅ Unsure of how to fix these avalonia errors
LoginView.axaml: https://pastebin.com/Kb0resSx
LoginViewMode.cs: https://pastebin.com/BcuyxF5S
Splash.axaml: https://pastebin.com/iazXwshx
SplashViewModel.cs: https://pastebin.com/U1FEwwSU
UpdateAvailableView.axaml: https://pastebin.com/C9WhCRC5
UpdateAvailableViewModel.cs: https://pastebin.com/p2mT7zt2
I spent a vast majority of yesterday trying to avoid asking for assistance with these problems and tried fixing them on my own. I get these errors in my Error List in visual studio. When I try running my program, it launches, but it's just a black screen and I'm not sure how to fix these problem. Thanks
112 Replies
If it launches, there are probably ghost errors. It happens sometimes because XAML has its own tooling that's separate from C#'s. You can double check by checking the Output tab in VS to see if the build really failed. If it was successful, just ignore the errors. You need to restart VS to get rid of them, usually.
Not sure about the black screen issue. It's hard to debug multiple file systems without knowing exactly which view is black. Easier if it were on GitHub so somebody could clone + run locally.
It is on GitHub. https://github.com/mekasu0124/Diary
GitHub
GitHub - mekasu0124/Diary: A general use diary with the option to s...
A general use diary with the option to store your data locally or in online storage - mekasu0124/Diary
You baked in way too many bugs within testing. I really have no idea how you got this far.
1. You used
async
in a constructor which silently fails. Do not do this. Instead:
And call your async method from code-behind:
2. You have no ViewLocator, so your Views won't be found from your ViewModels anyways. You can either add the ViewLocator or do this in App.axaml:
At this point, I'm getting exceptions because I don't have the necessary files, so I can't diagnose any further.
This observable merging seems like a bad idea, but I don't use RxUI:
Your csproj also has this which prevents nesting of MainWindowView
in the Solution Explorer:
Oh wow. So i just got a lot of it backwards and didn’t even realize it. Aside from the view locator, I’ve been doing everything else the same across multiple projects. Hm. Ok. I’ll have to do some rewriting when I get home from work. Another question for you. I’m wanting to build my apps for offline use as well. Like a hybrid type thing. I want to create a function or a class (whichever is better) that I can call from app.axaml.cs. It basically check if the user is connected to internet. If so, it’ll use an online dabatase. Otherwise, it’ll use SQLite with a local database instead and then when the user connects to internet again in the future, it’ll push all their locally saved progress to the online database
There's no way to reliably check internet connection without making a request. You could create an endpoint to ping for a fast response on startup, otherwise you need to fallback when the connection times out (manually adding this to the task).
Alternatively, you could work the other way around: host locally by default and sync to the online API periodically. You won't need intensive fallback handling to offline mode on every request this way.
If you're using a REST client like https://github.com/reactiveui/refit, it will let you configure a timeout in one spot for all requests.
Great advice. Ty. I’m using a FastAPI for this project if that helps
With FastAPI don’t I have to use something called UUID
Oh, Python stuff. No idea if it has a client generator. Otherwise, you need to create the client with types and endpoints yourself on the C# side so you can actually communicate with the API. Refit helps with that if you need to build it yourself.
This is how I use the FastAPI on my websites. I’m assuming it would be similar? Probably not. I’ll have to look up how to use FastAPI with a C# Avalonia desktop app
That looks poorly maintainable. Having a function that mixes API access, serialization, data transforms, and defining the storage schema which apparently just is supposed to leak to the caller?
.NET is strongly typed, so you create Models to store the data. Either classes or records, but records are easier to define. The property names in the Model match the JSON schema, so System.Text.Json will let you map it in a single call. Data transforms are less straightforward.
Which part? The Python or the JavaScript?
"Yes"
Right. I’ll be using a json file for the config file. It’ll have a setup Boolean, and it’ll hold the users settings that they adjust through the settings menu
Obvious bias because I'm used to writing in C#. :catlul:
So the Java script is the React API. That’s how it’s used and that’s how everyone who’s helped me with my code used it too. I don’t know enough about JS to do anything more than put stuff on the screen. As far as the Python goes, all that function is doing is reading in the information from the json file. It’s going to create a new Project model and then put them all in a list and return it back to the Java script code
The JS side is certainly the worse of the two.
True lol but I always use json files that are locally hosted to store the setup Boolean and other items needed from the user that don’t need to go anywhere past local host
It’s ReactJS. lol to my knowledge, and I could always be wrong, they do it like that in the docs too
I know. The examples (and JS as a whole) will just DIY the schema definition in code (functions) instead of creating concrete type definitions.
Understandable. The only thing I hate about C# that I love about Python is the type definitions. If I have x = 9, it should be smart enough to know that’s an integer lol but that’s just my opinion
var x = 9;
good enough
And you keep strong typing, don't need type hints, etc.Idk I just don’t feel “natural” using var lmao
I always use an explicit type for numerics, but that's possibly from long-ingrained habits.
everyone has their own way of doing things, and that's what makes us unique 😄
Classes and structs? Almost never outside of needing to define something and initialize later.
ok. just got to my computer. going back up and starting re-writes
that's what I like about Python, although different, to me they're the same
corrected*
C# version's members aren't accessible anywhere.
Is the better way to define classes that are data-only (no behavior).
1. You used async
in your constructor which silently fails. Do not do this, instead:
<code>
Right. It silently fails because I did not await the call. I didn't await the call because I didn't want to make the constructor async, however, I will give your method a try.
2. You have no ViewLocator, so your Views won't be found from your ViewModels anyways. You can either add the ViewLocator or do this in App.axaml: <code>My GradeBook application doesn't have a ViewLocator file either, and it runs perfectly fine. https://github.com/mekasu0124/GradeBook
This observable merging seems like a bad idea, but I don't use RxUI: <code> Your csproj also has this which prevents nesting of MainWindowView in the solution explorer: <code>I'll look into this, but it helps me to keep the MainWindowView in the View folder and same for MainWindowViewModel too.
Alternatively, you could work the other way around: host locally by default and sync to the online API periodically. You won't need intensive fallback handling to offline mode on every request this way. If you're using a REST client like <link>, it will let you configure a timeout in one spot for all requestsI'm interested in learning more about this and possibly seeing some code examples too please?
2. I don't see any way that project could work to resolve views. There don't seem to be any
DataTemplate
s nor is there a ViewLocator.
I can't really give Refit examples. I've tried it once on an API that I had a serious blocker on, so I ended up not being able to use said API. It was much nicer than using HttpClient
or RestSharp
though.ok I'll look up a tutorial for that
There are some basic docs and plenty of examples if you GitHub search for relevant methods / classes like
RestService.For
.
(The blocker was related to OAuth and requiring actual written permissions for a manually created account, so nothing limited by Refit itself. The API had changed since I last tried)both projects have a ViewModelBase.cs file in the VIewModels folder, but they don't have a ViewLocator file and I went to restore some repo's from old projects to look at them, but GitHub cleaned out the deleted list so that's a bust. I'm just going to create a new blank project, and see if it comes with one
yea see it doesn't come with anymore since they changed how the project is created. Used too, you would select one of the options for an Avalonia project (desktop, web, mobile) in the menu when creating the project, but they changed it and I guess it doesn't come with it anymore
I've been seeing the
.Desktop
project created lately across other people. Which project template is that, specifically?the only one that avalonia has available to my knowledge and at the end I select compiled bindings and that's the setup process now since I last updated VS and this changed happened along with it so I'm assuming its set to the latest version of avalonia 🤷
Oh, template studio. I don't use wizards.
I use the MVVM app template on the bottom...the structure is different.
Also can optionally include the ViewLocator.
Install with instructions from https://github.com/AvaloniaUI/avalonia-dotnet-templates
GitHub
GitHub - AvaloniaUI/avalonia-dotnet-templates: Avalonia Templates f...
Avalonia Templates for
dotnet new
. Contribute to AvaloniaUI/avalonia-dotnet-templates development by creating an account on GitHub.thta's not even an option for me. I'm going to have to fix that because I very much dislike this
.Desktop
thing and having to fix my play button to target that instead of the project I'm working in. Compiling down to an exe from the .Desktop etcHaving a
.Desktop
project is a bit more future-proof if you create new targets later.understandable, but I build my mobile apps in ReactNativeJS. I build my websites in ReactJS and if it's a desktop app that I'm just going to use by myself on my own computer, I build it in Python using PyQT.
I have a single UI project (domain, services, etc in separate projects) which is going to take a fair amount of work to retarget if I add WASM or specific publishing options for Mac/Linux.
the only reason I even learned C# and how to use Visual Studio was because it's easier to package down into a
.exe
than it is in Python which I still can't figure outBy a fair amount, I probably mean like 2-3 hours at most. :udidit:
yea I don't necessarily built applications for any specific os. I haven't even released a project yet that I've built haha. But when I build my desktop projects, I would probably use the publish wizard in Visual Studio and compile the project down into an executable for all 3 os's
ohhhh it's because I had just bought this computer maybe 3 weeks ago, and that was the one thing I forgot to do
you said that you don't use ReactiveUI or RxUI (unsure if those are the same) so if that's the case, then do you use CommunityToolkit instead?
Yes, I use Mvvm Toolkit and bring in reactivity via System.Reactive / ReactiveProperty / DynamicData if needed.
I'm curious because I don't exactly like ReactiveUI because of all the boiler-plate code. I would rather use CommunityToolkit but I don't know how to convert my MWVM to use CTk instead of RxUI
You can use Mvvm Toolkit and ReactiveUI side-by-side until you phase out ReactiveUI.
If you're migrating instead of starting a new project, start by changing
ViewModelBase
to derive from ObservableObject
.
Then change the various ReactiveUI properties to be:
And change the containing class to be a partial class
.I am actually re-writing the Diary application. I just created a new project with CommunityToolkit. I would rather phase out of something at one time instead of as I go. I'll get too confused and try to do the boiler plate code lol
yea the [ObservableProperty] and partial class part I know about. I tried to learn CTk once before
Then work on changing ReactiveCommands to:
And bind your commands like:
Command="{Binding DoTheThingCommand}"
right. [ObservableProperty], [RelayCommand], Commmand=... those I know. My issue is like ok. My MainWindowViewModel for the Diary project I'm re-writing. CTk doesn't use Observable.Merge() so I know that In the ViewModel's for each window needs to be relay commands, but how would I return needed information from that relay command back to the main window view model so that it can be passed to the next screen that needs it?
Messenger is typically what I use.
You can check out https://github.com/stevemonaco/AvaloniaNavigationDemo
You can still use observables with Mvvm Toolkit, but you need to bring it in separately as I mentioned earlier.
I find Messenger to be 100x more readable for navigation scenarios though.
ok. I'm looking at the link now
this is a bit of a bit to chew for me. I'll see what I can do on my own and when I get snagged, I'll be back
this is where I'm at on the re-write of MainWindowViewModel and using RxUI, I would start implementing Observable.Merge()'s so instead I would do what? I would reactive commands within each window respectively?
Create navigation messages, register the messages, etc. https://github.com/stevemonaco/AvaloniaNavigationDemo/blob/master/AvaloniaNavigationDemo/ViewModels/MainWindowViewModel.cs
GitHub
AvaloniaNavigationDemo/AvaloniaNavigationDemo/ViewModels/MainWindow...
Contribute to stevemonaco/AvaloniaNavigationDemo development by creating an account on GitHub.
Your other VMs are triggering the navigation events AFAIK, so they have the navigation commands (which send the messages).
even with following that method, won't I have to still have some type of filter so that the program knows what window to show based off what button is clicked and where?
Depends on how complex the navigation is. Usually not. You can create a load of message types or condense them into one that you "filter" over. There's really only two components:
1. Swapping the
ActiveContent
's ViewModel based on the message: https://github.com/stevemonaco/AvaloniaNavigationDemo/blob/master/AvaloniaNavigationDemo/ViewModels/MainWindowViewModel.cs
2. Changing the Window
dimensions / characteristics when said ActiveContent
changes: https://github.com/stevemonaco/AvaloniaNavigationDemo/blob/master/AvaloniaNavigationDemo/Views/MainWindow.axaml.cs#L251. Swapping the ActiveContent
's ViewModel based on the message: <llink>
Instead of that, just as a split second thought. I could be wrong. idk. but um. couldn't I just make a relay command that when activated, it calls the MainWindowViewModel.Content variable and changes it to the vm that's needed for that button click? Like
2.Can't I just set the Width and Height in the axaml of the page itself and that work fine?
1. Yes, but the entire point of messaging is that you can send the message from anywhere. You can't do
MainWindowViewModel.Content = TheThing;
from anywhere. You need the right instance of MainWindowViewModel
in the exact spot you're using it. Wiring all of this is tricky, even with an IoC container doing the heavy lifting because you can somewhat easily run into circular dependencies.
2. Sure. But in this case, the login "window" wants a much smaller, fixed appearance than the app itself. This is, of course, optional.I'll fix the window sizes while I'm doing the re-write. Ok so them if I'm doing messaging, then I would need to register every window with it's own unique message which seems to always be a record. ok I'll give it a shot and send you a message when I get it done to see what you think
record
simply because very easy to define. They don't need any logic either. And yes, you can register each major navigation step. There are some patterns, like Master-Detail, which more-or-less happen automatically with binding, so you don't need messages there.
Sometimes it's convenient to send out a message that the active item has changed for disconnected components to listen to. For menus or status bars that need to update their information.I'm going to be building a Menu Bar component to use inside of the MainWindowViewModel because It's not going to change per screen, and it's always going to be visible
It may be awkward getting information into it. Especially if your hierarchy is like:
Getting data from Editor to MenuBar will be difficult. In some cases, you can use DI and inject MenuBar into Editor. Some cases, messaging is better. Some cases, you write another VM that contains shared data and inject into both to bind to.
In my
app.axaml.cs
file I have 5 variables that need to be passed to the MainWindowViewModel so that the rest of the application has access to it when it's needed. I decided to create them here as it's easier to create once and re-use 100 times than it is to create 100 times. It's also easier on debugging for me. So using the Messenger.Register<>();
how do I pass the 5 variables to MainWindowViewModel?
would you happen to have an example of this?You should register
Database
, GithubService
, and Helpers
with the DI services. Then add those 3 to MainWindowViewModel
ctor parameters. Resolve the version
and user
within it from the Helpers
instance passed in. You shouldn't mix-and-match when you're doing DI with more primitive parameter types like string
or int
that will be ambiguous.
Which case?you completely lost me on this. I do apologize. I know that DI means Dependency Injector, but ok wait. let me see what I can figure out on my own. I'll be back on this
messaging. I think I'm going to go that route for this application.
TBH, I use the third approach with a lot of injection. Messaging isn't an all-or-nothing approach. Just use it where it makes sense. https://github.com/stevemonaco/ImageMagitek/blob/main/TileShop.UI/Features/Shell/MenuViewModel.cs
I used messaging with menus before and I found I needed to register a lot of messages. This was before Mvvm Toolkit and
record
came along, so it's more convenient now.lol tbh, RxUI is a bit easier to understand, but I'm going to give this a try
MainView.axaml
: https://pastebin.com/k5PZhjEr
MainView.axaml.cs
: https://pastebin.com/MBpgCEBM
MainViewModel.cs
: https://pastebin.com/7XRNMiyn
ok so I've copied the code from the navigation example repo literally line for line and in doing so, I'm resulting in 3 errors. and I'm lost on how to solve themTypos:
Binging
i hate spelling >_<
ok so since I'm redoing this, would it be better to check for my
version.txt
and config.json
files in the app.axaml.cs
file or should I move that to the helpers file and then call it in the MainWindowViewModel or MainViewModel?App.axaml.cs is not a great place for error-handling. There are mechanisms you can use, but if you expect to need any error handling, I'd move the call into the VM or View.
I'm not sure what they actually do, but I'd put the processing into a service class.
ok thanks 🙂
With this, do you mean to do like
Sure. Those might not need to be singleton lifetime scoped though. Depends.
ok what would be the better option?
like I wanna understand. This is as far as I've gotten with trying to understand your message there. I do apologize
AddTransient
exists for services, etc that don't need to be singleton.So something like this?
or
.AddTransient<GithubService>()
though you don't have to chain everything together.is it better to chain or worse?
Doesn't really matter.
I tend to separate for readability.
ok so by adding them as transients, does that allow me the ability to access those instances in a ViewModel maybe by passing it through the parameters? Like
No, the service registration in general does that.
Singleton/Transient/Scoped defines which instance you get.
ok so then how do I access it in the view model?
or pass it to the vm
Like how you're doing above.
ok and it just makes the bridge and connects the two together
cool. tyvm
As long as you don't have a circular dependency, sure.
"The two" is a bit misleading.
If you inject ViewModelA registered as transient into ViewModelB and ViewModelC, you've created two separate instances of ViewModelA.
Which is important if you're expecting the same instance to be shared.
oh ok. that makes sense
when the user clicks the Login button, I want it to check if the user's input matches what's saved in the database. If it does, I'll write a Message.Send(), but if it doesn't then I want it to change the visibility status of an error label that'll be on the screen, delay 3 seconds and then reset the screen. I'm having a bit of problem getting that logic
something like this maybe?
It's tricky because there's concurrency enabled. If the user starts typing in another try during the 3s delay, their fields will get reset if they're too slow.
You can try using the command cancellation https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/relaycommand#cancel-commands-for-asynchronous-operations inside of
OnPasswordChanged
and OnUserNameChanged
.
Or you can use [RelayCommand(AllowConcurrentExecutions = false)]
, but the delay will be a bit long. This will disable the button.
I would immediately clear whatever you want to clear instead of messing up the user mid-typing.
eg. Just clearing the password immediately.and I do that by just the simple
Password = "";
right
how about this?That works. You'll need to see if it's the UX you want though. The delay is quite long because it blocks.
ok. I'll check that out when I test, ty
Inside of the returning UserModel, there is UserModel.UserSettings. The two nested models inside of UserSettings are supposed to be information pulled from the styles.json file. I did have that in a helper function but I was wondering if it would be appropriate to do it here instead so that it all gets queried and returned only once
If you aren't intending on having styles.json be hand-edited, I would probably store the JSON in the DB.
I would also use EF Core instead of ADO.NET. Or at least Dapper if you want to write SQL.
ok then I'll just store it all in the database under the user's table or I may create another table for the user's settings
Some DBs have JSON columns. Don't know if SQLite has them as I don't use the feature.
ok np 🙂
whew this is a bunch of stuff to learn lol Like I'm trying not to go back to RxUI lol
Nearly 100% of this stuff you would've needed to do for a RxUI app anyways. Only a small part is Mvvm Toolkit-specific.
I got you. I have another question
Is there a way to possibly get away with doing something like
???
and when I use the connection, I can close it at the end of the function, and when I insert/update/delete I can use someting like a conn.Comit() and then a conn.Close() at the end of my functions
I'm not sure that actually buys you much. But no, the second is not possible.
If you cache conn/cmd in a private field, then you should implement
IDisposable
and take care of them there.
Then the caller is responsible for (using var db = Database.CreateDatabase())
or whatever (which should probably be a static factory method). I find the approach pretty awkward, but I'm more used to working with EF Core.
Outside of EF Core, I'm used to Dapper and something like this: https://github.com/JustAHack/TimCoRetailManager/blob/main/TRMDataManager.Library/Internal/DataAccess/SQLDataAccess.cs
But this is for stored procedures rather than in-code SQL.oh ok. I'll just forget that for now lol
Using raw ADO.NET isn't for convenience. It's what EF Core and Dapper build on top of. You can abstract some of it, but you're bound to make some bad decisions.
right right. so another question then. With my websites that I doodle around with I use a FastAPI for the server-side. Is it possible to use FastAPI with Avalonia? If so, how do I do it? I can't find any tutorials or StackOverflows on google
A web API is a web API.
right, but in the client-side of my application, I use JS.
I create and export an API that knows where to call, and then I import api into the pages that use it and go from there
You use whatever libraries C# / .NET has that can make http requests.
HttpClient
, Refit, or some others.
No, you use axios.well that. my fault. wrong name
HttpClient
and Refit fill the same role with varying levels of (in)convenience.so you said HttpClient. So I would use that like I do in my installer when getting the latest release from a github repo
Sure, but it's significantly less convenient than Refit.
ok I'll look at Refit. Thanks
ok so once more. If I create a new project in my current window
nvm. I know the answer I'm looking for
I created a custom font in my
App.axaml
file. In my view page, I called to that x:Key
however I keep getting the error Could not create glyph Typeface
and I'm trying to follow their example here on using a custome font, but I think I'm doing it wrong. In my solution explorer, I have
https://docs.avaloniaui.net/docs/guides/styles-and-resources/how-to-use-fontsYou need to make sure its build action is an AvaloniaResource. Could try using the
avares:
URI, too.
Besides that, font imports are a bit of a pain. There are a few issues specific to that in the past months, but no time to work on them.ok thank you
ok I appreciate all the help you've given me, but unfortunately this is just a bit too big of a concept for me to chew at this present moment so I'm going to revert back to ReactiveUI. Thank you for the help ❤️