C#使用GetTextAsync时触发Invalid FORMATETC structure异常排查
问题分析与解决方案
核心异常原因:剪贴板API混用 + 线程违规
你遇到的Invalid FORMATETC structure occurred异常,本质是同时混用了UWP剪贴板API(Windows.ApplicationModel.DataTransfer.Clipboard)和WinForms剪贴板API(System.Windows.Forms.Clipboard),再加上异步事件回调里直接操作剪贴板未遵循UI线程调用要求,导致剪贴板格式冲突。
分步修复方案
1. 统一剪贴板操作API
WPF程序直接使用原生的System.Windows.Clipboard,彻底摒弃UWP或WinForms的剪贴板类,避免跨框架格式冲突。
2. 修正异步线程问题
剪贴板操作必须在UI线程执行,异步回调里通过Dispatcher切换到UI线程;同时替换阻塞UI的Thread.Sleep(500)为非阻塞的await Task.Delay(500),防止界面卡死。
3. 资源文件读取优化(两种方式可选)
- StringReader方式:只要资源是正确嵌入的文本格式,原写法本身没问题,无需替换;
- StreamReader方式:若要改用流读取,通过资源管理器获取嵌入资源的流即可。
修复后的完整代码
public partial class MainWindow : System.Windows.Window { string line; string currentClipboardContent; string expectedClipboardContent; string vocabularygerman = Properties.Resources.vocabularygerman; string vocabularyfrench = Properties.Resources.vocabularyfrench; int lineNumber; public MainWindow() { InitializeComponent(); // 采用WPF原生剪贴板监听事件,更贴合框架线程模型 System.Windows.Clipboard.AddPasteHandler(this, ClipboardChangedHandler); } private async void ClipboardChangedHandler(object sender, DataObjectPastingEventArgs e) { if (e.DataObject.GetDataPresent(DataFormats.Text)) { currentClipboardContent = e.DataObject.GetData(DataFormats.Text) as string; if (expectedClipboardContent != currentClipboardContent) { await Task.Delay(500); // 非阻塞等待,避免重复触发 // StringReader读取资源文本(原逻辑保留,修正剪贴板操作) using (var reader = new StringReader(vocabularygerman)) { lineNumber = 0; while ((line = reader.ReadLine()) != null) { lineNumber++; if (line.Contains(currentClipboardContent)) { // 切换到UI线程设置剪贴板,替换为目标行文本 await Dispatcher.InvokeAsync(() => { System.Windows.Clipboard.SetText(line); }); break; } } } // 更新预期内容,防止循环触发事件 expectedClipboardContent = System.Windows.Clipboard.GetText(); } } } // 若需改用StreamReader读取嵌入资源,可使用此方法 private void ReadResourceViaStreamReader() { using (var stream = Properties.Resources.ResourceManager.GetStream("vocabularygerman")) { if (stream != null) { using (var reader = new StreamReader(stream)) { string fullContent = reader.ReadToEnd(); // 按需求处理文本内容 } } } } }
额外注意事项
- 原代码中
SetDataObject(lineNumber)是设置行号,不符合你“替换为单词所在行”的需求,已修正为SetText(line); - 确保资源文件
vocabularygerman.txt的生成操作设置为“嵌入的资源”,否则无法通过Properties.Resources正常访问; expectedClipboardContent的判断逻辑必须保留,避免设置剪贴板后再次触发事件形成循环。
内容的提问来源于stack exchange,提问作者Biswind
相关产品推荐
相关产品推荐

