J'ai donc parcouru de nombreuses réponses déjà publiées dans StackOverflow et je n'arrive pas à en trouver une qui s'applique.

Tout d'abord, laissez-moi vous expliquer mon application Xamarin Forms. J'ai la structure de solution traditionnelle (bibliothèque de classes .Net Standard 2.0 avec les projets d'application Andoid et iOS). L'application sur laquelle je travaille fait partie d'une suite d'applications qui partagent une grande quantité de code (en-tête, pied de page, gestion des erreurs, etc.) via une bibliothèque de classes standard .Net 2.0 supplémentaire. Dans cette classe, j'ai un modèle de vue pour la gestion des exceptions ainsi qu'une vue de contenu d'en-tête standard utilisée dans toutes les applications faisant partie de la suite.

Dans l'en-tête, je montre une icône d'erreur dans la zone d'en-tête sur laquelle l'utilisateur peut cliquer pour signaler les erreurs, etc. lorsque le processeur d'exception ajoute une exception. Je lie la propriété IsVisible du contrôle d'image pour l'icône d'erreur à une propriété dans le viewmodel de gestion des exceptions. Chaque fois que ma page s'affiche (toutes les pages utilisent l'en-tête partagé), le get pour la propriété dans le modèle de vue à laquelle la propriété IsVisible est liée est appelé. Il semblerait donc que la liaison soit correctement configurée.

Le problème est que lorsque j'ajoute une erreur via mon modèle de vue de gestion des exceptions, puis que j'essaie d'informer l'interface utilisateur que la propriété liée a changé, l'objet d'événement PropertyChange - défini comme suit :

public event PropertyChangedEventHandler PropertyChanged;

Est toujours nul. Ainsi, le 'get' de la propriété liée n'est jamais appelé et mon interface utilisateur n'est pas mise à jour. J'espère que c'est quelque chose de simple mais je n'ai pas réussi à le comprendre.

VEUILLEZ NOTER !! Une solution différente dans la suite (avec le talon d'application UWP uniquement) qui utilise exactement les mêmes vues de contenu et le même code, fonctionne exactement comme prévu. En d'autres termes, lorsque le processeur d'exception ajoute une erreur, la propriété liée est interrogée et l'icône d'erreur s'affiche comme prévu.

Ci-dessous mon code. Toute assistance sera grandement appréciée.

CODE XAML POUR L'AFFICHAGE DU CONTENU APPHEADER

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sfGrad ="clr-namespace:Syncfusion.XForms.Graphics;assembly=Syncfusion.Core.XForms"
             BackgroundColor="#4D648D"
             x:Class="FCISharedAll.AppHeader">
    <ContentView.Content>
        <StackLayout x:Name="slMaster" HorizontalOptions="Fill" VerticalOptions="Start" Orientation="Vertical" Margin="0,0,0,-6" 
                     Spacing="0">
            <Grid x:Name="grdGradient" HorizontalOptions="Fill" VerticalOptions="Start" HeightRequest="110" MinimumHeightRequest="110">
                <sfGrad:SfGradientView>
                    <sfGrad:SfGradientView.BackgroundBrush>
                        <sfGrad:SfLinearGradientBrush StartPoint="0.5, 0" EndPoint="0.5, 1">
                            <sfGrad:SfLinearGradientBrush.GradientStops>
                                <sfGrad:SfGradientStop Color="#4D648D" Offset="0.0" />
                                <sfGrad:SfGradientStop Color="#283655" Offset="0.5" />
                                <sfGrad:SfGradientStop Color="#4D648D" Offset="1.0" />
                            </sfGrad:SfLinearGradientBrush.GradientStops>
                        </sfGrad:SfLinearGradientBrush>
                    </sfGrad:SfGradientView.BackgroundBrush>
                </sfGrad:SfGradientView>
                <Grid x:Name="grdHeader" HorizontalOptions="Fill" VerticalOptions="Start">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Image x:Name="imgHeader" Source="fciapp.png" HeightRequest="110" MinimumHeightRequest="110" HorizontalOptions="Fill"
                           VerticalOptions="Center"  Aspect="AspectFit" Grid.Column="0" />
                    <Image x:Name="imgError" Source="error.png" HorizontalOptions="End" VerticalOptions="Center" Margin="8,8,8,8"
                       IsVisible="{Binding ShowErrorIcon}" Grid.Column="0">
                        <Image.GestureRecognizers>
                            <TapGestureRecognizer Tapped="imgError_Tapped" />
                        </Image.GestureRecognizers>
                    </Image>
                </Grid>
            </Grid>
        </StackLayout>
    </ContentView.Content>
</ContentView>

CODE C# POUR L'AFFICHAGE DU CONTENU APPHEADER

  using Rg.Plugins.Popup.Services;
    using System;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    namespace FCISharedAll
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class AppHeader : ContentView
        {
    
            public AppHeader()
            {
                InitializeComponent();
                NavigationPage.SetHasNavigationBar(this, false);
                imgError.BindingContext = FCISharedAllHelperClass.gvm_GlobalExceptionClass;
            }
    
            private async void imgError_Tapped(object sender, EventArgs e)
            {
                try
                {
                    await PopupNavigation.Instance.PushAsync(new FCISharedAll.ExceptionDisplay(FCISharedAllHelperClass.gvm_GlobalExceptionClass));
                }
                catch (Exception ex)
                {
                    SharedErrorHandler.ProcessException(ex);
                }
            }
        }
    }

