【发布时间】:2020-10-20 22:24:07
【问题描述】:
我有一个适用于 Android 和 UWP 的 Xamarin 项目。这个问题似乎只发生在 UWP 上。
在我的 Xamarin 项目中,我有 ContentPage 与绑定为上下文的视图模型。在这个 ViewModel 中有一个 ObservableCollection 和另一种视图模型。当我创建这个底层 ViewModel 的新实例并添加到我的 ObservableCollection 时,有时ContentPage 会按预期工作,在我的 ListView 中显示一个项目。但有时会添加一个空元素,将鼠标悬停在列表上时可以看到。发生这种情况时,我会在“输出”选项卡中收到一堆警告。
我的DownloadsPage:
<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"
xmlns:local="clr-namespace:Downloader.Converters"
mc:Ignorable="d"
x:Class="Downloader.Views.DownloadsPage">
<ContentPage.Resources>
<ResourceDictionary>
<local:DownloadStatusToColorConverter x:Key="downloadStatusToColor" />
</ResourceDictionary>
</ContentPage.Resources>
<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
<ListView x:Name="DownloadsListView" SelectionMode="None" ItemsSource="{Binding Downloads}" RowHeight="70">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10" BackgroundColor="{Binding DownloadStatus, Converter={StaticResource downloadStatusToColor}}">
<Label Text="{Binding Name}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Grid Grid.Row="0" Grid.Column="0" Padding="10,0,10,0">
<ProgressBar BackgroundColor="Transparent" Progress="{Binding PercentDownloaded}" HorizontalOptions="FillAndExpand" HeightRequest="20">
</ProgressBar>
<Label Text="{Binding PercentString}" HorizontalTextAlignment="Center"></Label>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</RefreshView>
</ContentPage>
DownloadsViewModel 在代码隐藏中设置为上下文,如下所示:
public partial class DownloadsPage : ContentPage
{
private readonly DownloadsViewModel _viewModel;
public DownloadsPage()
{
InitializeComponent();
BindingContext = _viewModel = new DownloadsViewModel();
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Device.BeginInvokeOnMainThread(() => _viewModel.RefreshDownloads());
return true;
});
}
}
绑定DownloadsViewModel:
public class DownloadsViewModel : BaseViewModel
{
public ObservableCollection<DownloadViewModel> Downloads { get; set; } = new ObservableCollection<DownloadViewModel>();
public Command LoadItemsCommand { get; set; }
public DownloadsViewModel()
{
Title = "Downloads";
LoadItemsCommand = new Command(() => {
IsBusy = true;
Downloads.Clear();
RefreshDownloads();
IsBusy = false;
});
}
public void RefreshDownloads()
{
foreach (var download in DownloadManager.GetDownloads())
{
var existingDownload = Downloads.FirstOrDefault(d => d.Id == download.Id);
if (existingDownload != null)
{
existingDownload.UpdateValues(download);
}
else
{
Downloads.Add(new DownloadViewModel(download));
}
}
}
}
ObservableCollection 包含 DownloadViewModel,看起来像这样:
public class DownloadViewModel : BaseViewModel
{
private IDownload _download;
public DownloadViewModel(IDownload download)
{
UpdateValues(download);
}
private string _id;
public string Id
{
get { return _id; }
set { SetProperty(ref _id, value); }
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private DownloadStatus _status;
public DownloadStatus DownloadStatus
{
get { return _status; }
set { SetProperty(ref _status, value); }
}
public double PercentDownloaded
{
get
{
return _download.DownloadedBytes == -1
? 0f
: (double)_download.DownloadedBytes / _download.TotalBytes;
}
}
public string PercentString { get => $"{(int)(PercentDownloaded * 100)} %"; }
public void UpdateValues(IDownload download)
{
_download = download;
Id = _download.Id;
Name = _download.Name;
DownloadStatus = _download.Status;
}
}
我有时会遇到导致 ListView 中的项目为空的错误:
Binding: 'DownloadStatus' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.StackLayout.BackgroundColor'
Binding: 'Name' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.Label.Text'
Binding: 'PercentDownloaded' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.ProgressBar.Progress'
Binding: 'PercentString' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.Label.Text'
在调试时,我已确认该项目已按预期添加到我的 ObservableCollection 中。
为什么有时它会在 DownloadsViewModel 而不是 DownloadViewModel 上查找 DownloadStatus、Name、PercentDownloaded 和 PercentString?
【问题讨论】:
-
你能分享一下你是如何设置页面
BindingContext的吗? -
@NicoZhu-MSFT - 我编辑包括如何将 DownloadsViewModel 设置为绑定上下文。
-
你的代码看起来是正确的,我们无法用上面的方法重现这个问题,你能不能用 onedrive 或 github 为我们分享一个代码示例?
-
@NicoZhu-MSFT 好的,我已经创建了一个清理项目,我可以在其中始终如一地重现它,但它现在似乎永远无法工作。我想在它工作之前是我在启动时加载已经创建的下载。当我在运行时创建下载时它不起作用。您可以在此处访问该项目:github.com/OrderlyFashion/Downloader
-
我已经下班了,明天可以检查一下吗?
标签: c# xamarin mvvm data-binding uwp