上周需要再产品上编写一个截图工具,发现博客上的文章都是只有截取屏幕这一步,或是需要关注公众号之类的营销,便自己撸了一个,今天在github上发现了一个开源的框架,如果准备开始写的可以参照那个框架。
https://github.com/WPFDevelopersOrg/WPFDevelopers
刚刚写完便记录一下自己遇到的问题,防止后面忘掉。
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后可以显示图片,确认应该是裁剪范围的原因,修改为整个屏幕渲染解决问题
报错原因应该是剪切范围与渲染范围一致导致的报错,应该保证原图大于剪切区域。
How would it be possible to remove all event handlers of the ‘Click’ event of a ‘Button’?
先说一下,我这一步其实绕了远路增加了程序的冗余性,应该是创建一个工厂模式,用户点击按钮时按照性质唤醒不同的函数,这种可参照上面的框架地址。
才开始是因为截图下面创建了四个按钮,分别是箭头,矩形,文字和保存,但是唤醒箭头功能后,再次点击矩形两个都会,但是他们点击的顺序是不一致的,所以我打算每次点击事件按钮就取消掉挂载在``MouseDown,MouseUp
,MouseMove
的所有事件,在重新挂载到此按钮事件,所以有了上面这个需求。
搜索后发现需要反射方法调用MouseDownEventHandler里面的removeHanlder方法,这个可以在元数据中看到具体的数据,但是目前有的解决方案全是针对Winform的,不适用于WPF。
///
/// 清除一个对象的某个事件所挂钩的delegate
///
/// 控件对象
/// 事件名称,默认的
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);
}
}
///
/// Removes all event handlers subscribed to the specified routed event from the specified element.
///
/// The UI element on which the routed event is defined.
/// The routed event for which to remove the event handlers.
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