简体   繁体   English

如何在带有 FileSystemWatcher 的 MAUI 中使用 Clipboard.Default.SetTextAsync

[英]How to use Clipboard.Default.SetTextAsync in MAUI with FileSystemWatcher

I have followed https://learn.microsoft.com/en-us/do.net/maui/platform-integration/data/clipboard?view.net-maui-7.0 in my project, and I understand that:我在我的项目中关注了 https://learn.microsoft.com/en-us/do.net/maui/platform-integration/data/clipboard?view.net-maui-7.0 ,我了解到:

Access to the clipboard must be done on the main user interface thread.必须在主用户界面线程上访问剪贴板。 For more information on how to invoke methods on the main user interface thread, see MainThread.有关如何在主用户界面线程上调用方法的更多信息,请参阅 MainThread。

I cannot do Clipboard.Default.SetTextAsync(url) without errors, and I can't understand where I've done wrong.我不能在没有错误的情况下执行Clipboard.Default.SetTextAsync(url) ,而且我不明白我哪里做错了。

  • The URL is generated through the OnCreated() method of FileSystemWatcher. URL是通过FileSystemWatcher的OnCreated()方法生成的。
  • I understand this is not the UI thread, but I fire an event which I believe should enable UI thread operations我知道这不是 UI 线程,但我触发了一个我认为应该启用 UI 线程操作的事件

I would like to get this code below fixed so that I can my app in macOS without any issues.我想修复下面的代码,以便我可以在 macOS 中毫无问题地使用我的应用程序。

You can also check the code in GitHub by pulling the following two projects:也可以通过拉取以下两个项目查看GitHub中的代码:

My code is as below.我的代码如下。

using HelpersLib;
using Microsoft.Extensions.Logging;
using ShareX.HelpersLib;
using ShareX.UploadersLib;

namespace UploaderX;

public partial class MainPage : ContentPage
{
    int count = 0;
    private FileSystemWatcher _watcher;

    private string _watchDir;
    private string _destDir;

    public delegate void UrlReceivedEventHandler(string url);
    public event UrlReceivedEventHandler UrlReceived;

    public MainPage()
    {
        InitializeComponent();

        string AppDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "UploaderX");
        string AppSettingsDir = Path.Combine(AppDir, "Settings");
        App.Settings = ApplicationConfig.Load(Path.Combine(AppSettingsDir, "ApplicationConfig.json"));
        App.UploadersConfig = UploadersConfig.Load(Path.Combine(AppSettingsDir, "UploadersConfig.json"));
        App.UploadersConfig.SupportDPAPIEncryption = false;

        DebugHelper.Init(Path.Combine(AppDir, $"UploaderX-{DateTime.Now.ToString("yyyyMMdd")}-Log.txt"));

        _watchDir = Directory.Exists(App.Settings.CustomScreenshotsPath2) ? App.Settings.CustomScreenshotsPath2 : Path.Combine(AppDir, "Watch Folder");
        Helpers.CreateDirectoryFromDirectoryPath(_watchDir);

        _destDir = _watchDir;

        DebugHelper.Logger.WriteLine("Watch Dir: " + _watchDir);
        DebugHelper.Logger.WriteLine("Destination Dir: " + _destDir);

        _watcher = new FileSystemWatcher();
        _watcher.Path = _watchDir;

        _watcher.NotifyFilter = NotifyFilters.FileName;
        _watcher.Created += OnCreated;
        _watcher.EnableRaisingEvents = true;

        this.UrlReceived += MainPage_UrlReceived;

    }

    private async void MainPage_UrlReceived(string url)
    {
        await Clipboard.Default.SetTextAsync(url);
    }

    private void OnUrlReceived(string url)
    {
        UrlReceived?.Invoke(url);
    }

    private async void OnCounterClicked(object sender, EventArgs e)
    {
        count++;

        if (count == 1)
            CounterBtn.Text = $"Clicked {count} time";
        else
            CounterBtn.Text = $"Clicked {count} times";

        await Clipboard.Default.SetTextAsync(CounterBtn.Text);
    }

    async void OnCreated(object sender, FileSystemEventArgs e)
    {
        try
        {
            string fileName = new NameParser(NameParserType.FileName).Parse("%y%mo%d_%ra{10}") + Path.GetExtension(e.FullPath);
            string destPath = Path.Combine(Path.Combine(Path.Combine(_destDir, DateTime.Now.ToString("yyyy")), DateTime.Now.ToString("yyyy-MM")), fileName);
            FileHelpers.CreateDirectoryFromFilePath(destPath);
            if (!Path.GetFileName(e.FullPath).StartsWith("."))
            {
                int successCount = 0;
                long previousSize = -1;

                await Helpers.WaitWhileAsync(() =>
                {
                    if (!FileHelpers.IsFileLocked(e.FullPath))
                    {
                        long currentSize = FileHelpers.GetFileSize(e.FullPath);

                        if (currentSize > 0 && currentSize == previousSize)
                        {
                            successCount++;
                        }

                        previousSize = currentSize;
                        return successCount < 4;
                    }

                    previousSize = -1;
                    return true;
                }, 250, 5000, () =>
                {
                    File.Move(e.FullPath, destPath, overwrite: true);
                }, 1000);

                WorkerTask task = new WorkerTask(destPath);
                UploadResult result = task.UploadFile();
                DebugHelper.Logger.WriteLine(result.URL);
                OnUrlReceived(result.URL);
            }
        }
        catch (Exception ex)
        {
            DebugHelper.Logger.WriteLine(ex.Message);
        }

    }
}

Error once URL is generated:生成一次URL报错:

在此处输入图像描述

You can wrap your call to SetTextAsync() with MainThread.BeginInvokeOnMainThread() like so to make sure it's invoked correctly:您可以像这样使用MainThread.BeginInvokeOnMainThread()包装对SetTextAsync()的调用,以确保它被正确调用:

private void MainPage_UrlReceived(string url)
{
    MainThread.BeginInvokeOnMainThread(() => 
    {
        Clipboard.Default.SetTextAsync(url);
    });
}

There is no need to await the call to SetTextAsync() , either, because you're calling it as a singular operation from within an event handler, which isn't awaitable.也不需要awaitSetTextAsync()的调用,因为您是在事件处理程序中将其作为单一操作调用,这是不可等待的。

I understand this is not the UI thread, but I fire an event which I believe should enable UI thread operations我知道这不是 UI 线程,但我触发了一个我认为应该启用 UI 线程操作的事件

Generally, there is no guarantee that event handlers of UI classes are called on the Main Thread.通常,不能保证在主线程上调用 UI 类的事件处理程序。

You can find more information on when and how to invoke methods on the Main Thread in the official documentation: https://learn.microsoft.com/en-us/do.net/maui/platform-integration/appmodel/main-thread?view.net-maui-7.0您可以在官方文档中找到有关何时以及如何在主线程上调用方法的更多信息: https:https://learn.microsoft.com/en-us/do.net/maui/platform-integration/appmodel/main-thread ?view.net-maui-7.0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM