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

Passing an UIElement to the ViewModel using RelayCommand from MVVM-Light

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

因此,我正在研究一种方法来保存属于每个 LoadingTileViewDocumentView 实例的缓存图像,以便可以显示它而不是实际的 DocumentView ,下次启动我的程序时。

我目前正在研究如何保存缓存图像。我的想法是让每个 LoadTileView 在加载后通过 MVVM-Light RelayCommand 调用其 LoadingTileViewModel 并将其 DocumentView 实例传递给命令。我把 DocumentView 放在 DataTemplate 中,这样我就可以用它的缓存图像(和相应的视图)替换它,一旦它存在,通过在 LoadingTileView.

中相应地设置 CurrentDocumentViewModel

我找到了关于如何将 UIElement 传递给 ViewModel (here) and how to use the RelayCommand with an argument (here) 的解释。结合 blender interaction-triggers 来触发 ViewModel 中的 ViewLoadedEventHandlerCommand 得到如下所示的简化代码。

此代码编译并运行,但 ExecuteViewLoadedEventHandlerCommand(object parameter) 中的 parameterNull。我也尝试过直接使用 DocumentView,而不是 ContentControl,但 parameter 仍然是 Null

我不确定我在这里做错了什么,因为我在其他情况下使用了 RelayCommandInteraction.Triggers,它们工作正常。也许有人能发现我的错误?

LoadingTileView的代码:

<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>

LoadingTileViewModel的代码:

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();
}

更新:

Stacktrace,在第 UIElement toSave = (UIElement)parameter; 行中断时:

