Binding null, but is working

Eduardo Gomez 3,651 Reputation points
2025-05-09T23:45:59.3366667+00:00

In have my viewModel

using System.Collections.ObjectModel;

namespace FireChat.ViewModels;

public partial class AppShellViewModel : BaseViewModel {

    readonly FirebaseAuthClient _authClient;
    readonly WeakReferenceMessenger _messenger;
    readonly IMediaPicker _mediaPicker;

    [ObservableProperty]
    LocalUser localUser = new();

    [ObservableProperty]
    string? _selectedItem;

    public ObservableCollection<string>? OptionsColletion { get; set; }

    public AppShellViewModel(FirebaseAuthClient authClient, WeakReferenceMessenger messenger, IMediaPicker mediaPicker) {

        _authClient = authClient;

        if(_authClient.User != null) {
            localUser.Username = _authClient.User.Info.DisplayName;
            localUser.Email = _authClient.User.Info.Email;
        }

        _messenger = messenger;
        _mediaPicker = mediaPicker;

        OptionsColletion = GetOptions();
    }

    [RelayCommand]
    async Task SignOut() {

        _authClient.SignOut();

        await Shell.Current.GoToAsync("..");
    }

    [RelayCommand]
    void OpenProfile() {

        _messenger.Send("OpenProfile");

    }

    [RelayCommand]
    void SavePopUpContent() {

        _messenger.Send("SavePopUpContent");
    }

    [RelayCommand]
    void SelectedOption() {

        Action action = SelectedItem switch {
            "Take picture" => async () => await TakePicture(),
            "Remove picture" => RemovePicture,
            "Change picture" => async () => await ChangePicture(),
            _ => () => throw new InvalidOperationException("Invalid selection.")
        };

        // Execute the selected action
        action();

    }

    private async Task ChangePicture() {

        if(LocalUser.ImagePath != null) {

            var NewImagePath = await _mediaPicker.PickPhotoAsync(new MediaPickerOptions() {
                Title = "Select a new profile picture"
            });

            if(NewImagePath != null) {
                LocalUser.ImagePath = NewImagePath.FullPath;

            }

        }
    }

    private void RemovePicture() {

        LocalUser.ImagePath = string.Empty;
    }

    private async Task TakePicture() {

        if(_mediaPicker.IsCaptureSupported) {

            var photo = await _mediaPicker.CapturePhotoAsync();

            if(photo != null) {

                string newFileName = $"{LocalUser.Username}-{DateTime.Today.ToString("yyyy-MM-dd")}.jpg";
                string localFilePath = Path.Combine(FileSystem.AppDataDirectory, newFileName);

                using Stream sourceStream = await photo.OpenReadAsync();
                using FileStream localFileStream = File.OpenWrite(localFilePath);

                await sourceStream.CopyToAsync(localFileStream);

                Debug.WriteLine($"Image saved to: {localFilePath}");

                LocalUser.ImagePath = new Uri(localFilePath).AbsoluteUri;

            }
        }
        else {
            Debug.WriteLine("Camera not supported");
        }
    }

    public ObservableCollection<string> GetOptions() {

        OptionsColletion = ["Take picture", "Remove picture", "Change picture"];

        return OptionsColletion;
    }

}

and my view

