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

https://github.com/WPFDevelopersOrg/WPFDevelopers

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

@[toc]

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

1
2
3
4
5
6
7
8
9
10
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/// <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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/// <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