CODE C# POUR LE VIEWMODEL DU GESTIONNAIRE D'EXCEPTION

namespace FCISharedAll
{
    public class CompleteException
    {
        public DateTime Error_DateTime { get; set; }
        public Exception Error { get; set; }
    }

    public class ExceptionProcessor : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private List<CompleteException> iobj_ApplicationExceptions { get; set; }

        public ExceptionProcessor()
        {
            try
            {
                if (iobj_ApplicationExceptions == null)
                {
                    iobj_ApplicationExceptions = new List<CompleteException>();
                }
            }
            catch (Exception ex)
            {
                iobj_ApplicationExceptions.Add(new CompleteException() { Error_DateTime = DateTime.Now, Error = ex });
            }
        }

        public bool ShowErrorIcon
        {
            get
            {
                return (iobj_ApplicationExceptions == null || iobj_ApplicationExceptions.Count > 0);
            }
        }
        public void AddExceptionToList(Exception pobj_Exception)
        {
            try
            {
                iobj_ApplicationExceptions.Add(new CompleteException() { Error_DateTime = DateTime.Now, Error = pobj_Exception });
                //NotifyPropertyChanged(ge_PreferenceKey.ShowErrorIcon.ToString());
                NotifyPropertyChanged("ShowErrorIcon");
            }
            catch (Exception ex)
            {
                iobj_ApplicationExceptions.Add(new CompleteException() { Error_DateTime = DateTime.Now, Error = ex });
            }
        }

        public int ErrorCount
        {
            get
            {
                int li_ReturnValue = 0;
                if (iobj_ApplicationExceptions != null)
                {
                    li_ReturnValue = iobj_ApplicationExceptions.Count;
                }
                return li_ReturnValue;
            }
        }

        public void RemoveProcessedExceptions(int pi_NumberOfExceptionsToInclude)
        {
            int li_ErrorsToProcess = 0;
            try
            {
                li_ErrorsToProcess = (pi_NumberOfExceptionsToInclude <= iobj_ApplicationExceptions.Count ? pi_NumberOfExceptionsToInclude : iobj_ApplicationExceptions.Count);

                for (int li_IX = 0; li_IX <= li_ErrorsToProcess - 1; li_IX++)
                {
                    iobj_ApplicationExceptions.RemoveAt(0);
                }

                
                NotifyPropertyChanged(ge_PreferenceKey.ErrorCount.ToString());
                NotifyPropertyChanged(ge_PreferenceKey.ShowErrorIcon.ToString());
            }
            catch (Exception ex)
            {
                iobj_ApplicationExceptions.Add(new CompleteException() { Error_DateTime = DateTime.Now, Error = ex });
            }
        }

        public string PrepareErrorText(int pi_NumberOfExceptionsToInclude = 5)
        {
            string ls_EmailText = "";
            int li_ErrorsToProcess = 0;

            try
            {
                li_ErrorsToProcess = (pi_NumberOfExceptionsToInclude <= iobj_ApplicationExceptions.Count ? pi_NumberOfExceptionsToInclude : iobj_ApplicationExceptions.Count);

                for (int li_IX = 0; li_IX <= li_ErrorsToProcess - 1; li_IX++)
                {
                    ls_EmailText += FormatException(iobj_ApplicationExceptions[li_IX]) + System.Environment.NewLine;
                }

            }
            catch (Exception ex)
            {
                iobj_ApplicationExceptions.Add(new CompleteException() { Error_DateTime = DateTime.Now, Error = ex });
            }

            return ls_EmailText;
        }

