ReactiveUI 6,listview不更新

时间:2014-11-03 07:50:38

标签: wpf reactiveui

正在修改电磁阀并尝试在通用应用中使用一个简单的示例并且有一些差异。

我将viewmodel视为:

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在哪里有一个非常简单的工作示例?

1 个答案:

答案 0 :(得分:1)

如果您await Observable,它大致相当于Rx:

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

这里有问题,请查看你的Observable:

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

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

Wat Do?

相反,我们应该写:

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测试可以在他们想要显式测试它们时调用它们。