C
C#14mo ago
Mekasu0124

✅ How to display an image avalonia

<Image Source="{Binding ImagePath}" />
<Image Source="{Binding ImagePath}" />
public static string? _imagePath;
public ViewModel()
{
ImagePath = "/Assets/logo.ico";
}
public string? ImagePath
{
get => _imagePath;
set => this.RaiseAndSetIfChanged(ref _imagePath, value);
}
public static string? _imagePath;
public ViewModel()
{
ImagePath = "/Assets/logo.ico";
}
public string? ImagePath
{
get => _imagePath;
set => this.RaiseAndSetIfChanged(ref _imagePath, value);
}
how do I get my image to display? This isn't working
43 Replies
arion
arion14mo ago
The source property expects type IImage You could try the approach they say in the avalonia docs named Binding to Image Files from Various Sources (It's basically setting the IImage to something like a bitmap in the documentation case with
public Bitmap? ImageFromBinding { get; } = ImageHelper.LoadFromResource(new Uri("avares://LoadingImages/Assets/abstract.jpg"));
public Bitmap? ImageFromBinding { get; } = ImageHelper.LoadFromResource(new Uri("avares://LoadingImages/Assets/abstract.jpg"));
Additionally you can try out other types that are also of type IImage like these:
arion
arion14mo ago
Xaml doesn't necessarily confirm to C# standards, providing a path isn't always converted as a string
Mekasu0124
Mekasu0124OP14mo ago
I tried that. I even tried to use their ImageHelper class and it didn't work for me. I wound up trying
<Image Source="/Assets/logo.ico"></Image>
<Image Source="/Assets/logo.ico"></Image>
and that worked beautifully
arion
arion14mo ago
Great! Just note that you can shave off the tail bit of that if not needed like
<Image Source="/Assets/logo.ico"/>
<Image Source="/Assets/logo.ico"/>
Mekasu0124
Mekasu0124OP14mo ago
I tried doing a self-closing tag, and it wouldn't work unfortunately but then again, half of this framework doesn't work for me
arion
arion14mo ago
You still want to use binding for it right?
Mekasu0124
Mekasu0124OP14mo ago
I'm using Visual Studio. When I type in the axaml file, there is no drop down box for code completion and I cannot use the Designer either. idk why it's all broken. I have tried every solution I could find to fix it. I've asked in the Microsoft discord, and here, but got no responses. It's just broken, and I want to stay up to date with the framework. I'm currently using 11.0.2 or whatever it is, and therefore I'm not wanting to back date just to get those features back no. I'm not changing images throughout the process. It's the same image each time so I just typed it straight in
arion
arion14mo ago
Whats the problem with just keeping it like
<Image Source="/Assets/logo.ico"/>
<Image Source="/Assets/logo.ico"/>
compared to making it a binding?
Mekasu0124
Mekasu0124OP14mo ago
I'm not making it a binding? There is no problem? I'm confused on the question There is no problem on having the path in the Image tag like that. That's what I did
arion
arion14mo ago
Oh, so the problem aint that you want it to display as a binding but instead you want to make it display? like its not appearing despite both attempts. Um, lemme get visual studio out since idk how it looks like in visual studio, it may be a resource property issue
arion
arion14mo ago
In Rider its usual that you mark it as an "AvaloniaResource" like in this screenshot
arion
arion14mo ago
Is your icon set to it like this?
Mekasu0124
Mekasu0124OP14mo ago
no the problem was that it wasn't displaying at all, but then I tried this and it worked. the image displays just fine now. The problem I'm on right now is getting a screen to display a style for when an input is wrong, and then getting the screen to refresh after n seconds and put the stylings back to normal
arion
arion14mo ago
You could use classes. You can add or remove classes and on the axaml side change how they look based upon each class Then from the code-behind side, you set the classes and remove them as you wish.
arion
arion14mo ago
Classes is a collection, like a list, so adding something would be
Control x = null!;

x.Classes.Add("WrongInput");
Control x = null!;

x.Classes.Add("WrongInput");
Mekasu0124
Mekasu0124OP14mo ago
View => https://pastebin.com/2mC6kC9X ViewModel => https://pastebin.com/D0bBd00K What I'm trying to accomplish is that in this function
public User ReturnNewUser()
{
if (CurrentUsers.Contains(NewUser))
{
IsValid = false;
return null;
}

User user = new() { Username = NewUser };

Database.InsertNewUsername(user);

return user;
}
public User ReturnNewUser()
{
if (CurrentUsers.Contains(NewUser))
{
IsValid = false;
return null;
}

User user = new() { Username = NewUser };

Database.InsertNewUsername(user);

return user;
}
when it hits the early return because the username they're trying to create already exists, it will show the error styling which is based off the IsValid bool. After 3 seconds, it will reset the screen. I tried doing
// main window view model
public void SelectUser()
{
var vm = new SelectUserViewModel();

Observable.Merge(vm.Login, vm.CreateUser)
.Take(1)
.Subscribe(model =>
{
if (model != null)
{
SelectedUser = model.Username;
// GetGameInformation();
}
else
{
Thread.Sleep(3000);
SelectUser();
}
});

Content = vm;
}
// main window view model
public void SelectUser()
{
var vm = new SelectUserViewModel();

Observable.Merge(vm.Login, vm.CreateUser)
.Take(1)
.Subscribe(model =>
{
if (model != null)
{
SelectedUser = model.Username;
// GetGameInformation();
}
else
{
Thread.Sleep(3000);
SelectUser();
}
});

Content = vm;
}
but that didn't allow the error styling to show and just froze and reset the screen the way it's supposed to work is if I go to create a new username in the text box, and that username already exists in the current users list, then it will change the styling of the text box and swap the button with a label in the view. Once that change happens, I want the program to count down 3 seconds, and then reset the screen. This, I believe, has to be controlled from the main window view model since that's what handles the returned model which is returned from the button click on that view so if I select a username from the combo box, and click login, it will send that username back to main window view model. If I enter a new username that doens't exist in the combo box and click the play game button, then it'll save it to the database, and return that new username back to the main window view model. If I enter in a username in the text box that already exists in the combo box and click the play game button, it'll early escape and send a null model back to the main window view model and if that model is null else { SelectUser(); } then I want the error styling to still show on the screen, the system to sleep for 3 seconds, and then refresh the screen
Mekasu0124
Mekasu0124OP14mo ago
No description
No description
No description
Mekasu0124
Mekasu0124OP14mo ago
as it sits right this second, if I put in my username which already exists. It just simply resets the screen. No error stylings show, the label doesn't show and the button hide. It just resets the screen
arion
arion14mo ago
just froze and reset the screen
Thread.Sleep(3000);
SelectUser();
Thread.Sleep(3000);
SelectUser();
thats exactly what this part is doing. Since its not async code and is executing on the main thread Thread.Sleep freezes your entire application What prevents you from returning a Tuple like
public (bool Success, User NewUser) ReturnNewUser()
public (bool Success, User NewUser) ReturnNewUser()
? Also I can't see any code that actually does styling on the ReturnNewUser method failing by returning an "IsValid = false" object but what you can do is, when that method returns, check the value, add a class to the Control that shows an error state and then maybe after 3 sec remove that, or set the control / window properties directly like:
User x = ReturnNewUser();
if (!x.IsValid)
{
window.MyFancyLabel.IsVisible = true;
window.MyFancyButton.IsVisible = false;
}
User x = ReturnNewUser();
if (!x.IsValid)
{
window.MyFancyLabel.IsVisible = true;
window.MyFancyButton.IsVisible = false;
}
You could also set it as a class or even create a ViewModelBinding for their respective IsVisible states like this
arion
arion14mo ago
Dialogs are also an option
Mekasu0124
Mekasu0124OP14mo ago
just frose and reset the screen Thread.Sleep(3000); Select User(); thats exactly what this part is doing, Since it's not async code and is executing on the main thread Thread.Sleep freezes your entire application
that's what I thought too, but I can't figure out any other way.
What prevents you from returning a Tuple like public (bool Success, User NewUser) ReturnNewUser();?
I didn't know that was an option. I'm still a beginner at most things C# and Avalonia related.
Also I can't see any code that actually does styling on the ReturnNewUser method failing by returning an "IsValid = false" object but what you can od is, when that method returns, check the value, add a class to the Control that shows an error state and then maybe after 3 sec remove that, or set the control / window properties directly like User x = ReturnNewUser(); if (!x.IsValid) { window.MyFancyLabel.IsVisible = true; window.MyFancyButton.IsVisiable = false; }
There are stylings. It's in a separate style file. The styles are done off conditional rendering like this
<Border Grid.Column="1" Classes="SelectUserBorder">
<Grid RowDefinitions="*,*,*">
<Label Classes="SelectUserLabel" Grid.Row="0" Content="Create A New User" />
<TextBox Classes.SelectedUserInput="{Binding IsValid}" Classes.Wrong="{Binding !IsValid}" Grid.Row="1" Text="{Binding NewUser}" />
<Label Classes.Wrong="{Binding !IsValid}" Grid.Row="2" Content="That Username Already Exists!" IsVisible="{Binding !IsValid}"/>
<Button Classes="SelectUserButton" Grid.Row="2" Content="Create User" Command="{Binding SendNewUser}" IsVisible="{Binding IsValid}" />
</Grid>
</Border>
<Border Grid.Column="1" Classes="SelectUserBorder">
<Grid RowDefinitions="*,*,*">
<Label Classes="SelectUserLabel" Grid.Row="0" Content="Create A New User" />
<TextBox Classes.SelectedUserInput="{Binding IsValid}" Classes.Wrong="{Binding !IsValid}" Grid.Row="1" Text="{Binding NewUser}" />
<Label Classes.Wrong="{Binding !IsValid}" Grid.Row="2" Content="That Username Already Exists!" IsVisible="{Binding !IsValid}"/>
<Button Classes="SelectUserButton" Grid.Row="2" Content="Create User" Command="{Binding SendNewUser}" IsVisible="{Binding IsValid}" />
</Grid>
</Border>
Which is based off the IsValid boolean within the ViewModels code.
You could also set it as a class or even create a ViewModelBinding for their respective IsVIsible states like this <screenshot> Dialogs are also an option
I don't know anything about dialogs, tbh. I want the main window view model to control the stylings being applied through the IsValid bool like I have it setup, but if that's not efficient, then I'll re-write it to whatever is most efficient and the best practice. I just don't know what that is. I'm still learning the best methods of doing things with this framework
arion
arion14mo ago
ah gotcha, i see, um for the "async code" part. You could change your subscribe method to dispatch an async event to the UI after 3sec 1sec i show dispatcher code
Mekasu0124
Mekasu0124OP14mo ago
if I do this, then the stylings get applied. I just don't know the best way to have the program sleep and then reset the screen
No description
arion
arion14mo ago
Observable.Merge(vm.Login, vm.CreateUser)
.Take(1)
.Subscribe(model =>
{
if (model != null)
{
SelectedUser = model.Username;
// GetGameInformation();
}
else
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(3));
SelectedUser();
});
}
});
Observable.Merge(vm.Login, vm.CreateUser)
.Take(1)
.Subscribe(model =>
{
if (model != null)
{
SelectedUser = model.Username;
// GetGameInformation();
}
else
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(3));
SelectedUser();
});
}
});
Mekasu0124
Mekasu0124OP14mo ago
so I would set the IsValid to false before the dispatcher, right?
arion
arion14mo ago
Yes The dispatcher just makes sure your application doesnt freeze when doing async operations just please dont use any Thread.Sleeps in UI code
Mekasu0124
Mekasu0124OP14mo ago
I do my best not to. Most times they're just placeholders until I can find a better way to do what I'm wanting to do. Like in this instance for example and that you for showing me the dispatcher. That works amazingly. Thank you!
arion
arion14mo ago
viennaCool also for synchronous code you can do
Dispatcher.UIThread.Post(() =>
{

});
Dispatcher.UIThread.Post(() =>
{

});
for if you're on another thread and want to send something to the main thread.
Mekasu0124
Mekasu0124OP14mo ago
oh ok. cool. tyvm
NumberRange = new()
{
"Select One", "1", "2", "3",
"4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14",
"15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25" };
NumberRange = new()
{
"Select One", "1", "2", "3",
"4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14",
"15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25" };
what's a more efficient way to create a string list of numbers 1 through 25 inclusive with having "Select One" at index 0 than this?
MODiX
MODiX14mo ago
arion
REPL Result: Success
var numbers = Enumerable.Range(1, 25);
var NumbersRange = new List<string> { "Select One" };
NumbersRange.AddRange(numbers.Select(x => x.ToString()));