        private string FormatException(CompleteException pobj_CompleteException)
        {
            string ls_ReturnText = "";
            ls_ReturnText = "Date: " + pobj_CompleteException.Error_DateTime + System.Environment.NewLine +
                "Message: " + (pobj_CompleteException.Error.Message == null ? "" : pobj_CompleteException.Error.Message + System.Environment.NewLine) +
                "Source: " + (pobj_CompleteException.Error.Source == null ? "" : pobj_CompleteException.Error.Source + System.Environment.NewLine) +
                "Stack Trace: " + (pobj_CompleteException.Error.StackTrace == null ? "" : pobj_CompleteException.Error.StackTrace + System.Environment.NewLine);

            if (pobj_CompleteException.Error.InnerException != null)
            {
                ls_ReturnText += "Inner Exception Message: " + (pobj_CompleteException.Error.InnerException.Message == null ? "" : pobj_CompleteException.Error.InnerException.Message + System.Environment.NewLine) +
                    "Inner Exception Source: " + (pobj_CompleteException.Error.InnerException.Source == null ? "" : pobj_CompleteException.Error.InnerException.Source + System.Environment.NewLine) +
                    "Inner Exception Stack Trace: " + (pobj_CompleteException.Error.InnerException.StackTrace == null ? "" : pobj_CompleteException.Error.InnerException.StackTrace);
            }

            if (ls_ReturnText.LastIndexOf(System.Environment.NewLine) > ls_ReturnText.Length - 5)
            {
                //Remove the last line linefeed
                ls_ReturnText = ls_ReturnText.Substring(0, ls_ReturnText.LastIndexOf(System.Environment.NewLine));
            }

            return ls_ReturnText;
        }

        /// <summary>
        /// Manual Notification to subscribers that a property has changed. 
        /// </summary>
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Voici le code de la classe d'assistance dans mon projet de code partagé qui instancie le modèle de vue Exception Processing en tant qu'objet statique

using FCISharedAll.FCICommObjects;
using System;

namespace FCISharedAll
{
    public static class FCISharedAllHelperClass
    {
        public static ExceptionProcessor gvm_GlobalExceptionClass = new ExceptionProcessor();
        public static ThemeConfig gobj_ThemeConfig { get; set; }

        public static bool IsCheckInPage { get; set; } = false;

        //internal
        private static KioskInfo iobj_KioskInfo = null;
        public static KioskInfo HostKioskInfo
        {
            get
            {
                if (iobj_KioskInfo == null)
                {
                    iobj_KioskInfo = new KioskInfo();
                }
                return iobj_KioskInfo;
            }
            set
            {
                iobj_KioskInfo = value;
            }

        }

        public static void ConfigureTheme(bool pb_UseKioskTheme)
        {
            try
            {
                gobj_ThemeConfig = new ThemeConfig(pb_UseKioskTheme);
            }
            catch (Exception ex)
            {
                SharedErrorHandler.ProcessException(ex);
            }
        }
    }

}

Je sais que cela beaucoup à parcourir, mais j'apprécierais toute aide qui peut être fournie.

METTRE À JOUR!!! ARG - vous savez après avoir posté la question que vous pensez avoir compris. Je crois que j'obtenais en fait deux instances différentes de ma classe de gestionnaire d'exceptions, une de la bibliothèque de classes Xamarin Forms .net et une dans mon code partagé. Je supprime le modèle de vue de ma bibliothèque de classes .net de formulaires xamarin pour voir si cela résout le problème et je mettrai à jour.

0
George M Ceaser Jr 10 mars 2021 à 21:46

1 réponse

Meilleure réponse

SO - dans mon cas, ce qui s'est passé, c'est que j'avais une instance du modèle de vue défini dans mon projet Xamarin Forms et une version statique de l'objet défini dans mon code partagé. J'ai oublié de supprimer l'instance du viewmodel de l'application Xamarin Forms et donc tout dans ce projet référençant le viewmodel accédait à une instance différente de tout le code de ma classe de code partagé. Une fois que j'ai supprimé l'instance dans mon application Xamarin Forms et que j'ai tout pointé vers l'instance statique dans mon projet de code partagé séparé, tout a bien fonctionné. Peut-être que cela aidera quelqu'un d'autre.

0
George M Ceaser Jr 10 mars 2021 à 19:15