Skip to content

Commit cef75cb

Browse files
committed
Add synchronous and asynchronous call methods
1 parent 270c706 commit cef75cb

4 files changed

Lines changed: 175 additions & 14 deletions

File tree

src/ScreenGrab/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,25 @@
22

33
## Usage
44

5+
1. Callback method after screenshot is completed
6+
57
```csharp
68
BitmapSource bs;
79
bool isAuxiliary = true; // Open auxiliary lines
810
ScreenGrabber.OnCaptured = bitmap => bs = bitmap.ToImageSource();
911
ScreenGrabber.Capture(isAuxiliary);
12+
```
13+
14+
2. Synchronous method to get screenshot(like MessageBox)
15+
16+
```csharp
17+
bool isAuxiliary = false; // Do not open auxiliary lines
18+
var bitmap = ScreenGrabber.CaptureDialog(isAuxiliary);
19+
```
20+
21+
3. Asynchronous method to get screenshot
22+
23+
```csharp
24+
bool isAuxiliary = false; // Do not open auxiliary lines
25+
var bitmap = await ScreenGrabber.CaptureAsync(isAuxiliary);
1026
```

src/ScreenGrab/ScreenGrab.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</ItemGroup>
1313

1414
<PropertyGroup Label="Nuget">
15-
<Version>1.0.8</Version>
15+
<Version>1.0.9</Version>
1616
<Title>ScreenGrab</Title>
1717
<Description>ScreenGrab extracted from Text-Grab</Description>
1818
<PackageReadmeFile>README.md</PackageReadmeFile>

src/ScreenGrab/ScreenGrabber.cs

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System.Drawing;
1+
using ScreenGrab.Extensions;
2+
using System.Drawing;
23
using System.Windows;
3-
using ScreenGrab.Extensions;
4+
using System.Windows.Threading;
45
using WpfScreenHelper;
56

67
namespace ScreenGrab;
@@ -11,6 +12,8 @@ public abstract class ScreenGrabber
1112

1213
public static Action<Bitmap>? OnCaptured { get; set; }
1314

15+
private static TaskCompletionSource<Bitmap?>? _captureTaskCompletionSource;
16+
1417
public static void Capture(bool isAuxiliary = false)
1518
{
1619
if (IsCapturing) return;
@@ -47,4 +50,117 @@ public static void Capture(bool isAuxiliary = false)
4750
screenGrab.Activate();
4851
}
4952
}
53+
54+
/// <summary>
55+
/// 同步方式捕获屏幕截图,类似 Window.ShowDialog() 的阻塞式调用
56+
/// </summary>
57+
/// <param name="isAuxiliary">是否显示辅助线</param>
58+
/// <returns>返回捕获的 Bitmap,如果用户取消则返回 null</returns>
59+
public static Bitmap? CaptureDialog(bool isAuxiliary = false)
60+
{
61+
if (IsCapturing)
62+
return null;
63+
64+
Bitmap? result = null;
65+
var frame = new DispatcherFrame();
66+
67+
IsCapturing = true;
68+
69+
var allScreens = Screen.AllScreens;
70+
var allScreenGrab = Application.Current.Windows.OfType<ScreenGrabView>().ToList();
71+
var numberOfScreenGrabWindowsToCreate = allScreens.Count() - allScreenGrab.Count;
72+
73+
for (var i = 0; i < numberOfScreenGrabWindowsToCreate; i++)
74+
{
75+
var view = new ScreenGrabView(bitmap =>
76+
{
77+
// 截图成功时保存结果并退出消息循环
78+
result = bitmap;
79+
frame.Continue = false;
80+
}, isAuxiliary)
81+
{
82+
OnGrabClose = () =>
83+
{
84+
IsCapturing = false;
85+
// 关闭时退出消息循环
86+
frame.Continue = false;
87+
}
88+
};
89+
allScreenGrab.Add(view);
90+
}
91+
92+
foreach (var (screen, screenGrab) in allScreens.Zip(allScreenGrab,
93+
(displayInfo, screenGrab) => (displayInfo, screenGrab)))
94+
{
95+
screenGrab.WindowStartupLocation = WindowStartupLocation.Manual;
96+
screenGrab.WindowState = WindowState.Normal;
97+
var screenWithScaledBounds = screen.ScaledBounds();
98+
99+
screenGrab.Width = screenWithScaledBounds.Width;
100+
screenGrab.Height = screenWithScaledBounds.Height;
101+
screenGrab.Left = screenWithScaledBounds.X;
102+
screenGrab.Top = screenWithScaledBounds.Y;
103+
104+
screenGrab.Show();
105+
screenGrab.Activate();
106+
}
107+
108+
// 阻塞等待用户完成截图或取消
109+
Dispatcher.PushFrame(frame);
110+
111+
return result;
112+
}
113+
114+
/// <summary>
115+
/// 异步方式捕获屏幕截图,类似 Dialog 的使用方式
116+
/// </summary>
117+
/// <param name="isAuxiliary">是否显示辅助线</param>
118+
/// <returns>返回捕获的 Bitmap,如果用户取消则返回 null</returns>
119+
public static Task<Bitmap?> CaptureAsync(bool isAuxiliary = false)
120+
{
121+
if (IsCapturing)
122+
return Task.FromResult<Bitmap?>(null);
123+
124+
_captureTaskCompletionSource = new TaskCompletionSource<Bitmap?>();
125+
126+
IsCapturing = true;
127+
128+
var allScreens = Screen.AllScreens;
129+
var allScreenGrab = Application.Current.Windows.OfType<ScreenGrabView>().ToList();
130+
var numberOfScreenGrabWindowsToCreate = allScreens.Count() - allScreenGrab.Count;
131+
132+
for (var i = 0; i < numberOfScreenGrabWindowsToCreate; i++)
133+
{
134+
var view = new ScreenGrabView(bitmap =>
135+
{
136+
// 截图成功时完成任务
137+
_captureTaskCompletionSource?.TrySetResult(bitmap);
138+
}, isAuxiliary)
139+
{
140+
OnGrabClose = () =>
141+
{
142+
IsCapturing = false;
143+
}
144+
};
145+
allScreenGrab.Add(view);
146+
}
147+
148+
foreach (var (screen, screenGrab) in allScreens.Zip(allScreenGrab,
149+
(displayInfo, screenGrab) => (displayInfo, screenGrab)))
150+
{
151+
screenGrab.WindowStartupLocation = WindowStartupLocation.Manual;
152+
screenGrab.WindowState = WindowState.Normal;
153+
var screenWithScaledBounds = screen.ScaledBounds();
154+
155+
screenGrab.Width = screenWithScaledBounds.Width;
156+
screenGrab.Height = screenWithScaledBounds.Height;
157+
screenGrab.Left = screenWithScaledBounds.X;
158+
screenGrab.Top = screenWithScaledBounds.Y;
159+
160+
screenGrab.Show();
161+
screenGrab.Activate();
162+
}
163+
164+
return _captureTaskCompletionSource.Task;
165+
}
50166
}

