【问题标题】:Passing an UIElement to the ViewModel using RelayCommand from MVVM-Light使用 MVVM-Light 中的 RelayCommand 将 UIElement 传递给 ViewModel
【发布时间】:2016-11-09 15:51:52
【问题描述】:

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

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

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

我找到了有关如何将 UIElement 传递给 ViewModel (here) 以及如何将 RelayCommand 与参数 (here) 一起使用的解释。结合搅拌机交互触发器来触发 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();
}

更新:

堆栈跟踪,在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

【问题讨论】:

  • 如果您在构造函数中设置 LoadingTileView 的 DataContext,那么请确保在调用 InitializeComponent() 之前执行此操作
  • 我想说,如果绑定到命令有效,那么 DataContext 就在那里,所以不是这样。我实际上认为代码看起来不错...当您点击ExecuteViewLoadedEventHandlerCommand 时,stacktrace 看起来如何,也许您会找到有关哪里出错的提示...
  • @MarkusHütter 感谢您的评论。不幸的是,调用堆栈并没有给我太多启示。见下文。也许您还有其他建议? LoadingTileViewModel.ExecuteViewLoadedEventHandlerCommand(object parameter) LoadingTileViewModel..ctor.AnonymousMethod__24_0(object obj) [External Code] [Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]
  • @Will 这是一个很好的观点,我没有考虑过。我的代码暂时可以工作,但我应该清理它以更符合 MVVM 模式。

标签: wpf mvvm mvvm-light relaycommand


【解决方案1】:

原来问题在于,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>

【讨论】:

  • 感谢@packoman 的建议。我能够在我的 RelayCommand 参数中检索 Button 控件。这对我有用:- &lt;Button x:Name="MyButton" Command="{Binding _MyRelayCommand}" CommandParameter="{Binding ElementName=MyButton} /&gt;
【解决方案2】:

在 cmets 你说someinput 到达命令。这意味着 elementname 绑定要么完全失败,要么迟到。

所以:为了测试,添加一个Button,它具有相同的i:InvokeCommandAction,但在&lt;i:EventTrigger EventName="Click"&gt; 上,这样您就可以测试以后的绑定是否可以工作。

在调试时还要留意 VS 中的 Output 窗口。如果绑定失败,应该会有一条消息。

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

【讨论】:

  • 是的,最后就是这样。正如我的回答中所述,DataTemplate 是在 Tile 控件之后初始化的。我想知道,这是否是 ContentControl 的默认行为?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 1970-01-01
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多