Software.UI.ViewModel.dll!ProgramEditor.ViewModel.LoadingTileViewModel.ExecuteViewLoadedEventHandlerCommand(object parameter) Line 168  C#
Software.UI.ViewModel.dll!ProgramEditor.ViewModel.LoadingTileViewModel.get_ViewLoadedEventHandlerCommand.AnonymousMethod__50_0(object i) Line 184   C#
[Native to Managed Transition]  
[Managed to Native Transition]  
GalaSoft.MvvmLight.dll!GalaSoft.MvvmLight.Helpers.WeakAction<System.__Canon>.Execute(System.__Canon parameter)  Unknown
GalaSoft.MvvmLight.dll!GalaSoft.MvvmLight.Command.RelayCommand<object>.Execute(object parameter)    Unknown
System.Windows.Interactivity.dll!System.Windows.Interactivity.InvokeCommandAction.Invoke(object parameter)  Unknown
System.Windows.Interactivity.dll!System.Windows.Interactivity.TriggerBase.InvokeActions(object parameter)   Unknown
System.Windows.Interactivity.dll!System.Windows.Interactivity.EventTriggerBase.OnEvent(System.EventArgs eventArgs)  Unknown
System.Windows.Interactivity.dll!System.Windows.Interactivity.EventTriggerBase.OnEventImpl(object sender, System.EventArgs eventArgs)   Unknown
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) Unknown
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised)    Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args)   Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs e)  Unknown
PresentationFramework.dll!System.Windows.BroadcastEventHelper.BroadcastEvent(System.Windows.DependencyObject root, System.Windows.RoutedEvent routedEvent)  Unknown
PresentationFramework.dll!System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(object root) Unknown
PresentationCore.dll!MS.Internal.LoadedOrUnloadedOperation.DoWork() Unknown
PresentationCore.dll!System.Windows.Media.MediaContext.FireLoadedPendingCallbacks() Unknown
PresentationCore.dll!System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()    Unknown
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandlerCore(object resizedCompositionTarget)    Unknown
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandler(object resizedCompositionTarget)    Unknown
PresentationCore.dll!System.Windows.Media.MediaContext.Resize(System.Windows.Media.ICompositionTarget resizedCompositionTarget) Unknown
PresentationCore.dll!System.Windows.Interop.HwndTarget.OnResize()   Unknown
PresentationCore.dll!System.Windows.Interop.HwndTarget.HandleMessage(MS.Internal.Interop.WindowMessage msg, System.IntPtr wparam, System.IntPtr lparam) Unknown
PresentationCore.dll!System.Windows.Interop.HwndSource.HwndTargetFilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)   Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)  Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)   Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)  Unknown
[Native to Managed Transition]  
user32.dll!74d862fa()   Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]    
user32.dll!74d86d3a()   Unknown
user32.dll!74d86ded()   Unknown
user32.dll!74d86e4c()   Unknown
ntdll.dll!773a011a()    Unknown
user32.dll!74d872c1()   Unknown
user32.dll!74dad4ff()   Unknown
user32.dll!74d862fa()   Unknown
user32.dll!74d86d3a()   Unknown
user32.dll!74d90d37()   Unknown
user32.dll!74d90d5d()   Unknown
WindowsBase.ni.dll!6b4a6e70()   Unknown
[Managed to Native Transition]  
WindowsBase.dll!MS.Win32.HwndSubclass.DefWndProcWrapper(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)    Unknown
[Native to Managed Transition]  
user32.dll!74d862fa()   Unknown
user32.dll!74d86d3a()   Unknown
user32.dll!74d90d37()   Unknown
user32.dll!74d90d5d()   Unknown
WindowsBase.ni.dll!6b4ced1a()   Unknown
[Managed to Native Transition]  
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)  Unknown
[Native to Managed Transition]  
user32.dll!74d862fa()   Unknown
user32.dll!74d86d3a()   Unknown
user32.dll!74d86ded()   Unknown
user32.dll!74d86ded()   Unknown
user32.dll!74d88fb7()   Unknown
ntdll.dll!773a011a()    Unknown
user32.dll!74d92832()   Unknown
user32.dll!74d92802()   Unknown
user32.dll!74d9289a()   Unknown
[Managed to Native Transition]  
MahApps.Metro.dll!Standard.NativeMethods.SetWindowRgn(System.IntPtr hWnd, System.IntPtr hRgn, bool bRedraw) Unknown
MahApps.Metro.dll!Microsoft.Windows.Shell.WindowChromeWorker._SetRoundingRegion(Standard.WINDOWPOS? wp) Unknown
MahApps.Metro.dll!Microsoft.Windows.Shell.WindowChromeWorker._UpdateFrameState(bool force)  Unknown
MahApps.Metro.dll!Microsoft.Windows.Shell.WindowChromeWorker._ApplyNewCustomChrome()    Unknown
MahApps.Metro.dll!Microsoft.Windows.Shell.WindowChromeWorker._WindowSourceInitialized(object sender, System.EventArgs e)    Unknown
PresentationFramework.dll!System.Windows.Window.OnSourceInitialized(System.EventArgs e) Unknown
PresentationFramework.dll!System.Windows.Window.CreateSourceWindow(bool duringShow) Unknown
PresentationFramework.dll!System.Windows.Window.CreateSourceWindowDuringShow()  Unknown
PresentationFramework.dll!System.Windows.Window.SafeCreateWindowDuringShow()    Unknown
PresentationFramework.dll!System.Windows.Window.ShowHelper(object booleanBox)   Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)  Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()   Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object state)  Unknown
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(object obj)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext, System.Threading.ContextCallback callback, object state)  Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()   Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()  Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)  Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)  Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)   Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)  Unknown
[Native to Managed Transition]  
user32.dll!74d862fa()   Unknown
user32.dll!74d86d3a()   Unknown
user32.dll!74d877d3()   Unknown
user32.dll!74d8789a()   Unknown
WindowsBase.ni.dll!6b4ceff4()   Unknown
[Managed to Native Transition]  
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame)   Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame)   Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore)   Unknown
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window)  Unknown
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window)  Unknown
PresentationFramework.dll!System.Windows.Application.Run()  Unknown
ProgramEditor.exe!ProgramEditor.App.Main()  C#
[Native to Managed Transition]  
mscoreei.dll!7143cc0b() Unknown
mscoree.dll!714b7f16()  Unknown
mscoree.dll!714b4de3()  Unknown
kernel32.dll!76d6338a() Unknown
ntdll.dll!773c9902()    Unknown
ntdll.dll!773c98d5()    Unknown

在评论中你说 someinput 达到了命令。这意味着 elementname 绑定完全失败或延迟。

因此:为了测试,添加具有相同 i:InvokeCommandActionButton,但在 <i:EventTrigger EventName="Click"> 上,这样您可以测试以后的绑定是否有效。

调试时还要注意VS中的Output window。如果绑定失败,应该有一条消息。

我的假设是问题在您 Tile 的控制范围内。我猜你的 Tile 控件在 Loaded 事件发生时还没有初始化它的子元素。

事实证明,问题是 TileViewLoaded 事件在 DataTemplate 中的 DocumentView 加载之前 触发 .我通过将 DocumentViewModel 中的另一个命令附加到 DocumentViewLoaded 事件来发现这一点。之后我看到了马库斯的回答,这基本上就是他的建议。

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

<DataTemplate DataType="{x:Type ViewModels:DocumentViewModel}">
    <StackPanel>
        <View:DocumentView x:Name="DocumentViewInstance"/>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <i:InvokeCommandAction Command="{Binding Path=DataContext.ViewLoadedEventHandlerCommand,
                                                         RelativeSource={RelativeSource FindAncestor,
                                                                                        AncestorType={x:Type UserControl}}}"
                                       CommandParameter="{Binding ElementName=DocumentViewInstance}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </StackPanel>
</DataTemplate>