바인딩이있는 사용자 정의보기를 사용할 때 "지정된 캐스트가 유효하지 않습니다"라는 메시지가 표시되지만 수동으로 설정 한 경우에는 표시되지 않는 이유는 무엇입니까?

Aug 17 2020

BindableProperty로 ObservableCollection을 사용하여 사용자 지정보기를 작성 중입니다 (내 목표는 해당 내용,이 경우 색상 목록에 따라보기의 형식을 업데이트하는 것이 었습니다). 사용자 정의보기에서 속성이 제대로 설정되었다고 생각합니다. C #에서 바인딩 가능 속성을 설정하면 작동합니다. XAML 내에서 {Binding varname}을 사용하려고하면 "Specified Cast is not Valid"오류가 발생합니다. 내 문제가 어디에 있는지 알아 내려고 노력하고 있습니다.

아래 public MainPage ()에서 속성을 수동으로 설정 한 주석 처리 된 줄을 볼 수 있습니다. 이 주석을 제거하고 MainPage.xaml에서 "Color = {Binding Test}"를 가져 오면 모든 것이 작동합니다. 이대로 실행하면 예외가 발생합니다.

내 모든 코드는 다음과 같습니다.

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public ObservableCollection<Color> Test { get; set; }
    public MainPage()
    {
        Test = new ObservableCollection<Color>();

        Test.Add(Color.Blue);
        Test.Add(Color.Green);
        Test.Add(Color.Red);
        Test.Add(Color.Purple);
        
        this.BindingContext = this;
        InitializeComponent();

        //myView.Colors = Test;
    }

    

    private void OnClicked(object sender, EventArgs e)
    {
        myView.Colors.Add(Color.Yellow);
    }
}

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:ColorBoxes"
         x:Class="ColorBoxes.MainPage">

    <StackLayout HorizontalOptions="CenterAndExpand">
        <local:ColorBoxView  x:Name="myView" Colors="{Binding Test}" WidthRequest="400" HeightRequest="600"/>
        <Button Text="Add Color" Clicked="OnClicked"/>
    </StackLayout>

</ContentPage>

ColorBoxView.xaml.cs

public partial class ColorBoxView : ContentView
{
    public ColorBoxView()
    {
       InitializeComponent();
       
    }
    
    public static BindableProperty ColorList = BindableProperty.Create(
        propertyName: "Colors",
        returnType: typeof(ObservableCollection<Color>),
        declaringType: typeof(ColorBoxView),
        defaultValue: new ObservableCollection<Color>(),
        defaultBindingMode: BindingMode.OneWay,
        propertyChanged: HandleColorListPropertyChanged
    );

    public ObservableCollection<Color> Colors
    {
        get { return (ObservableCollection<Color>) base.GetValue(ColorList); }
        set
        {
            if (value != this.Colors)
            {
                base.SetValue(ColorList, value);
                Colors.CollectionChanged += Items_CollectionChanged;
            }
        }
    }
   
    
    void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        buildView(Colors);
    }

    private void buildView(ObservableCollection<Color> newColors)
    {
        /* This code is never reached */
    }
    private static void HandleColorListPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ObservableCollection<Color> newColors = (ObservableCollection<Color>) newValue;
        ColorBoxView thisView = (ColorBoxView) bindable;

        thisView.buildView(newColors);
        
    }

ColorBoxView.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"
         x:Class="ColorBoxes.ColorBoxView" >

    <Grid  x:Name="BoxGrid"  HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" 
           RowSpacing="0" ColumnSpacing="0" Padding="0">
    </Grid>

</ContentView>

스택 추적 :

System.InvalidCastException: Specified cast is not valid. 
   at ColorBoxes.MainPage.InitializeComponent () [0x00023] in /Users/docmani/RiderProjects/ColorBoxes/ColorBoxes/ColorBoxes/obj/Debug/netstandard2.0/MainPage.xaml.g.cs:26
   at ColorBoxes.MainPage..ctor () [0x00060] in /Users/docmani/RiderProjects/ColorBoxes/ColorBoxes/ColorBoxes/MainPage.xaml.cs:25
   at ColorBoxes.App..ctor () [0x0000f] in /Users/docmani/RiderProjects/ColorBoxes/ColorBoxes/ColorBoxes/App.xaml.cs:15
   at ColorBoxes.iOS.AppDelegate.FinishedLaunching (UIKit.UIApplication app, Foundation.NSDictionary options) [0x00007] in /Users/docmani/RiderProjects/ColorBoxes/ColorBoxes/ColorBoxes.iOS/AppDelegate.cs:25
   at at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
   at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIKit/UIApplication.cs:86
   at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIKit/UIApplication.cs:65
   at ColorBoxes.iOS.Application.Main (System.String[] args) [0x00001] in /Users/docmani/RiderProjects/ColorBoxes/ColorBoxes/ColorBoxes.iOS/Main.cs:16

