如何调试 Xamarin Picker 中的绑定问题

How to debug binding problems in Xamarin Picker

我想在我的 Xamarin 表单中添加一个选择器,它显示模板名称列表,并允许用户选择一个。

表格如下:

<?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:DefectReport"
             x:Class="DefectReport.VehiclePage">
    <ContentPage.Content>
        <ScrollView>
            <StackLayout>
                <Label x:Name="Message" TextColor="Red" />
                <Label Text="Registration Number" />
                <Entry Text="{Binding Vehicle.RegistrationNumber}" />
                <Label Text="Description" />
                <Entry Text="{Binding Vehicle.Description}" />
                <Entry Text="Vehicle Type" />
                <Picker ItemsSource="{Binding Templates, PresentationTraceSources.TraceLevel=High}" ItemDisplayBinding="{Binding TemplateName}" SelectedItem="{Binding SelectedTemplate}"/>
                <Button Text="Save" Clicked="SaveButton_Clicked" />
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>
</ContentPage>

下面是代码:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class VehiclePage : ContentPage {
    Vehicle Vehicle { get; set; }
    ObservableCollection<Template> Templates { get; set; }
    Template SelectedTemplate { get; set; }

    public VehiclePage(Vehicle vehicle, List<Template> templates) {
        Vehicle = vehicle ?? new Vehicle();
        Templates = new ObservableCollection<Template>(templates);
        SelectedTemplate = templates.FirstOrDefault(t => t.ServerRecordId == Vehicle.TemplateId) ?? templates.FirstOrDefault();
        BindingContext = this;
        InitializeComponent();
    }

    private async void SaveButton_Clicked(object sender, EventArgs e) {

    }
}

模板和载具类:

public class Template {
    [PrimaryKey]
    [AutoIncrement]
    public int DeviceRecordId { get; set; }
    [Indexed]
    public int idTemplate { get; set; }
    public string TemplateName { get; set; }
    public string TemplateData { get; set; }
    [Ignore]
    public int ServerRecordId {
        get {
            return idTemplate;
        }
        set {
            idTemplate = value;
        }
    }
}

public class Vehicle {
    [PrimaryKey]
    [AutoIncrement]
    public int DeviceRecordId { get; set; }
    [Indexed]
    public int idVehicle { get; set; }
    [Indexed]
    public string RegistrationNumber { get; set; }
    public string Description { get; set; }
    public int TemplateId { get; set; }
    [Ignore]
    public ServerRecordId {
        get {
            return idVehicle;
        }
        set {
            idVehicle = value;
        }
    }
}

当我显示表单时,提供了 1 个模板的列表,但下拉列表中没有模板。

此外,当我在表格中输入数据时,在SaveButton_Clicked方法中,Vehicle.RegistrationNumber和Vehicle.Description没有填写,即使我输入了一些数据。

我看不出如何调试它 - 一切都被隐藏起来了!

一些不能解决的建议:

  1. 当您使用 "Bindings" 时,您应该使用 ObservableCollection 而不是 List
  2. 您的属性应实现 INotifyPropertyChanged
  3. 你应该使用get和set

    车辆车辆{get;set;}

    列表模板{get;set;}

根据亚历山德罗·卡利亚罗的回答,添加:

我为数据创建了一个单独的 class - 使用 this 因为 BindingContext 出于某种原因不起作用。我制作了 class 工具 INotifyPropertyChanged.

我将列表更改为 ObservableCollection

我把所有的数据都变成了属性,带有通知,因此:

    public class VehicleInfo : Model {
        private Vehicle selectedVehicle;

        public Vehicle SelectedVehicle {
            get { return selectedVehicle; }
            set {
                if (selectedVehicle != value) {
                    selectedVehicle = value;
                    OnPropertyChanged("SelectedVehicle");
                }
            }
        }

        private ObservableCollection<Vehicle> vehicles;

        public ObservableCollection<Vehicle> Vehicles {
            get { return vehicles; }
            set {
                if (vehicles != value) {
                    vehicles = value;
                    OnPropertyChanged("Vehicles");
                }
            }
        }


        private Template selectedTemplate;

        public Template SelectedTemplate {
            get { return selectedTemplate; }
            set {
                if (selectedTemplate != value) {
                    selectedTemplate = value;
                    OnPropertyChanged("SelectedTemplate");
                }
            }
        }

    }

模型是一个简单的 class,实现了 INotifyPropertyChanged:

public class Model : System.ComponentModel.INotifyPropertyChanged {
    public void OnPropertyChanged(string name) {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

为了省去所有繁琐的打字,我在Visual Studio2017中添加了一段代码来做属性:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>propn</Title>
            <Shortcut>propn</Shortcut>
            <Description>Code snippet for property and backing field with notification</Description>
            <Author>Nikki Locke</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>The variable backing this property</ToolTip>
                    <Default>myVar</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp"><![CDATA[private $type$ $field$;

    public $type$ $property$
    {
        get { return $field$;}
        set {
            if($field$ != value) {
                $field$ = value;
                OnPropertyChanged("$property$");
            }
        }
    }
    $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>