tests/ScreenGrab.Sample/MainWindow.xaml.cs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,49 @@ public MainWindow()
1515
InitializeComponent();
1616
}
1717

18-
private void Capture()
18+
private async void Capture()
1919
{
2020
Clean();
2121

22-
ScreenGrabber.OnCaptured = bitmap =>
23-
{
24-
Img.Source = bitmap.ToImageSource();
25-
if (WindowState != WindowState.Normal)
26-
WindowState = WindowState.Normal;
27-
if (!IsVisible)
28-
Show();
29-
Activate();
30-
};
31-
ScreenGrabber.Capture(AuxiliaryCb.IsChecked ?? false);
22+
// 1. 回调等待结果
23+
//ScreenGrabber.OnCaptured = bitmap =>
24+
//{
25+
// Img.Source = bitmap.ToImageSource();
26+
// if (WindowState != WindowState.Normal)
27+
// WindowState = WindowState.Normal;
28+
// if (!IsVisible)
29+
// Show();
30+
// Activate();
31+
//};
32+
//ScreenGrabber.Capture(AuxiliaryCb.IsChecked ?? false);
33+
34+
// 2. 同步获取结果(类似Dialog)
35+
//var bitmap = ScreenGrabber.CaptureDialog(AuxiliaryCb.IsChecked ?? false);
36+
37+
//// 如果用户取消截图,bitmap 将为 null
38+
//if (bitmap is null)
39+
// return;
40+
41+
//Img.Source = bitmap.ToImageSource();
42+
//if (WindowState != WindowState.Normal)
43+
// WindowState = WindowState.Normal;
44+
//if (!IsVisible)
45+
// Show();
46+
//Activate();
47+
48+
// 3. 异步获取结果
49+
var bitmap = await ScreenGrabber.CaptureAsync(AuxiliaryCb.IsChecked ?? false);
50+
51+
// 如果用户取消截图,bitmap 将为 null
52+
if (bitmap is null)
53+
return;
54+
55+
Img.Source = bitmap.ToImageSource();
56+
if (WindowState != WindowState.Normal)
57+
WindowState = WindowState.Normal;
58+
if (!IsVisible)
59+
Show();
60+
Activate();
3261
}
3362

3463
private void Capture(object? sender, HotkeyEventArgs e)

0 commit comments

Comments
 (0)