【问题标题】:Exception "The operation completed successfully" raising property changed event异常“操作成功完成”引发属性更改事件
【发布时间】:2016-08-29 22:02:16
【问题描述】:

我遇到了可能是我见过的最没用的异常(在 VBA 之外),System.ComponentModel.Win32Exception: "The operation completed successfully"

堆栈跟踪:

   at MS.Win32.UnsafeNativeMethods.CreateWindowEx(Int32 dwExStyle, String lpszClassName, String lpszWindowName, Int32 style, Int32 x, Int32 y, Int32 width, Int32 height, HandleRef hWndParent, HandleRef hMenu, HandleRef hInst, Object pvParam)
   at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
   at System.Windows.Interop.HwndSource.Initialize(HwndSourceParameters parameters)
   at System.Windows.Interop.HwndSource..ctor(HwndSourceParameters parameters)
   at System.Windows.Controls.Primitives.Popup.PopupSecurityHelper.BuildWindow(Int32 x, Int32 y, Visual placementTarget, Boolean transparent, HwndSourceHook hook, AutoResizedEventHandler handler)
   at System.Windows.Controls.Primitives.Popup.BuildWindow(Visual targetVisual)
   at System.Windows.Controls.Primitives.Popup.CreateWindow(Boolean asyncCall)
   at System.Windows.Controls.Primitives.Popup.OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
   at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
   at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.ClrBindingWorker.NewValueAvailable(Boolean dependencySourcesChanged, Boolean initialValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(Object o, String propName)
   at System.Windows.WeakEventManager.ListenerList`1.DeliverEvent(Object sender, EventArgs e, Type managerType)
   at System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(Object sender, PropertyChangedEventArgs args)
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at MVVMSeaCores.Controls.HelpTip.NotifyOfPropertyChange(String propertyName) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 140
   at MVVMSeaCores.Controls.HelpTip.set_IsOpen(Boolean value) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 181
   at MVVMSeaCores.Controls.HelpTipManager.OpenNext() in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 102
   at MVVMSeaCores.Controls.HelpTipManager.AddedToScreen(HelpTip helpTip) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 115
   at MVVMSeaCores.Controls.HelpTipManager.HelpTip_PropertyChanged(Object sender, PropertyChangedEventArgs e) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 67
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at MVVMSeaCores.Controls.HelpTip.NotifyOfPropertyChange(String propertyName) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 140
   at MVVMSeaCores.Controls.HelpTip.set_IsOnscreen(Boolean value) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 195
   at MVVMSeaCores.Controls.HelpPopup.View1_Loaded(Object sender, RoutedEventArgs e) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpPopup.xaml.cs:line 181
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
   at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
   at MS.Internal.LoadedOrUnloadedOperation.DoWork()
   at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Interop.HwndTarget.OnResize()
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

它始终在一行中发生,为属性 IsOpen 引发属性更改事件,但它似乎是随机发生的(有时一切正常!):

    private void NotifyOfPropertyChange(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName)); //<-here
        }
    }

对于上下文,IsOpen 绑定到弹出窗口的 open 属性:

<Popup x:Name="Popup"
               DataContext="{Binding HelpTip, ElementName=userControl}"
               IsOpen="{Binding IsOpen}"
               StaysOpen="True" PopupAnimation="Fade"
               AllowsTransparency="True"
               Placement="{Binding Placement, ElementName=userControl}">

并且由一个静态类设置,它确保一次只在屏幕上显示一个,使用加载的事件来更新 IsOnscreen 属性和静态管理器类中的此方法:

    private static void HelpTip_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        HelpTip helpTip = sender as HelpTip;
        if (helpTip != null)
        {
            //is this on screen or not?
            switch (e.PropertyName)
            {
                case "IsOnscreen":
                    //Update our onscreen lists and perform related behaviour
                    if (helpTip.IsOnscreen)
                    {
                        AddedToScreen(helpTip);
                    }
                    else
                    {
                        RemovedFromScreen(helpTip);
                    }
                    break;
                case "IsOpen":
                    lock (helpTip.Lock)
                    {
                        if (!helpTip.IsOpen)
                        {
                            OpenNext();
                        }
                    }
                    break;
            }
        }
    }

OpenNext 选择一个添加到屏幕的帮助提示,并将其设置为使用 IsOpen 打开,这似乎是导致错误的原因。

一开始我以为可能是并发的问题,但是我把所有的线程化和简化的东西都去掉了,现在实际上一切都在主线程上完成了。

我以前从未遇到过通知属性更改失败的情况,而且我不知道可能出了什么问题。看看这个:System.ComponentModel.Win32Exception: The operation completed successfully 它似乎与使用太多句柄有关(但我不确定我是如何达到打开和关闭 6 或 7 个弹出窗口的限制 - 编辑:还使用任务管理器进行了检查,它在崩溃时使用了大约 530 个。)或者使用了太大的图形或太大的缓冲区,我认为我没有这样做,因为这些弹出窗口只是少数几个组件。

【问题讨论】:

  • 用windows任务管理器监控你的进程,看看它消耗了多少句柄。
  • 没想到这样做。它上升到并保持在 530 左右,偶尔增加到 540 左右。所以似乎不是句柄。
  • 好吧,我猜你在复制崩溃之前不会看到多余的句柄。
  • 很容易复制。看似随机,但频繁,使其在 530 崩溃

标签: c# wpf


【解决方案1】:

不是一个很好的答案。但至少它是一种解决方法。该错误发生在 MS.Win32.UnsafeNativeMethods.CreateWindowEx 中,是 WPF 打开弹出窗口的结果。看来这是 WPF 中的一个错误,我几乎没有办法解决它。我仍然不确定为什么它会特别影响这些弹出窗口。 (其他弹出窗口工作正常,显然这不是弹出窗口的常见问题,但它对我来说非常可重现)。

我使用了以下(不是很愉快的)解决方法。简单地使用绑定到它的 IsOpen 的东西关闭和打开弹出窗口是行不通的 - 一旦它崩溃打开,弹出窗口就会完全损坏,直到它被卸载(更改视图)并再次加载。

所以解决方案是捕获错误,从它的父级中删除弹出窗口,然后安排它在调度线程上异步添加。我不得不停止简单地绑定到 IsOpen,而是在代码隐藏中监听属性更改。

我没有发现其他与 Internet 上的弹出窗口有关的错误实例,尽管还有其他各种原因。这可能对将来的某些人有用:

    private void HelpPopup_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.Equals("IsOpen"))
        {
            //re-try opening
            try {
                Popup.IsOpen = (sender as HelpTip).IsOpen;
            }
            catch (System.ComponentModel.Win32Exception ex)
            {
                Canvas parent = Popup.Parent as Canvas;
                Popup.IsOpen = false;
                parent.Children.Remove(Popup);
                Application.Current.Dispatcher.BeginInvoke(new Action(() => {
                    Popup.IsOpen = true;
                    parent.Children.Add(Popup);

                    //known method of updating position (for some reason it was incorrectly positioned on open)
                    var offset = Popup.HorizontalOffset;
                    Popup.HorizontalOffset = offset + 1;
                    Popup.HorizontalOffset = offset;

                }), DispatcherPriority.SystemIdle);

            }
        }
    }

【讨论】:

    【解决方案2】:

    如果您在弹出窗口中使用任何网格,则应提供该网格的高度。否则它将占用无限高度,并且在渲染期间,它会尝试显示具有无限高度网格的弹出窗口并且会崩溃。

    【讨论】:

      猜你喜欢
      • 2011-10-01
      • 1970-01-01
      • 2018-10-10
      • 2011-01-22
      • 2022-11-16
      • 2012-01-17
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      相关资源
      最近更新 更多