Поскольку 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/…