从 MaterialDesignInXamlToolkit 使用我自己的 DialogHost 时获取 InvalidOperationException

Getting InvalidOperationException while using my own DialogHost from MaterialDesignInXamlToolkit

我正在使用 Material Design library for WPF 并尝试在单击按钮时打开对话框。调用 DialogHost.Show(...) 后,程序中断并显示以下消息

Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree.

我试图了解堆栈跟踪以及为什么会发生这种情况,但由于对库和 MVVM 架构的经验有限,似乎无法成功做到这一点。

这是堆栈跟踪

 StackTrace "
   at System.Windows.FrameworkElement.FindResourceInTree(FrameworkElement  feStart, FrameworkContentElement fceStart, DependencyProperty dp, Object resourceKey, Object unlinkedParent, Boolean allowDeferredResourceReference, Boolean mustReturnDeferredResourceReference, DependencyObject boundaryElement, InheritanceBehavior& inheritanceBehavior, Object& source)\r\n
   at System.Windows.FrameworkElement.FindResourceInternal(FrameworkElement fe, FrameworkContentElement fce, DependencyProperty dp, Object resourceKey, Object unlinkedParent, Boolean allowDeferredResourceReference, Boolean mustReturnDeferredResourceReference, DependencyObject boundaryElement, Boolean isImplicitStyleLookup, Object& source)\r\n
   at System.Windows.FrameworkElement.FindImplicitStyleResource(FrameworkElement fe, Object resourceKey, Object& source)\r\n
   at System.Windows.FrameworkElement.GetRawValue(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& entry)\r\n
   at System.Windows.FrameworkElement.EvaluateBaseValueCore(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& newEntry)\r\n
   at System.Windows.DependencyObject.EvaluateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry newEntry, OperationType operationType)\r\n
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)\r\n
   at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)\r\n
   at System.Windows.FrameworkElement.UpdateStyleProperty()\r\n
   at System.Windows.TreeWalkHelper.InvalidateOnTreeChange(FrameworkElement fe, FrameworkContentElement fce, DependencyObject parent, Boolean isAddOperation)\r\n
   at System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)\r\n
   at System.Windows.FrameworkElement.AddLogicalChild(Object child)\r\n
   at System.Windows.Controls.ContentControl.OnContentChanged(Object oldContent, Object newContent)\r\n
   at System.Windows.Controls.ContentControl.OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\r\n
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)\r\n
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)\r\n
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)\r\n
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)\r\n
   at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)\r\n
   at System.Windows.StyleHelper.InvalidateDependents(Style ownerStyle, FrameworkTemplate frameworkTemplate, DependencyObject container, DependencyProperty dp, FrugalStructList 1& dependents, Boolean invalidateOnlyContainer)\r\n
   at System.Windows.StyleHelper.OnTriggerSourcePropertyInvalidated(Style ownerStyle, FrameworkTemplate frameworkTemplate, DependencyObject container, DependencyProperty dp, DependencyPropertyChangedEventArgs changedArgs, Boolean invalidateOnlyContainer, FrugalStructList 1& triggerSourceRecordFromChildIndex, FrugalMap& propertyTriggersWithActions, Int32 sourceChildIndex)\r\n
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)\r\n
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)\r\n
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)\r\n
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)\r\n
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)\r\n
   at MaterialDesignThemes.Wpf.DialogHost.<ShowInternal>d__29.MoveNext() in C:\projects\materialdesigninxamltoolkit\MaterialDesignThemes.Wpf\DialogHost.cs:line 192\r\n--- End of stack trace from previous location where exception was thrown ---\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
   at MaterialDesignThemes.Wpf.DialogHost.<Show>d__28.MoveNext() in C:\projects\materialdesigninxamltoolkit\MaterialDesignThemes.Wpf\DialogHost.cs:line 183\r\n--- End of stack trace from previous location where exception was thrown ---\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
   at MaterialDesignThemes.Wpf.DialogHost.<Show>d__23.MoveNext() in C:\projects\materialdesigninxamltoolkit\MaterialDesignThemes.Wpf\DialogHost.cs:line 111\r\n--- End of stack trace from previous location where exception was thrown ---\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
   at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult()\r\n
   at SimpleUXApp_ForRizwan.MainWindow.<btn_Action_Click>d__5.MoveNext() in C:\Users\Paras\Documents\Visual Studio 2015\Projects\SimpleUXApp_ForRizwan\SimpleUXApp_ForRizwan\MainWindow.xaml.cs:line 99\r\n--- End of stack trace from previous location where exception was thrown ---\r\n
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)\r\n
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()\r\n
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)\r\n
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at System.Windows.Threading.DispatcherOperation.Invoke()\r\n
   at System.Windows.Threading.Dispatcher.ProcessQueue()\r\n
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)\r\n
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)\r\n
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)\r\n
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)\r\n
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)\r\n
   at System.Windows.Application.RunDispatcher(Object ignore)\r\n
   at System.Windows.Application.RunInternal(Window window)\r\n
   at System.Windows.Application.Run(Window window)\r\n
   at System.Windows.Application.Run()\r\n
   at SimpleUXApp_ForRizwan.App.Main() in C:\Users\Paras\Documents\Visual Studio 2015\Projects\SimpleUXApp_ForRizwan\SimpleUXApp_ForRizwan\obj\Debug\App.g.cs:line 0\r\n
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)\r\n
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)\r\n
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()\r\n
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)\r\n
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at System.Threading.ThreadHelper.ThreadStart()"  string

