【问题标题】:ReactiveUI 6 with listview not updating带有列表视图的 ReactiveUI 6 未更新
【发布时间】:2014-11-03 07:50:38
【问题描述】:

一直在修改响应式用户界面,并尝试让一个简单的示例在通用应用程序中运行并有一些差异。

我的视图模型为:

public class Rooms : ReactiveObject
{
    private RoomsService roomService;
    private IReactiveCommand<IList<Room>> fetchRooms;

    private ObservableAsPropertyHelper<IList<Room>> myRooms;
    public IList<Room> MyRooms
    {
        get { return myRooms.Value; }
    }

    public Rooms(RoomsService roomsService)
    {
        this.RoomService = roomsService;
        fetchRooms = ReactiveCommand.CreateAsyncTask<IList<Room>>(Observable.Return<bool>(true), async x => await RoomService.Rooms);
        fetchRooms.Subscribe(_ => LogMessage("Cool, it was invoked!"));
        fetchRooms.ToProperty(this, x => x.MyRooms, out myRooms);

    }

    public RoomsService RoomService
    {
        get { return roomService; }
        set { roomService = value; }
    }
}

正在获取信息的服务是:

public class RoomsService
{
    private FakeRoomService service = new FakeRoomService();

    public IObservable<IList<Room>> Rooms
    {
        get
        {
            LogMessage("RoomsService - Rooms property called.");
            return Observable
                .Interval(TimeSpan.FromSeconds(1))
                .Select(_ => service.GetRoomsForUser());
        }
    }
}

后面有基本代码:

public sealed partial class HubPage : Page
{
    private NavigationHelper navigationHelper;
    private Rooms rooms = new Rooms(new RoomsService());

    /// <summary>
    /// Gets the NavigationHelper used to aid in navigation and process lifetime management.
    /// </summary>
    public NavigationHelper NavigationHelper
    {
        get { return this.navigationHelper; }
    }

    /// <summary>
    /// Gets the rooms view model.
    /// </summary>
    public Rooms Rooms
    {
        get { return this.rooms; }
    }

    public HubPage()
    {
        this.InitializeComponent();
        this.navigationHelper = new NavigationHelper(this);
        this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
    }

以及最终的 xaml:

<Page
x:Name="pageRoot"
x:Class="HubPage"
DataContext="{Binding Rooms, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Hub"
xmlns:data="using:Hub.Data"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Hub SectionHeaderClick="Hub_SectionHeaderClick">
        <HubSection Width="500" x:Uid="Section1Header" Header="Section 1">
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="300" />
                    </Grid.RowDefinitions>

                    <ListView Name="RoomListView" Grid.Row="1" ItemsSource="{Binding MyRooms}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </Grid>
            </DataTemplate>
        </HubSection>         
    </Hub>
</Grid>

我显然在视图模型中遗漏了一些明显的东西,但我不确定它是什么。任务似乎结束了,但属性永远不会更新......或者如果更新了,它不会传播到视图?

任何建议或是否有任何地方的 v6 的非常简单的工作示例?

【问题讨论】:

    标签: wpf reactiveui


    【解决方案1】:

    如果你awaitObservable,大致相当于在 Rx 中:

    someObservable.TakeLast(1).Publish(new AsyncSubject<T>()).Subscribe();
    

    这就是问题所在,请查看您的 Observable:

    return Observable
        .Interval(TimeSpan.FromSeconds(1))
        .Select(_ => service.GetRoomsForUser());
    

    它永远不会终止,所以TakeLast 永远不会返回!

    做什么?

    相反,我们应该写:

    fetchRooms = ReactiveCommand.CreateAsyncTask<IList<Room>>(_ => Task.Run(service.GetRoomsForUser());
    

    然后在 View 代码隐藏中,我们可以设置计时器来调用命令:

    Observable.Interval(TimeSpan.FromSeconds(5), RxApp.MainThreadScheduler)
        .InvokeCommand(this, x => x.ViewModel.FetchRooms);
    

    为什么是 View 代码隐藏?

    在 ViewModel 构造函数中设置计时器并调用 Do Stuff 的命令使得测试变得困难,因为您必须部署 3032x 模拟来阻止一堆事情的发生。

    相反,View 构造函数应该进入 VM 以启动这些操作,并且 VM 测试可以在他们想要显式测试它们时调用它们。

    【讨论】:

    • 谢谢保罗!那么一般建议是在后面的视图代码中完成所有涉及设置计时器和定期请求的工作吗?
    • @KieranH 不是你在后面的View代码里做的工作,而是这个工作是由后面的View代码发起的。您在 VM 中编写代码,但在视图中启动它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多