<Shell
    x:Class="FireChat.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:controls="clr-namespace:FireChat.Controls"
    xmlns:icons="clr-namespace:FireChat.Icons"
    xmlns:model="clr-namespace:FireChat.Model"
    xmlns:sfPopup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:views="clr-namespace:FireChat.Views"
    xmlns:vm="clr-namespace:FireChat.ViewModels"
    x:Name="AppShellFireChatPage"
    x:DataType="vm:AppShellViewModel"
    FlyoutBehavior="{OnIdiom Desktop=Locked,
                             Phone=Disabled}"
    Shell.FlyoutWidth="60">

    <ShellContent
        ContentTemplate="{DataTemplate views:LoginPage}"
        FlyoutItemIsVisible="False"
        Route="LoginPage"
        Shell.FlyoutBehavior="Disabled" />

    <ShellContent
        ContentTemplate="{DataTemplate views:ChatPage}"
        Route="ChatPage">
        <ShellContent.Icon>
            <FontImageSource
                FontFamily="MaterialSymbol"
                Glyph="{Static icons:MateriallFontGlyphs.Chat}"
                Color="White" />
        </ShellContent.Icon>
    </ShellContent>

    <Shell.FlyoutFooter>
        <Grid
            Padding="10"
            BackgroundColor="Transparent"
            HeightRequest="48">
            <Image x:Name="UserProfileImage">
                <Image.Source>
                    <FontImageSource
                        FontFamily="MaterialSymbol"
                        Glyph="{Static icons:MateriallFontGlyphs.Account_circle}"
                        Color="White" />
                </Image.Source>
                <Image.GestureRecognizers>
                    <TapGestureRecognizer
                        x:DataType="vm:AppShellViewModel"
                        Command="{Binding OpenProfileCommand}" />
                </Image.GestureRecognizers>
            </Image>

            <sfPopup:SfPopup
                x:Name="AvatarPopUp"
                AbsoluteX="-20"
                AbsoluteY="-20"
                AutoSizeMode="Height"
                RelativePosition="AlignTop"
                ShowFooter="False"
                ShowHeader="False"
                ShowOverlayAlways="False"
                WidthRequest="150">

                <sfPopup:SfPopup.PopupStyle>
                    <sfPopup:PopupStyle
                        CornerRadius="8"
                        PopupBackground="{AppThemeBinding Dark={DynamicResource PrimaryDarkText},
                                                          Light={DynamicResource White}}" />
                </sfPopup:SfPopup.PopupStyle>

                <sfPopup:SfPopup.ContentTemplate>
                    <DataTemplate>
                        <Border StrokeThickness="2">
                            <CollectionView
                                x:Name="OptionCollectionView"
                                Margin="10"
                                ItemsSource="{Binding OptionsColletion}"
                                SelectedItem="{Binding SelectedItem}"
                                SelectionChangedCommand="{Binding SelectedOptionCommand}"
                                SelectionMode="Single" />
                            <Border.StrokeShape>
                                <RoundRectangle CornerRadius="8" />
                            </Border.StrokeShape>
                        </Border>
                    </DataTemplate>
                </sfPopup:SfPopup.ContentTemplate>
            </sfPopup:SfPopup>


            <sfPopup:SfPopup
                x:Name="UserProfilePopup"
                AbsoluteX="-30"
                AbsoluteY="30"
                AcceptCommand="{Binding SavePopUpContentCommand}"
                HeaderHeight="90"
                HeightRequest="400"
                RelativePosition="AlignTopRight"
                RelativeView="{x:Reference UserProfileImage}"
                ShowFooter="True"
                ShowHeader="True"
                ShowOverlayAlways="False"
                WidthRequest="400">

                <sfPopup:SfPopup.HeaderTemplate>
                    <DataTemplate x:DataType="model:LocalUser">
                        <toolkit:AvatarView
                            Margin="20,10,0,0"
                            BorderColor="{AppThemeBinding Dark={DynamicResource White},
                                                          Light={DynamicResource PrimaryDarkText}}"
                            BorderWidth="1"
                            CornerRadius="80"
                            FontFamily="MaterialSymbol"
                            FontSize="20"
                            HeightRequest="80"
                            HorizontalOptions="Start"
                            ImageSource="{Binding ImagePath}"
                            Text="{Static icons:MateriallFontGlyphs.Add_a_photo}"
                            TextColor="{AppThemeBinding Dark={DynamicResource White},
                                                        Light={DynamicResource PrimaryDarkText}}"
                            WidthRequest="80">
                            <toolkit:AvatarView.GestureRecognizers>
                                <PointerGestureRecognizer
                                    x:Name="AvatarImage"
                                    PointerEntered="AvatarImage_PointerEntered"
                                    PointerExited="AvatarImage_PointerExited" />
                                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
                            </toolkit:AvatarView.GestureRecognizers>
                        </toolkit:AvatarView>
                    </DataTemplate>
                </sfPopup:SfPopup.HeaderTemplate>
                <sfPopup:SfPopup.PopupStyle>
                    <sfPopup:PopupStyle
                        CornerRadius="0"
                        PopupBackground="{AppThemeBinding Dark={DynamicResource PrimaryDarkText},
                                                          Light={DynamicResource White}}" />
                </sfPopup:SfPopup.PopupStyle>
                <sfPopup:SfPopup.ContentTemplate>
                    <DataTemplate>
                        <Grid
                            Padding="20"
                            HorizontalOptions="Center"
                            RowDefinitions="80,80"
                            RowSpacing="5"
                            VerticalOptions="Center">
                            
                            <controls:MaterialEntry
                                Hint="Username"
                                HintColor="{AppThemeBinding Dark={DynamicResource White},
                                                            Light={DynamicResource Black}}"
                                HorizontalOptions="Start"
                                ShowIcon="False"
                                Text="{Binding LocalUser.Username}"
                                TextColor="{AppThemeBinding Dark={DynamicResource White},
                                                            Light={DynamicResource Black}}" />
                            <controls:MaterialEntry
                                Grid.Row="1"
                                Hint="Status"
                                HintColor="{AppThemeBinding Dark={DynamicResource White},
                                                            Light={DynamicResource Black}}"
                                HorizontalOptions="Start"
                                ShowIcon="False"
                                Text="{Binding LocalUser.StatusMessage}"
                                TextColor="{AppThemeBinding Dark={DynamicResource White},
                                                            Light={DynamicResource Black}}" />
                        </Grid>
                    </DataTemplate>
                </sfPopup:SfPopup.ContentTemplate>
                <sfPopup:SfPopup.FooterTemplate>
                    <DataTemplate>
                        <Grid>
                            <Button
                                Margin="20"
                                BackgroundColor="{AppThemeBinding Dark={DynamicResource Gray900},
                                                                  Light={DynamicResource White}}"
                                HorizontalOptions="End"
                                Text="Save"
                                TextColor="{AppThemeBinding Dark={DynamicResource White},
                                                            Light={DynamicResource PrimaryDarkText}}"
                                VerticalOptions="Center"
                                WidthRequest="200">
                                <Button.Behaviors>
                                    <toolkit:TouchBehavior HoveredBackgroundColor="{AppThemeBinding Dark={DynamicResource FireOrange}, Light={DynamicResource White}}" />
                                </Button.Behaviors>
                            </Button>
                        </Grid>
                    </DataTemplate>
                </sfPopup:SfPopup.FooterTemplate>
            </sfPopup:SfPopup>
        </Grid>
    </Shell.FlyoutFooter> </Shell>  


