【问题标题】:Understanding of data binding in Xamarin forms了解 Xamarin 表单中的数据绑定
【发布时间】:2020-08-27 19:15:53
【问题描述】:

我对 Xamarin 绑定的工作方式感到困惑。

单向

表示绑定应该只传播来自源的更改 (通常是视图模型)到目标(BindableObject)。这是 大多数 BindableProperty 值的默认模式。

所以默认情况下,如果在视图模型中设置了值,它将反映在 xaml 页面中。

但在 Xamarin 默认模板中,下面是插入新项目的代码。页面没有在标记中设置任何双向绑定模式。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="Christianity.Mobile.Views.NewItemPage"
             Title="New Item">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Cancel" Clicked="Cancel_Clicked" />
        <ToolbarItem Text="Save" Clicked="Save_Clicked" />
    </ContentPage.ToolbarItems>

    <ContentPage.Content>
        <StackLayout Spacing="20" Padding="15">
            <Label Text="Text" FontSize="Medium" />
            <Entry Text="{Binding Item.Text}" d:Text="Item name" FontSize="Small" />
            <Label Text="Description" FontSize="Medium" />
            <Editor Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small" Margin="0" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

在这里我可以看到在创建新页面时会填充项目的默认值,并且在保存项目时可以使用已编辑的名称和描述。

我的问题 - 默认情况下是否实现了两种方式绑定而没有设置任何绑定模式?

public partial class NewItemPage : ContentPage
{
    public Item Item { get; set; }
    public NewItemPage()
    {
        InitializeComponent();
        Item = new Item
        {
            Text = "Item name",
            Description = "This is an item description."
        };
        BindingContext = this;
    }
    async void Save_Clicked(object sender, EventArgs e)
    {
        MessagingCenter.Send(this, "AddItem", Item);
        await Navigation.PopModalAsync();
    }
    async void Cancel_Clicked(object sender, EventArgs e)
    {
        await Navigation.PopModalAsync();
    }
}

更新 这是我异步加载数据的代码

<?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:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="Christianity.Mobile.Views.ItemDetailPage"
             Title="{Binding Title}">

    <StackLayout Spacing="20" Padding="15">
        <Label Text="Text:" FontSize="Medium" />
        <Label Text="{Binding Item.Title}" d:Text="Item title" FontSize="Small"/>
        <Label Text="Description:" FontSize="Medium" />
        <Label Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small"/>
    </StackLayout>
</ContentPage>
public class ItemDetailViewModel : BaseViewModel
{
    public ItemListItemDTO SelectedItem { get; set; }

    public ItemDTO Item { get; set; }
    public ICommand LoadItemCommand;

    public ItemDetailViewModel(IPageService pageService, ItemListItemDTO selectedItem)
    {
        SelectedItem = selectedItem;

        LoadItemCommand = new Command(async () => await LoadItem());

    }

    public async Task LoadItem()
    {
        IsBusy = true;

        try
        {
            // Both are not working
            Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
            //await Device.InvokeOnMainThreadAsync(async () =>
            //{
            //    Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
            //});
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        finally
        {
            IsBusy = false;
        }
    }
}

【问题讨论】:

  • 我认为您需要在 xaml 中添加绑定模式,例如 &lt;Entry Text="{Binding Item.Text, Mode=TwoWay}" d:Text="Item name" FontSize="Small" /&gt;
  • 它在没有设置绑定模式的情况下正常工作,我的问题是没有它它是如何工作的。

标签: xamarin xamarin.forms


【解决方案1】:

根据Xamarin.Forms Binding Mode,您可以看到大多数可绑定属性的默认绑定模式为OneWay,但以下属性的默认绑定模式为TwoWay

  1. DatePicker 的日期属性

  2. Editor、Entry、SearchBar 和 EntryCell 的文本属性

  3. ListView 的 IsRefreshing 属性

  4. MultiPage 的SelectedItem 属性

  5. Picker 的 SelectedIndex 和 SelectedItem 属性

  6. Slider 和 Stepper 的 Value 属性

  7. Switch 的 IsToggled 属性

  8. SwitchCell 的 On 属性

  9. TimePicker 的时间属性

这些特殊属性被定义为 TwoWay 是有充分理由的:

当数据绑定与 Model-View-ViewModel (MVVM) 应用程序架构一起使用时,ViewModel 类是数据绑定源,而由 Slider 等视图组成的 View 是数据绑定目标。 MVVM 绑定与Reverse Binding 示例的相似之处多于之前示例中的绑定。您很可能希望页面上的每个视图都使用 ViewModel 中相应属性的值进行初始化,但视图中的更改也会影响 ViewModel 属性。

默认绑定模式为 TwoWay 的属性是最有可能在 MVVM 场景中使用的属性。

更新:

例如你使用Web Api获取数据,然后加载到ItemDTO Item中,请确认你已经为ItemDTO类实现了INotifyPropertyChanged接口来通知数据发生变化。

public class ItemDTO:ViewModelBase
{
    private string _Text;
    public string Text
    {
        get { return _Text; }
        set
        {
            _Text = value;
            RaisePropertyChanged("Text");
        }
    }

    private string _Description;
    public string Description
    {
        get
        { return _Description; }
        set
        {
            _Description = value;
            RaisePropertyChanged("Description");
        }
    }
}

ViewModelBase 是实现 INotifyPropertyChanged 的类。

public class ViewModelBase : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

【讨论】:

  • 谢谢。我有另一个问题,我正在使用相同的场景通过 OnAppearing 事件从 Web API 检索它来使用 MVVM 绑定项目属性。但是来自 api 的值没有从视图模型绑定到视图。既然是两种方式,绑定不应该填充吗?
  • @Sunny 请先确认您可以从Web Api 获取数据到ViewModel,然后如果您的绑定正确,则可以成功显示数据,与双向模式无关。不知道你的绑定有没有问题,请把你的绑定代码贴在这里。
  • 感谢您回来。我添加了相关代码来异步显示值。我确认已成功从 webapi 检索数据,但 UI 中的标题和描述未更新。
  • @Sunny 根据你的代码,我猜你没有实现 INotifyPropertyChanged 接口来通知数据改变,请看我的更新。
  • 对于只读屏幕是 INotifyPropertyChanged 的​​强制要求。
猜你喜欢
  • 2016-06-26
  • 2018-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 2019-05-24
  • 2018-02-16
  • 2021-04-18
相关资源
最近更新 更多