Поскольку CoreDispatcher устарел в WinUI 3 Windows App SDK и заменен DispatcherQueue, как можно преобразовать следующий код для правильного использования DispatcherQueue?
fileInputNode.FileCompleted += FileInputNodeOnFileCompleted;
private async void FileInputNodeOnFileCompleted(AudioFileInputNode sender, object args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
sender.Stop();
sender.Reset();
});
}
Другая причина обновить код для использования DispatcherQueue заключается в том, что при использовании CoreDispatcher в коде возникает следующая ошибка:
В экземпляре объекта не задана ссылка на объект.
РЕДАКТИРОВАТЬ
По запросу YangXiaoPo-MSFT вот воспроизводимый образец тестового приложения, содержащего рассматриваемую проблему.
Ниже приведен относящийся к нему XAML:
<Window
x:Class = "Test_3_Take_2.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "using:Test_3_Take_2"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable = "d">
<StackPanel Orientation = "Vertical" HorizontalAlignment = "Center" VerticalAlignment = "Center">
<Button x:Name = "recordStopButton" Content = "Record" Click = "recordStopButton_Click"/>
<Button x:Name = "playButton" Content = "Play Recorded File" Margin = "0,50,0,0" IsEnabled = "False" Click = "playButton_Click"/>
</StackPanel>
</Window>
И следующий код:
using Microsoft.UI.Xaml;
using System;
using System.Threading.Tasks;
using Windows.Media.Audio;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.Media.Transcoding;
using Windows.Media.Capture;
using Windows.Media.Render;
using Microsoft.UI.Dispatching;
namespace Test_3_Take_2
{
public sealed partial class MainWindow : Window
{
private AudioGraph graph, graph2;
private AudioFileInputNode fileInputNode;
private AudioFileOutputNode fileOutputNode;
private AudioDeviceOutputNode deviceOutputNode, deviceOutputNode2;
private AudioDeviceInputNode deviceInputNode;
private StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder;
private StorageFile file;
public MainWindow()
{
this.InitializeComponent();
this.Title = "Test 3 Take 2";
var root = this.Content as FrameworkElement;
if (root != null)
root.Loaded += async (s, e) => await CreateAudioGraph();
var root2 = this.Content as FrameworkElement;
if (root2 != null)
root2.Loaded += async (s, e) => await CreateAudioGraph2();
}
private void playButton_Click(object sender, RoutedEventArgs e)
{
if (file != null)
{
TogglePlay();
}
}
private async void TogglePlay()
{
//Toggle playback
if (playButton.Content.Equals("Play Recorded File"))
{
if (fileInputNode != null) {
fileInputNode.Dispose();
}
CreateAudioFileInputNodeResult fileInputResult = await graph2.CreateFileInputNodeAsync(file);
if (AudioFileNodeCreationStatus.Success != fileInputResult.Status)
{
// Cannot read input file
return;
}
fileInputNode = fileInputResult.FileInputNode;
fileInputNode.AddOutgoingConnection(deviceOutputNode2);
fileInputNode.StartTime = TimeSpan.FromSeconds(0);
graph2.Start();
playButton.Content = "Stop Playing Recorded File";
fileInputNode.FileCompleted += FileInputNodeOnFileCompleted;
if (fileInputNode.Position == TimeSpan.FromSeconds(0))
{
graph2.Stop();
playButton.Content = "Play Recorded File";
}
}
else
{
graph2.Stop();
playButton.Content = "Play Recorded File";
}
}
private async void FileInputNodeOnFileCompleted(AudioFileInputNode sender, object args) {
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
sender.Stop();
sender.Reset();
}); }
private async void recordStopButton_Click(object sender, RoutedEventArgs e)
{
await ToggleRecordStop();
}
private async Task ToggleRecordStop()
{
if (recordStopButton.Content.Equals("Record"))
{
playButton.Content = "Play Recorded File";
playButton.IsEnabled = false;
if (deviceInputNode != null)
{
deviceInputNode.Dispose();
CreateAudioDeviceInputNodeResult deviceInputNodeResult = await graph.CreateDeviceInputNodeAsync(MediaCategory.Other);
if (deviceInputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device input node
return;
}
deviceInputNode = deviceInputNodeResult.DeviceInputNode;
}
file = await temporaryFolder.CreateFileAsync("file1.mp3",
CreationCollisionOption.ReplaceExisting);
// File can be null if cancel is hit in the file picker
if (file == null)
{
return;
}
MediaEncodingProfile fileProfile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
// Operate node at the graph format, but save file at the specified format
CreateAudioFileOutputNodeResult fileOutputNodeResult = await graph.CreateFileOutputNodeAsync(file, fileProfile);
if (fileOutputNodeResult.Status != AudioFileNodeCreationStatus.Success)
{
// FileOutputNode creation failed
return;
}
fileOutputNode = fileOutputNodeResult.FileOutputNode;
// Connect the input node to both output nodes
deviceInputNode.AddOutgoingConnection(fileOutputNode);
deviceInputNode.AddOutgoingConnection(deviceOutputNode);
graph.Start();
recordStopButton.Content = "Stop";
}
else if (recordStopButton.Content.Equals("Stop"))
{
// Good idea to stop the graph to avoid data loss
graph.Stop();
TranscodeFailureReason finalizeResult = await fileOutputNode.FinalizeAsync();
if (finalizeResult != TranscodeFailureReason.None)
{
// Finalization of file failed. Check result code to see why
return;
}
recordStopButton.Content = "Record";
playButton.IsEnabled = true;
}
}
private async Task CreateAudioGraph()
{
AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
if (result.Status != AudioGraphCreationStatus.Success)
{
// Cannot create graph
return;
}
graph = result.Graph;
// Create a device output node
CreateAudioDeviceOutputNodeResult deviceOutputNodeResult = await graph.CreateDeviceOutputNodeAsync();
if (deviceOutputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device output node
return;
}
deviceOutputNode = deviceOutputNodeResult.DeviceOutputNode;
// Create a device input node using the default audio input device
CreateAudioDeviceInputNodeResult deviceInputNodeResult = await graph.CreateDeviceInputNodeAsync(MediaCategory.Other);
if (deviceInputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device input node
return;
}
deviceInputNode = deviceInputNodeResult.DeviceInputNode;
}
private async Task CreateAudioGraph2()
{
// Create an AudioGraph with default settings
AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
if (result.Status != AudioGraphCreationStatus.Success)
{
// Cannot create graph
return;
}
graph2 = result.Graph;
// Create a device output node
CreateAudioDeviceOutputNodeResult deviceOutputNodeResult = await graph2.CreateDeviceOutputNodeAsync();
if (deviceOutputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
return;
}
deviceOutputNode2 = deviceOutputNodeResult.DeviceOutputNode;
}
}
}
@SimonMourier Если это поможет достичь конечной цели, как это можно реализовать, чтобы приведенный выше код работал?
Вы видели Изменение CoreDispatcher.RunAsync на DispatcherQueue.TryEnqueue?
@YangXiaoPo-MSFT Да, но как это можно адаптировать к этому варианту использования?
Не могли бы вы показать минимальный воспроизводимый образец без личной информации?
@YangXiaoPo-MSFT В основной пост добавлен минимальный воспроизводимый образец без личной информации.
Ничего сложного.
private void FileInputNodeOnFileCompleted(AudioFileInputNode sender, object args)
{
DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>
{
sender.Stop();
sender.Reset();
});
}
К сожалению, этот код выдает следующую ошибку: «Ссылка на объект не установлена на экземпляр объекта».
Кажется, вы ссылаетесь на объект null
. Можете ли вы проверить, какой из них?
Все проверяется, включая часть кода отправителя, на которую ссылается ненулевой объект AudioFileInputNode.
Неудивительно. Меня устраивает.
Обновить код:
bool isQueued = this.DispatcherQueue.TryEnqueue(() =>
{
sender.Stop();
sender.Reset();
});
Можете ли вы поделиться кодом в том формате, в котором я поделился кодом в исходном сообщении, вместе со снимком экрана, для всеобщего блага? Спасибо.
@GiovanniBriones обновлено. Это почти то же самое, что Измените CoreDispatcher.RunAsync на DispatcherQueue.TryEnqueue.
@YamgXiaoPo-MSFT Фантастика! Это работает! Спасибо вам большое от всего сердца! Я действительно ценю это! Еще раз спасибо!
Вы ищете DispatcherQueue.TryEnqueue? Learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/…