【问题标题】:Xamarin.Forms binding does not workXamarin.Forms 绑定不起作用
【发布时间】:2017-11-02 00:36:54
【问题描述】:

我尝试使用 XAML 将我的适用于 Windows10 的 UWP C# 应用程序重写为 Xamarin 应用程序。但是绑定(例如在 ListView ItemSource=... 中)对我不起作用,我不知道为什么。

Visual Studio 告诉我,由于未知的数据上下文,无法解析符号记录。

这是我的 XAML (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:XamarinTest;assembly=XamarinTest"
             x:Class="XamarinTest.MainPage">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <ListView x:Name="listView" IsVisible="false" ItemsSource="{Binding Recording}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <StackLayout Orientation="Horizontal">
                                <Image Source="Accept" WidthRequest="40" HeightRequest="40" />
                                <StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand">
                                    <Label Text="TEST" HorizontalOptions="FillAndExpand" />
                                    <Label Text="TEST" />
                                </StackLayout>
                            </StackLayout>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentPage>

这里是 C# (MainPage.xaml.cs):

namespace XamarinTest
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.AllTestViewModel = new RecordingViewModel();
            this.BindingContext = AllTestViewModel;                
        }
        public RecordingViewModel AllTestViewModel { get; set; }
    }
}

最后是 ViewModel (RecordingViewModel.cs):

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using XamarinTest.Model;

namespace XamarinTest.ViewModel
{
    public class RecordingViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<Recording> Recordings { get; } = new TrulyObservableCollection<Recording>();

        public RecordingViewModel()
        {
            Recordings.Add(new RecordingTest2()
            {
                TestName = "Test 1",
                TestNote = "Vytvoreni DB",
                TestTime = new TimeSpan(0, 0, 0)
            });
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
        where T : INotifyPropertyChanged
    {
        public TrulyObservableCollection()
        {
            CollectionChanged += FullObservableCollectionCollectionChanged;
        }

        public TrulyObservableCollection(IEnumerable<T> pItems) : this()
        {
            foreach (var item in pItems)
            {
                this.Add(item);
            }
        }

        private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Object item in e.NewItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                }
            }
            if (e.OldItems != null)
            {
                foreach (Object item in e.OldItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                }
            }
        }

        private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
            OnCollectionChanged(args);
        }
    }
}

一切(模型和视图模型)都在本机 UWP Windows 10 应用程序中运行。 Xamarin 中只有绑定和制作相同的视图是问题。有人可以帮忙绑定吗? 谢谢。

编辑

Recording.cs 在这里:

using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XamarinTest.Model
{
    public abstract class Recording : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string TestName { get; set; }
        private TimeSpan _testTime;
        private string _testNote;
        private string _actualIco = "Play";
        private bool _isActive = false;
        private bool _enabled = true;
        public double IcoOpacity { get; private set; } = 1.0;
        public string ActualIco
        {
            get => _actualIco;
            set
            {
                if (_actualIco == null) _actualIco = "Admin";
                _actualIco = value;
                NotifyPropertyChanged("ActualIco");
            }
        }
        public bool IsActive
        {
            get => _isActive;
            set
            {
                if (_isActive == value) return;
                _isActive = value;
                IcoOpacity = !value ? 1.0 : 0.3;
                NotifyPropertyChanged("IsActive");
                NotifyPropertyChanged("IcoOpacity");
            }
        }
        public bool Enabled
        {
            get => _enabled;
            set
            {
                if (_enabled == value) return;
                _enabled = value;
                NotifyPropertyChanged("Enabled");
            }
        }
        public string TestNote
        {
            get => _testNote;
            set
            {
                if (_testNote == value) return;
                _testNote = value;
                NotifyPropertyChanged("TestNote");
            }
        }
        public TimeSpan TestTime
        {
            get => _testTime;
            set
            {
                if (_testTime == value) return;
                _testTime = value;
                NotifyPropertyChanged("TestTime");
            }
        }

        protected Recording()
        {
            TestName = "Unkonwn";
            TestNote = "";
            _testTime = new TimeSpan(0, 0, 0);
        }

        protected Recording(string testName, string testNote, TimeSpan testTime)
        {
            TestName = testName;
            TestNote = testNote;
            _testTime = testTime;
        }
        public string OneLineSummary => $"{TestName}, finished: "
                                        + TestTime;

        private void NotifyPropertyChanged(string propertyName = "")
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public abstract bool playTest();

    }
}

