Back

WPF 截图工具

Language 中文 English

上周需要再产品上编写一个截图工具,发现博客上的文章都是只有截取屏幕这一步,或是需要关注公众号之类的营销,便自己撸了一个,今天在github上发现了一个开源的框架,如果准备开始写的可以参照那个框架。

https://github.com/WPFDevelopersOrg/WPFDevelopers

刚刚写完便记录一下自己遇到的问题,防止后面忘掉。

@[toc]

在渲染canvas的时候报错:System.ArgumentException:“值不在预期的范围内。”

 var renderTargetBitmap = new RenderTargetBitmap(Convert.ToInt32(_AllScreenWidth),
                Convert.ToInt32(_AllScreenHeight), 96d, 96d, PixelFormats.Default);
            renderTargetBitmap.Render(Capture_Canvas);


            var targetRec = new Int32Rect((int)rect.X, (int)rect.Y, (int)rect.Width , (int)rect.Height );

            var img = new CroppedBitmap(renderTargetBitmap,
                targetRec);

这里我原来按照用户框的举行设置渲染范围发现报错,修改targetRec的X,Y后可以显示图片,确认应该是裁剪范围的原因,修改为整个屏幕渲染解决问题

报错原因应该是剪切范围与渲染范围一致导致的报错,应该保证原图大于剪切区域。

取消EventHanlder上面挂载的所有事件

How would it be possible to remove all event handlers of the ‘Click’ event of a ‘Button’?

先说一下,我这一步其实绕了远路增加了程序的冗余性,应该是创建一个工厂模式,用户点击按钮时按照性质唤醒不同的函数,这种可参照上面的框架地址。

才开始是因为截图下面创建了四个按钮,分别是箭头,矩形,文字和保存,但是唤醒箭头功能后,再次点击矩形两个都会,但是他们点击的顺序是不一致的,所以我打算每次点击事件按钮就取消掉挂载在“MouseDown,MouseUp,MouseMove的所有事件,在重新挂载到此按钮事件,所以有了上面这个需求。 搜索后发现需要反射方法调用MouseDownEventHandler里面的removeHanlder方法,这个可以在元数据中看到具体的数据,但是目前有的解决方案全是针对Winform的,不适用于WPF。

这是Winform control

/// <summary>
        /// 清除一个对象的某个事件所挂钩的delegate
        /// </summary>
        /// <param name="ctrl">控件对象</param>
        /// <param name="eventName">事件名称,默认的</param>
        public static void ClearEvents(this object ctrl, string eventName = "_EventAll")
        {
            if (ctrl == null) return;

            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static;
            EventInfo[] events = ctrl.GetType().GetEvents(bindingFlags);


            if (events == null || events.Length < 1) return;

            for (int i = 0; i < events.Length; i++)
            {

                EventInfo ei = events[i];
                //只删除指定的方法,默认是_EventAll,前面加_是为了和系统的区分,防以后雷同
                if (eventName != "_EventAll" && ei.Name != eventName) continue;



                /********************************************************
                 * class的每个event都对应了一个同名(变了,前面加了Event前缀)的private的delegate类
                 * 型成员变量(这点可以用Reflector证实)。因为private成
                 * 员变量无法在基类中进行修改,所以为了能够拿到base 
                 * class中声明的事件,要从EventInfo的DeclaringType来获取
                 * event对应的成员变量的FieldInfo并进行修改
                 ********************************************************/

                var fileds = ei.DeclaringType.GetFields(bindingFlags);
                foreach (var filed in fileds)
                {
                    if (filed.Name.Equals("MouseDownEvent"))
                    {
                        filed.SetValue(ctrl, null);
                        var mEvent = filed.GetValue(ctrl);
                        var remove = filed.FieldHandle;

                    }
                    if (filed.Name.Equals("MouseMoveEvent"))
                        filed.SetValue(ctrl, null);
                    if (filed.Name.Equals("MouseUpEvent"))
                        filed.SetValue(ctrl, null);
                }
            }
            

这是WPF UIelement

/// <summary>
        /// Removes all event handlers subscribed to the specified routed event from the specified element.
        /// </summary>
        /// <param name="element">The UI element on which the routed event is defined.</param>
        /// <param name="routedEvent">The routed event for which to remove the event handlers.</param>
        public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
        {
            // Get the EventHandlersStore instance which holds event handlers for the specified element.
            // The EventHandlersStore class is declared as internal.
            var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
                "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
            object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

            // If no event handlers are subscribed, eventHandlersStore will be null.
            // Credit: https://stackoverflow.com/a/16392387/1149773
            if (eventHandlersStore == null)
                return;

            // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
            // for getting an array of the subscribed event handlers.
            var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
                "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
                eventHandlersStore, new object[] { routedEvent });

            if (routedEventHandlers == null)
                return;

            // Iteratively remove all routed event handlers from the element.
            foreach (var routedEventHandler in routedEventHandlers)
                element.RemoveHandler(routedEvent, routedEventHandler.Handler);
        }

箭头样式

箭头样式也是从github上面找的框架,直接地址po上来吧

https://github.com/icsharpcode/WpfDesigner