【问题标题】:Xamarin forms PropertyChanged object is nullXamarin 表单 PropertyChanged 对象为空
【发布时间】:2021-06-08 18:20:11
【问题描述】:

因此,我查看了 StackOverflow 中已经发布的许多答案,但似乎找不到适用的答案。

首先,让我解释一下我的 Xamarin Forms 应用程序。我有传统的解决方案结构(带有 Andoid 和 iOS 应用程序项目的 .Net Standard 2.0 类库)。我正在开发的应用程序是一组应用程序的一部分,该应用程序通过附加的 .Net 2.0 标准类库共享大量代码(页眉、页脚、错误处理等)。在这个类中,我有一个用于异常处理的视图模型以及一个标准的标题内容视图,用于套件中的所有应用程序。

在标题中,我在标题区域显示一个错误图标,当异常处理器添加异常时,用户可以单击该图标以报告错误等。我将错误图标的图像控件的 IsVisible 属性绑定到异常处理视图模型中的属性。每次显示我的页面(所有页面都使用共享标题)时,都会调用视图模型中属性的 get 绑定到的 IsVisible 属性。所以看起来绑定配置正确。

问题是,当我通过异常处理视图模型添加错误,然后尝试通知 UI 绑定属性已更改时,PropertyChange 事件对象 - 定义如下:

public event PropertyChangedEventHandler PropertyChanged;

始终为空。因此,永远不会调用绑定属性的“获取”,并且我的 UI 也不会更新。我希望这很简单,但我无法弄清楚。

请注意!!套件中的不同解决方案(仅使用 UWP 应用程序存根)使用完全相同的内容视图和代码,完全按预期工作。换句话说,当异常处理器添加错误时,将询问绑定属性并按预期显示错误图标。

下面是我的代码。任何帮助将不胜感激。

应用程序内容视图的 XAML 代码

<?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>

应用程序内容视图的 C# 代码

  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);
                }
            }
        }
    }

异常处理程序视图模型的 C# 代码

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));
        }
    }
}

这是我的共享代码项目中将异常处理视图模型实例化为静态对象的帮助程序类的代码

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);
            }
        }
    }

}

我知道这很多,但如果能提供任何帮助,我将不胜感激。

更新!!! ARG - 你知道在你发布问题后你认为你想通了。我相信我实际上得到了我的异常处理程序类的两个不同实例,一个来自 Xamarin forms .net 类库,一个来自我的共享代码。我正在从我的 xamarin forms .net 类库中删除视图模型,看看这是否能解决问题,我会更新。

【问题讨论】:

    标签: xamarin.forms mvvm viewmodel inotifypropertychanged propertychanged


    【解决方案1】:

    所以 - 就我而言,发生的事情是我有一个在我的 Xamarin Forms 项目中定义的视图模型的实例和在我的共享代码中定义的对象的静态版本。我忘记从 Xamarin Forms 应用程序中删除视图模型的实例,因此该项目中引用视图模型的所有内容都在访问与我的共享代码类中的所有代码不同的实例。一旦我在我的 Xamarin Forms 应用程序中删除了该实例,并将所有内容都指向我单独的共享代码项目中的静态实例,一切正常。也许这会对其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-01-01
      • 2017-07-10
      • 2011-04-05
      • 1970-01-01
      • 2018-11-19
      • 2014-06-15
      • 2021-10-04
      • 2018-11-15
      相关资源
      最近更新 更多