I am focusing on widows first

So, this is only accessible on a desktop.

 

This works as follows: You click on the avatar icon (This is where the error comes), and I display a collection of options

The strange part is, that this is working fine, but I want to get rid of the error

 
this is the "error"

`Severity	Code	Count	Data Context	Binding Path	Target	Target Type	Description	File	Line	Project
Error	Binding	1	null				Mismatch between the specified x:DataType (FireChat.Model.LocalUser) and the current binding context (FireChat.ViewModels.AppShellViewModel).	


But I can click on the Avatar View So I don’t understand

 Untitled video - Made with Clipchamp (1)

for reference, this is my class

    [FirestoreData]
    public partial class LocalUser : ObservableObject {

        private string _id;
        private string _username;
        private string _email;
        private string _password;
        private string _confirmPassword;
        private string _imagePath;
        private string _statusMessage = "Hey there! I'm using FireChat!";
        private bool _onlineStatus = true;

        [FirestoreProperty]
        public string Id {
            get => _id;
            set {
                _id = value;
                OnPropertyChanged(nameof(Id));
            }
        }

        [FirestoreProperty]
        public string Username {
            get => _username;
            set {
                _username = value;
                OnPropertyChanged(nameof(Username));
            }
        }

        [FirestoreProperty]
        public string Email {
            get => _email;
            set {
                _email = value;
                OnPropertyChanged(nameof(Email));
            }
        }

        [FirestoreProperty]
        public string Password {
            get => _password;
            set {
                _password = value;
                OnPropertyChanged(nameof(Password));
            }
        }

        [FirestoreProperty]
        public string ConfirmPassword {
            get => _confirmPassword;
            set {
                _confirmPassword = value;
                OnPropertyChanged(nameof(ConfirmPassword));
            }
        }

        [FirestoreProperty]
        public string ImagePath {
            get => _imagePath;
            set {
                _imagePath = value;
                OnPropertyChanged(nameof(ImagePath));
            }
        }

        [FirestoreProperty]
        public string StatusMessage {
            get => _statusMessage;
            set {
                _statusMessage = value;
                OnPropertyChanged(nameof(StatusMessage));
            }
        }

        [FirestoreProperty]
        public bool OnlineStatus {
            get => _onlineStatus;
            set {
                _onlineStatus = value;
                OnPropertyChanged(nameof(OnlineStatus));
            }
        }
    }
}

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
4,104 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.