我尝试在 XAML 中添加 DataContext(原始问题中的 postet),因为这样的智能:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:dvm="clr-namespace:XamarinTest.ViewModel"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
d:DataContext="{system:Type dvm:RecordingViewModel}"

这是网格:

<Label Text="{Binding Recordings[0].TestName}" Grid.Row="0" Grid.Column="2" />

IntelliSence 正常,但应用中不显示文字。

【问题讨论】:

  • XF XAML 使用 BindingContext,而不是 DataContext
  • @Jason 我试过它在public MainPage() evene 中声明 BidingContext 而没有在 XAML 中使用 DataContext,但它也不起作用。
  • 这里有太多的事情需要解读——我建议你把它归结为一个更简单的测试用例——只是一个带有标签和虚拟机的页面——让它工作,并且然后从那里构建。或者查看任何 Xamarin 示例。
  • 没问题。我只能在 MainPage() 中创建字符串 var 并将其设置为 BindingContext 并尝试通过 Binding 将其设置为仅 XAML 中的标签(其余部分已注释),但它仍然无法正常工作。我看到了很多示例,但是当我尝试使用绑定和 XAML 进行某些操作时,它不起作用。

标签: c# xaml xamarin mvvm xamarin.forms


【解决方案1】:

终于成功了!

XAML 应该类似于下面的代码。 重要的是xmls:viewModel="..."&lt;ContentPage.BindingContext&gt;...&lt;/&gt;

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"                                                  
             xmlns:viewModel="clr-namespace:XamarinTest.ViewModel;assembly=XamarinTest"
             x:Class="XamarinTest.MainPage"         
             >
    <ContentPage.BindingContext>
        <viewModel:RecordingViewModel/>
    </ContentPage.BindingContext>
<ListView x:Name="listView" ItemsSource="{Binding Recordings}" Grid.Row="1" Grid.Column="1">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <StackLayout Orientation="Horizontal">
                                <Image Source="Accept" WidthRequest="40" HeightRequest="40" />
                                <StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand">
                                    <Label Text="{Binding TestName}" HorizontalOptions="FillAndExpand" />
                                    <Label Text="{Binding TestNote}" />
                                </StackLayout>
                            </StackLayout>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentPage>

MainPage.xaml.cs 没问题

namespace XamarinTest
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.AllTestViewModel = new RecordingViewModel();
            this.BindingContext = AllTestViewModel;                
        }
        public RecordingViewModel AllTestViewModel { get; set; }
    }
}

【讨论】:

    【解决方案2】:

    查看您的 ViewModel,似乎没有 Recording 成员,但您确实有一个 Recordings 成员。

    编辑

    所以你在后面的代码中添加你的 DataContext 所以忽略 Xaml 部分。

    您的视图 (MainPage.xaml) 有一个 ViewModel(RecordingViewModel.cs)。 ViewModel 有一个名为 Recordings 的成员(Recording 类型的集合)。但在您的 Xaml 中,您尝试绑定到 Recording

    变化:

    &lt;ListView x:Name="listView" IsVisible="false" ItemsSource="{Binding Recording}"&gt;

    到:

    &lt;ListView x:Name="listView" IsVisible="false" ItemsSource="{Binding Recordings}"&gt;

    第二次编辑

    您的示例中唯一的Labels 是 ListView 内部的那个是吗?

    如果是这样,您可以通过以下方式访问 Recordings 子代,例如 TestNote

    【讨论】:

    • 我在问题中添加了 Recording.cs。是的,我认为缺少 DataContext 可能是个问题。你能告诉我我应该怎么写吗?因为我试了很多次都没有用。
    • 哦,是的,你说得对。但这没有帮助。构建和部署成功,但没有显示文本。
    • 我在 XAML 中尝试了 DataContext,但没有帮助,只有 IntelliSence 工作。我编辑了关于它的原始问题。
    • 我创建的这个标签是为了在 ListView 之外进行测试。很抱歉造成混乱。但是,如果我在 ListView 的 Label 中执行此操作,它也不起作用(构建和部署工作,但我只看到空白页面)。
    • 如果你使用静态标签:'' 会显示吗?
    猜你喜欢
    • 2018-12-09
    • 2019-04-29
    • 1970-01-01
    • 2015-11-12
    • 2022-01-14
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    相关资源
    最近更新 更多