NumbersRange
var numbers = Enumerable.Range(1, 25);
var NumbersRange = new List<string> { "Select One" };
NumbersRange.AddRange(numbers.Select(x => x.ToString()));

NumbersRange
Result: List<string>
[
"Select One",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25"
]
[
"Select One",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25"
]
Compile: 618.281ms | Execution: 69.272ms | React with ❌ to remove this embed.
arion
arion14mo ago
like that? You could even do
MODiX
MODiX14mo ago
arion
REPL Result: Success
var NumbersRange = new List<string> { "Select One" };
NumbersRange.AddRange(Enumerable.Range(1, 25).Select(x => x.ToString()));

NumbersRange
var NumbersRange = new List<string> { "Select One" };
NumbersRange.AddRange(Enumerable.Range(1, 25).Select(x => x.ToString()));

NumbersRange
Result: List<string>
[
"Select One",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25"
]
[
"Select One",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25"
]
Compile: 638.474ms | Execution: 71.405ms | React with ❌ to remove this embed.
Mekasu0124
Mekasu0124OP14mo ago
very much appreciated 🙂
arion
arion14mo ago
npnp nod
Mekasu0124
Mekasu0124OP14mo ago
lets say I have a list of text
string completedText;

List<string> text = new()
{
"hello",
"world",
"example
};
string completedText;

