【问题标题】:How do I use a Reactive User Control as a template for displaying a list of View Models in a List Box using Avalonia and ReactiveUI?如何使用响应式用户控件作为模板,使用 Avalonia 和 ReactiveUI 在列表框中显示视图模型列表?
【发布时间】:2022-12-22 00:06:55
【问题描述】:

我正在尝试使用 Avalonia 和 ReactiveUI 来显示从本地数据库中提取的图像列表框。我的实现基于 ReactiveUI 在其文档中的示例:here。我通过为主页创建一个视图和视图模型来实现它,其中包含为各个图像制作的视图模型列表。从我从演示中得到的信息,Avalonia 应该识别图像视图模型并在列表框中显示相应的用户控件,但列表框什么都不显示,元素检查器报告列表框已连接到列表的通用对象。我不确定我做错了什么,但我怀疑这与它没有在图像视图模型和图像视图之间建立联系有关。

BrowserViewModel.cs (MainWindowViewModel):

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Threading.Tasks;
using Avalonia.NETCoreMVVMApp.Models;
using ReactiveUI;

namespace Avalonia.NETCoreMVVMApp.ViewModels
{
    public class BrowserViewModel : ReactiveObject
    {
        //how many results to display per page. Right now in the absence of pages it's used as the limit for how many results
        //I pull from the database
        private const int PageResultSize = 50;
        //Observable property for the list of results pulled from the databse
        private readonly ObservableAsPropertyHelper<List<BrowserResultViewModel>> _browserResults;
        public List<BrowserResultViewModel> BrowserResults => _browserResults.Value;
        
        //reactive command used to link the SubmitButton click event to the service that retrieves images from the database
        public ReactiveCommand<Unit, List<BrowserResultViewModel>> FetchImages { get; }

        //property for the search query out in through a text box
        private string _searchQuery;
        public string SearchQuery
        {
            get => _searchQuery;
            set => this.RaiseAndSetIfChanged(ref _searchQuery, value);
        }

        //property for keeping track of the page the browser is on. (Not yet implemented)
        private int _pageNumber;
        public int PageNumber
        {
            get => _pageNumber;
            set => this.RaiseAndSetIfChanged(ref _pageNumber, value);
        }
        

        public BrowserViewModel()
        {
            FetchImages = ReactiveCommand.CreateFromTask(FetchImagesAsync);
            _browserResults = FetchImages.ToProperty(
                this, x => x.BrowserResults, scheduler: RxApp.MainThreadScheduler);
        }

        //background function for the FetchImage command
        public async Task<List<BrowserResultViewModel>> FetchImagesAsync()
        {
            var context = new ApplicationContext();
            var results = context.Images
                .Take(PageResultSize)
                .Select(x => new BrowserResultViewModel(x.FileUri, x.Tags
                    .Select(x => x.Name)
                    .ToList()))
                .ToList();
            return results;
        }
    }
}

浏览器结果视图模型.cs:

using System;
using System.Collections.Generic;
using ReactiveUI;

namespace Avalonia.NETCoreMVVMApp.ViewModels
{
    public class BrowserResultViewModel : ReactiveObject
    {
        //Uri containing corresponding image file path.
        public Uri ImageUri;

        //property for an image's corresponding tags (Not yet implemented)
        private List<string> _tags;
        public List<string> Tags
        {
            get => _tags;
            set => this.RaiseAndSetIfChanged(ref _tags, value);
        }
        
        public BrowserResultViewModel(Uri imageUri, List<string> tags)
        {
            ImageUri = imageUri;
            Tags = tags;
        }
    }
}

BrowserView.cs(主窗口视图):

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Mixins;
using Avalonia.Markup.Xaml;
using Avalonia.NETCoreMVVMApp.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace Avalonia.NETCoreMVVMApp.Views
{
    public partial class BrowserResultView : ReactiveUserControl<BrowserResultViewModel>
    {
        
        public BrowserResultView()
        {
            this.WhenActivated(disposable =>
            {
                //this binds the uri for an image to the image control in avalonia.
                this.OneWayBind(ViewModel,
                        viewModel => viewModel.ImageUri,
                        view => view.Thumbnail.Source)
                    .DisposeWith(disposable);
            });
            
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
    }    
}

浏览器结果视图.cs:

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Mixins;
using Avalonia.Markup.Xaml;
using Avalonia.NETCoreMVVMApp.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace Avalonia.NETCoreMVVMApp.Views
{
    public partial class BrowserResultView : ReactiveUserControl<BrowserResultViewModel>
    {
        
        public BrowserResultView()
        {
            this.WhenActivated(disposable =>
            {
                //this binds the uri for an image to the image control in avalonia.
                this.OneWayBind(ViewModel,
                        viewModel => viewModel.ImageUri,
                        view => view.Thumbnail.Source)
                    .DisposeWith(disposable);
            });
            
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
    }    
}

浏览器结果视图.axml:

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Avalonia.NETCoreMVVMApp.Views.BrowserResultView">
    <Grid>
        <Image x:Name="Thumbnail" Margin="6" Width="64" Height="64" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</UserControl>

主窗口.xaml:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:Avalonia.NETCoreMVVMApp.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:reactiveUi="http://reactiveui.net"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="Avalonia.NETCoreMVVMApp.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="Avalonia.NETCoreMVVMApp">

    <Grid RowDefinitions="1*, 20*" ColumnDefinitions="*">
        <Grid RowDefinitions="*" ColumnDefinitions="*, 70">
            <TextBox x:Name="searchBox"/>
            <Button Grid.Column="1" x:Name="submitSearchBtn">Submit</Button>
        </Grid>
        <ListBox x:Name="browserResultsListBox" Grid.Row="1"/>
    </Grid>
</Window>

【问题讨论】:

  • 我的回答有帮助吗?

标签: c# reactiveui avaloniaui


【解决方案1】:

你实际上并没有连接起来,ListBox 没有DataTemplate

尝试:

<ListBox x:Name="browserResultsListBox" Items={Binding BrowserResults} Grid.Row="1">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type BrowserResultViewModel}">
            <Image Source={Binding ImageUri} />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多