这里是相关代码

片段来自 MainWindow.xaml.cs

    void CredsDialogClosingHandler(object sender, DialogClosingEventArgs e)
    {
        credentials = new UserCreds(txt_Password.SecurePassword);
        e.Handled = true;
    }

    private async void btn_Action_Click(object sender, RoutedEventArgs e)
    {
        if(credentials == null)
        {
            var getCreds = await DialogHost.Show(dialog_about, CredsDialogClosingHandler);
        }
    ...
    }

片段来自 MainWindow.xaml

    <materialDesign:DialogHost 
        Name="dialog_about"
        Grid.Row="2"
        HorizontalAlignment="Center" VerticalAlignment="Center" CloseOnClickAway="true">
        <materialDesign:DialogHost.DialogContent>
            <StackPanel Margin="16">
                <StackPanel Width="350" Height="200">
                    <Label 
                        HorizontalAlignment="Center" 
                        FontWeight="Medium"
                        FontSize="15"
                        Foreground="{DynamicResource PrimaryHueDarkBrush}"
                        Margin="0,15,0,10">
                        Password please
                    </Label>
                    <PasswordBox 
                        Name="txt_Password"
                        Margin="15,0,0,15" 
                        HorizontalAlignment="Center">
                    </PasswordBox>
                </StackPanel>

                <Button 
                    Name="btn_DialogClose"
                    Style="{StaticResource MaterialDesignRaisedButton}"
                    IsDefault="True"
                    Margin="0 8 8 0"
                    MaxWidth="100"
                    Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
                    Content="Submit"/>
            </StackPanel>
        </materialDesign:DialogHost.DialogContent>
    </materialDesign:DialogHost>

Github 回购 Cryption Utility

一些注意事项。

  • DialogHost 是一个 ContentControl,内容是您 window 的所有内容,对话框应该覆盖
  • 使用 DialogHost.Show 方法时,您应该传递对话框的内容,而不是 DialogHost 本身。 这是你循环错误的根本原因。
  • 通常您可能会在 MVVM 设置中使用 DialogHost.Show,但您使用的是隐藏代码。在这种情况下,您可以使用路由命令打开对话框,并在对话框关闭时附加事件以回调到代码隐藏中:
<Button
    Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}"
    materialDesign:DialogHost.DialogClosingAttached="DialogClosing"
/>