使用MVVM-Light中的RelayCommand将UIElement传递给ViewModel

时间:2016-07-07 10:51:18

标签: wpf mvvm mvvm-light relaycommand

在我的程序的开始屏幕中,我显示(非交互式)UserControl DocumentView的缩略图,以在类似Tile的UserControl LoadTileView中显示不同的文档,用户可以在其上单击将文档加载到主视图中。此DocumentView也用于主视图中,以图形方式表示和编辑所选文档。由于此DocumentView图形较重,因此加载需要一些时间,这会导致巨大的启动时间,因为我在开始屏幕内显示DocumentView的多个实例(例如,各种Tiles,用户可以选择要编辑的文档。

因此,我正在开发一种方法来保存属于每个DocumentView的{​​{1}}实例的缓存图像,以便可以显示它而不是实际的LoadingTileView我的程序下次启动。

我目前正在研究如何保存缓存图像。我的想法是让每个DocumentView在加载后通过MVVM-Light LoadTileView调用LoadingTileViewModel并将RelayCommand的实例传递给命令。我将DocumentView放在DataTemplate中,以便我可以通过在DocumentView中相应地设置CurrentDocumentViewModel来替换它的缓存图像(以及相应的View)。

我找到了关于如何将LoadingTileView传递给ViewModel (here)以及如何将UIElement与参数(here)一起使用的说明。结合使用blender交互触发器触发ViewModel中的RelayCommand,可以得到如下所示的简化代码。

此代码编译并运行,但ViewLoadedEventHandlerCommand中的parameterExecuteViewLoadedEventHandlerCommand(object parameter)。我还尝试直接使用Null,而不是DocumentView,但ContentControl仍为parameter

我不确定我在这里做错了什么,因为我在其他情况下使用了NullRelayCommand这些,他们正确地工作了。也许有人可以发现我的错误?

LoadingTileView 的代码:

Interaction.Triggers

LoadingTileViewModel的代码

<UserControl.Resources>
    <DataTemplate DataType="{x:Type ViewModels:DocumentViewModel}">
        <View:DocumentView/>
    </DataTemplate>
</UserControl.Resources>

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding ViewLoadedEventHandlerCommand}"
                               CommandParameter="{Binding ElementName=DocumentViewInstance}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

<Controls:Tile Command="{Binding LoadProgramCommand}">
    <Viewbox>
        <ContentControl x:Name="DocumentViewInstance" Content="{Binding CurrentDocumentViewModel}"/>
    </Viewbox>
</Controls:Tile>

更新

Stacktrace,在第public LoadingTileViewModel() { ... ViewLoadedEventHandlerCommand = new RelayCommand<object>((obj)=>ExecuteViewLoadedEventHandlerCommand(obj)); ... } public RelayCommand<object> ViewLoadedEventHandlerCommand { get; set; } private void ExecuteViewLoadedEventHandlerCommand(object parameter) // object is NULL { UIElement toSave = (UIElement)parameter; //OnViewLoaded(); } 行突破时:

UIElement toSave = (UIElement)parameter;

2 个答案:

答案 0 :(得分:0)

在评论中你说someinput到达命令。这意味着元素名称绑定要么完全失败要么迟到。

所以:要进行测试,请添加一个Button i:InvokeCommandAction<i:EventTrigger EventName="Click"> TileLoaded这样可以测试以后的Binding是否有效。

调试时,请注意VS中的输出窗口。如果绑定失败,则应该有消息。

我的假设是问题出在[HttpPost]控制之内。我猜你的Tile控件在public class HomeController { [HttpPost] public ActionResult Method1 (object abc) { //blah //blah return blah } [HttpPost] public ActionResult Method2 (object abc) { //blah //blah return blah } [HttpPost] public ActionResult Method3 (object abc) { //blah //blah return blah } } 事件发生时还没有初始化它的子元素。

答案 1 :(得分:0)

事实证明,问题是Loaded TileView事件在加载DataTemplate内的DocumentView 之前触发了。我通过将DocumentViewModel中的另一个命令附加到Loaded的{​​{1}}事件中找到了这一点。之后我看到马库斯的答案,这基本上就是他的建议。

最后,我通过将DocumentView事件的命令移动到DataTemplate来使我的代码工作。为此,我使用Loaded绑定到其StackPanel事件,以便我最终得到:

Loaded