Caliburn.Micro EventAggregator.PublishOnUIThreadAsync "The tasks argument included a null value. Parameter name: tasks"
Caliburn.Micro EventAggregator.PublishOnUIThreadAsync "The tasks argument included a null value. Parameter name: tasks"
我正在尝试使用 EventAggregators 进行跨 VM 通信。
在我的 ChildViewModel 中,我做了类似的事情:
public async void ThisMethodIsCalledByUI()
{
// ShowMessageEvent is a simple class with with only 1 string property and a MessageDialogResult enum
ShowMessageEvent msg = new ShowMessageEvent("This is the message from ChildVM");
// doing this works, but MessageDialogResult will be false below since no await happens
//_eventAggregator.PublishOnUIThreadAsync(msg);
// doing this triggers exception
// however msg.DialogResult is already Affirmative by the time
// the exception is thrown, so it's almost as intended here
await _eventAggregator.PublishOnUIThreadAsync(msg);
// expected: Affirmative
Debug.WriteLine(msg.DialogResult);
}
但是我需要等待,因为我想使用 MessageDialogResult。
在 MainViewModel 中:
public class MainViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
private readonly IEventAggregator _eventAggregator;
public MainViewModel()
{
_eventAggregator = new EventAggregator();
_events.SubscribeOnPublishedThread(this);
}
public async Task HandleAsync(object message, CancellationToken cancellationToken)
{
if (message is ShowMessageEvent msg)
{
// Simulating work, show dialog, etc.
await Task.Delay(500);
// Implementation irrelevant, assume the dialog returns Affirmative
msg.DialogResult = await _dialogs.ShowMessageAsync(msg.Message);
}
}
}
所以目标是通知 MainViewModel 显示一个对话框,然后在继续之前等待并在 ChildViewModel 中检索对话框结果。是的,作为解决方法,我可以直接从 ChildViewModel 调用对话框,但这不是重点,我想避免这种情况。
我的实现基本上已经按预期完成了所有事情,我唯一需要解决的是抛出的异常。
有人知道我做错了什么吗?
编辑
我实际上可以让它像这样工作:
public async void ThisMethodIsCalledByUI()
{
// ShowMessageEvent is a simple class with with only 1 string property and a MessageDialogResult enum
ShowMessageEvent msg = new ShowMessageEvent("This is the message from ChildVM");
try
{
await _eventAggregator.PublishOnUIThreadAsync(msg);
}
// suppress the problematic exception
catch (ArgumentException e)
{
Console.WriteLine(e);
}
// works as expected: Affirmative
Debug.WriteLine(msg.DialogResult);
}
虽然这是可行的,但我更喜欢不需要抑制异常的设计...
现在我完成了自己的扩展实现:
/// <summary>
/// EventAggregatorExtensions
/// </summary>
public static class EventAggregatorExtensions
{
/// <summary>
/// Publishes a message to the UI thread
/// </summary>
/// <param name="eventAggregator"></param>
/// <param name="message"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task PublishOnUIThreadAsyncCustom(this IEventAggregator eventAggregator, object message,
CancellationToken cancellationToken)
{
try
{
await eventAggregator.PublishOnUIThreadAsync(message, cancellationToken);
}
// Suppress a specific exception that is always caused when above line is awaited
catch (ArgumentException e)
{
if (!e.Message.Contains("The tasks argument included a null value.") | !e.ParamName.Equals("tasks"))
{
throw;
}
}
}
/// <summary>
/// Publishes a message to the UI thread
/// </summary>
/// <param name="eventAggregator"></param>
/// <param name="message"></param>
/// <returns></returns>
public static async Task PublishOnUIThreadAsyncCustom(this IEventAggregator eventAggregator, object message)
{
await PublishOnUIThreadAsyncCustom(eventAggregator, message, CancellationToken.None);
}
}
我正在尝试使用 EventAggregators 进行跨 VM 通信。
在我的 ChildViewModel 中,我做了类似的事情:
public async void ThisMethodIsCalledByUI()
{
// ShowMessageEvent is a simple class with with only 1 string property and a MessageDialogResult enum
ShowMessageEvent msg = new ShowMessageEvent("This is the message from ChildVM");
// doing this works, but MessageDialogResult will be false below since no await happens
//_eventAggregator.PublishOnUIThreadAsync(msg);
// doing this triggers exception
// however msg.DialogResult is already Affirmative by the time
// the exception is thrown, so it's almost as intended here
await _eventAggregator.PublishOnUIThreadAsync(msg);
// expected: Affirmative
Debug.WriteLine(msg.DialogResult);
}
但是我需要等待,因为我想使用 MessageDialogResult。 在 MainViewModel 中:
public class MainViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
private readonly IEventAggregator _eventAggregator;
public MainViewModel()
{
_eventAggregator = new EventAggregator();
_events.SubscribeOnPublishedThread(this);
}
public async Task HandleAsync(object message, CancellationToken cancellationToken)
{
if (message is ShowMessageEvent msg)
{
// Simulating work, show dialog, etc.
await Task.Delay(500);
// Implementation irrelevant, assume the dialog returns Affirmative
msg.DialogResult = await _dialogs.ShowMessageAsync(msg.Message);
}
}
}
所以目标是通知 MainViewModel 显示一个对话框,然后在继续之前等待并在 ChildViewModel 中检索对话框结果。是的,作为解决方法,我可以直接从 ChildViewModel 调用对话框,但这不是重点,我想避免这种情况。
我的实现基本上已经按预期完成了所有事情,我唯一需要解决的是抛出的异常。
有人知道我做错了什么吗?
编辑
我实际上可以让它像这样工作:
public async void ThisMethodIsCalledByUI()
{
// ShowMessageEvent is a simple class with with only 1 string property and a MessageDialogResult enum
ShowMessageEvent msg = new ShowMessageEvent("This is the message from ChildVM");
try
{
await _eventAggregator.PublishOnUIThreadAsync(msg);
}
// suppress the problematic exception
catch (ArgumentException e)
{
Console.WriteLine(e);
}
// works as expected: Affirmative
Debug.WriteLine(msg.DialogResult);
}
虽然这是可行的,但我更喜欢不需要抑制异常的设计...
现在我完成了自己的扩展实现:
/// <summary>
/// EventAggregatorExtensions
/// </summary>
public static class EventAggregatorExtensions
{
/// <summary>
/// Publishes a message to the UI thread
/// </summary>
/// <param name="eventAggregator"></param>
/// <param name="message"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task PublishOnUIThreadAsyncCustom(this IEventAggregator eventAggregator, object message,
CancellationToken cancellationToken)
{
try
{
await eventAggregator.PublishOnUIThreadAsync(message, cancellationToken);
}
// Suppress a specific exception that is always caused when above line is awaited
catch (ArgumentException e)
{
if (!e.Message.Contains("The tasks argument included a null value.") | !e.ParamName.Equals("tasks"))
{
throw;
}
}
}
/// <summary>
/// Publishes a message to the UI thread
/// </summary>
/// <param name="eventAggregator"></param>
/// <param name="message"></param>
/// <returns></returns>
public static async Task PublishOnUIThreadAsyncCustom(this IEventAggregator eventAggregator, object message)
{
await PublishOnUIThreadAsyncCustom(eventAggregator, message, CancellationToken.None);
}
}