2

我正在实现一个由多个平台上的应用程序共享的视图模型。我正在使用具有自己的 MvxEventToCommand 类的 MvvmCross v3,但我相信对于 MVVM Light 等其他框架来说,挑战是相同的。只要事件不带参数使用,实现就很简单了,像点击控件这样的简单交互就是这种情况。

但是当命令需要处理事件参数时,事情变得更加复杂。例如,视图模型需要对某些滚动条更改采取行动(并在关联的列表视图中加载更多项目)。这是 XAML 的示例:

<cmd:EventToCommand 
    Command="{Binding ScrollChanged}" 
    CommandParameter="{Binding EventArgs}" />

(MvvmCross 使用的是 MvxEventToCommand,但原理是一样的)。

然后在我的模型中,我可以有以下命令处理程序:

public ICommand ScrollChanged
{
    get
    {
        return new RelayCommand<ScrollChangedEventArgs>(e =>
        {
            MessageBox.Show("Change!");
        });
    }
}

(MvvmCross 中的 MvxCommand)。

问题是 ScrollChangedEventArgs 是特定于平台的,并且此代码根本无法在可移植类库中编译。这是任何命令的普遍问题,它不仅需要在触发事件时进行推送,而且需要更具体的事件详细信息。将此代码移动到特定于平台的部分是愚蠢的,因为它或多或少地扼杀了可移植视图模型和无代码隐藏视图的概念。我试图搜索在不同平台之间共享视图模型的项目,但它们都使用简单的事件,如“Tap”,没有附加事件详细信息。

更新 1我同意 Stuart 的评论,即视图模型应该只处理更高级别的抽象,所以我将重新表述最初的担忧:如何将低级交互的结果映射到触发业务逻辑命令的平台中立事件?考虑上面的例子:业务逻辑命令是“在列表中加载更多项目”,即我们处理列表虚拟化,其中最初加载来自大型集合的有限数量的项目,并且向下滚动到列表底部应该导致加载额外的项目。

WinRT 可以通过使用支持 ISupportIncrementalLoading 接口的可观察集合来处理列表虚拟化。运行时检测此功能并在用户向下滚动列表时自动从相应服务请求额外的项目。在其他平台上,此功能应手动实现,除了对 ScrollViewer ScrollChanged 事件做出反应外,我找不到任何其他方法。然后我可以看到另外两个选项:

  • 将 OnScrollChanged 处理程序放在代码隐藏文件中并调用可移植视图模型更高级别的事件(例如“OnItemsRequested”);
  • 避免使用代码隐藏的东西并努力将 ScrollChanged 事件直接连接到视图模型,然后我们需要首先重新映射特定于平台的事件。

只要不支持第二个选项,只要将事件处理程序放在代码隐藏文件中就可以了,只要它仅用于事件映射即可。但我想研究使用第二种选择可以做什么。MvvmCross 有 MapCommandParameter 类似乎可以提供帮助,所以我想知道我是否应该利用那个。

更新 2我尝试了 MapCommandParameter 方法,它允许我插入一个特定于平台的适配器,该适配器将映射低级事件以查看特定于模型的命令。因此,第二个选项毫不费力地奏效了。Stuart 还建议使用 listview-subclassing,因此无需关心滚动事件。我打算以后玩它。

4

1 回答 1

2

我同意 viewmodel 命令通常应该用 viewmodel 概念来表达——所以向 viewmodel 发送一个关于滚动条值改变的命令是“奇怪的”,但是向 viewmodel 发送一个关于用户选择某些命令的命令可能是可以的列出要可见的元素(她通过滚动来实现)

我以前做过这类事情的一个例子是在列表选择中。

我最初使用跨平台 eventargs 对象在多个平台上执行此操作 -

然后通过诸如https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Commands/MvxSelectionChangedEventToCommand.cs的 EventToCommand 类在 WindowsPhone 上使用它

然而......我不得不承认这段代码并没有被太多使用......对于列表选择,我们主要使用了 selecteditem 绑定,并且根本没有任何应用程序需要更复杂的参数化命令(到目前为止) - 您甚至可能需要返回非常旧的 v1 mvvmcross 代码来查找使用它的任何示例。

于 2013-04-07T13:35:41.347 回答