List<string> text = new()
{
"hello",
"world",
"example
};
instead of creating a for-loop to bring all of that text together
foreach (string line in text)
{
completedText += line + " ";
}
foreach (string line in text)
{
completedText += line + " ";
}
how would I apply that enumerable thing you did with the numbers above to bring the list together instead? I know I can do
string completedText = """
The fancy
formatting of a string
like this
""";
string completedText = """
The fancy
formatting of a string
like this
""";
but I don't like how that presents in a textblock would I use string.Join(" ", text);?
arion
arion14mo ago
I don't exactly know what you want. Do you want something like this? seems Modix cant do newlines properly with raw literals, um i'll just post raw
var completedText = """
The fancy
formatting of a string
like this
""";

text = completedText.Split("\r\n")
var completedText = """
The fancy
formatting of a string
like this
""";

text = completedText.Split("\r\n")
Splitting by \r\n is a windows thing called CRLF
arion
arion14mo ago
There are 3 options, windows is CRLF, basically, splitting by \n is for linux, \r\n is for windows (in this context)
MODiX
MODiX14mo ago
arion
REPL Result: Success
var completedText = """
The fancy
formatting of a string
like this
""";

completedText.Split("\n")
var completedText = """
The fancy
formatting of a string
like this
""";

completedText.Split("\n")
Result: string[]
[
"The fancy",
"formatting of a string",
"like this"
]
[
"The fancy",
"formatting of a string",
"like this"
]
Compile: 515.625ms | Execution: 33.204ms | React with ❌ to remove this embed.
arion
arion14mo ago
So in your case, just add change the
completedText.Split("\n")
completedText.Split("\n")
from the modix repl to
completedText.Split("\r\n")
completedText.Split("\r\n")
Mekasu0124
Mekasu0124OP14mo ago
ok thank you ❤️
Want results from more Discord servers?
Add your server