추가 정보-오랫동안 NuGet에서 Xamarin.Forms를 업그레이드하려고했습니다. 이제 바인딩으로 컴파일하지도 않습니다. 그것은 나에게 준다 :

 MainPage.xaml(9, 46): [XFC0009] No property, BindableProperty, or event found for "Colors", or mismatching type between value and property.

그러나 다시 말하지만 C #에서 수동으로 값을 설정해도 여전히 작동합니다. 내 XAML에서 분명히 뭔가가 누락되었지만 그것이 무엇인지 모르겠습니다.

답변

LeonLu-MSFT Aug 17 2020 at 10:16

BindableProperty다음과 같이 변경 한 다음 ColorListPropertyxaml에서 테스트 할 수 있습니다 .

public partial class ColorBoxView : ContentView
    {
        public ColorBoxView ()
        {
            InitializeComponent ();
        }
 
        public static readonly BindableProperty ColorListProperty = BindableProperty.Create(
            nameof(ColorList), 
            typeof(ObservableCollection<object>), 
            typeof(ColorBoxView), 
            new ObservableCollection<object>(), 
            BindingMode.OneWay, 
            propertyChanged: ContractListPropertyChangedDelegate);
        public ObservableCollection<object> ColorList
        {
            get =>
            (ObservableCollection<object>)GetValue(ColorListProperty);
            set => SetValue(ColorListProperty, value);
        }
        private static void ContractListPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue)
        {
            // throw new NotImplementedException();
         //   ColorBoxView colorBoxView= bindable as ColorBoxView;


        }
 <local:ColorBoxView  x:Name="myView" ColorList="{Binding Test}"  WidthRequest="400" HeightRequest="600"/>

당신이 원하는 경우 CollectionChanged실행되는 이벤트 버튼을 클릭하면, 당신은 추가 할 수 있습니다 ColorList.CollectionChanged += ColorList_CollectionChanged에서 ColorBoxView의 생성자입니다.

public ColorBoxView ()
        {
            InitializeComponent ();
            ColorList.CollectionChanged += ColorList_CollectionChanged;

        }

        private void ColorList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           // throw new NotImplementedException();
        }

귀하의 set새 설정할 때 방법은 실행됩니다 ObservableCollection그냥 존재에 항목을 추가하는 경우 ObservableCollection, 사용 CollectionChangedColorBoxView어쩌면 더 나은.

BTGraham Aug 17 2020 at 20:33

그래서 많은 검색 후에 BindingProperty의 유형이 'IEnumerable'로 설정된 몇 가지 예를 발견했습니다. 내 코드를 다시 실행 한 후 작동하는 다음과 같은 결과를 얻었습니다.

public partial class ColorBoxView : ContentView
{
    public ColorBoxView()
    {
       InitializeComponent();
    }
    
    public static readonly BindableProperty ColorsProperty =
        BindableProperty.Create (nameof (Colors), typeof (IEnumerable), typeof (ColorBoxView), null,
            BindingMode.Default, null, HandleColorListPropertyChanged);

    public IEnumerable Colors
    {
        get { return (IEnumerable) GetValue (ColorsProperty); }
        set
        {
            SetValue (ColorsProperty, value);
            var oc = (ObservableCollection<Color>) (this.Colors);
            oc.CollectionChanged += Items_CollectionChanged;
        }
    }

    private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        buildView( (ObservableCollection<Color>)Colors);
    }

    private void buildView(ObservableCollection<Color> newColors)
    {
        /* Update code */
    }

    private static void HandleColorListPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ObservableCollection<Color> newColors = (ObservableCollection<Color>) newValue;
        ColorBoxView thisView = (ColorBoxView) bindable;

        thisView.Colors = newColors;
        thisView.buildView(newColors);

    }

}

이것이 작동하는 공식적인 이유를 알고 싶습니다. 의견을 부탁드립니다.