我需要从ViewModel显示MessageDialog,我需要将Action与按下的按钮相关联。为此我写了以下内容:
//Dummy implementation
private string Translate(string element) => element;
public async Task ShowAsync(string message, Dictionary<string, Action> commands)
{
var translatedCommands = new Dictionary<string, Action>();
foreach (var element in commands)
translatedCommands.Add(Translate(element.Key), element.Value);
string selectedElement = null;
var buttons = new string[translatedCommands.Keys.Count];
translatedCommands.Keys.CopyTo(buttons, 0);
Task<string> Result = null;
Device.BeginInvokeOnMainThread(() =>
{
Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
});
selectedElement = await Result;
if (selectedElement == null)
return;
translatedCommands[selectedElement]?.Invoke();
}
然后我从RelayCommand
调用它 private async void ExecuteButtonCommand(object p)
{
int Selectedindex = 0;
var messageCommands = new Dictionary<string, Action>()
{
{ "Before 2003", () =>
{
Selectedindex = 1;
}
},
{ "After 2003", () =>
{
Selectedindex = 2;
}
},
};
await ShowAsync("Select period", messageCommands);
var dummy = Selectedindex;
}
在Android上运行良好,但在Windows DisplayActionSheet
上立即返回null。我见过this so question,但它对我不起作用,因为如果我在Device.BeginInvokeOnMainThread
内等待,ShowAsync就不会变得等待。
答案 0 :(得分:1)
我的猜测是,在Android上,Action
中的BeginInvokeOnMainThread
会立即执行,而Result
会分配一个值。在Windows上,Action
方法可能在调用BeginInvokeOnMainThread
方法后立即执行。
你真的不应该在另一个线程上做一个依赖于结果的动作,正如你在这里做的那样。相反,您应该等待Result
被分配或在主要主题上执行ShowAsync
的后半部分。
我建议使用第二个选项,因为除了在主线程中分配Result
后使用Device.BeginInvokeOnMainThread(() =>
{
string selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
if (selectedElement == null)
return;
translatedCommands[selectedElement]?.Invoke();
});
之外,您还没有做任何其他事情:
ShowAsync
然而,这不会使ShowAsync
异步。要创建此方法的异步版本,只需将编辑后的Show
内容提取到同步private void Show(string message, Dictionary<string, Action> commands)
{
// Code in ShowAsync is moved here
}
public Task ShowAsync(string message, Dictionary<string, Action> commands)
{
return Task.Run(() => Show(message, commands));
}
方法中,然后创建一个异步包装器:
{{1}}
答案 1 :(得分:0)
如果找到解决方案。
在Windows(电话)上DisplayActionSheet
不应该在MainThread中执行,而是等待。
public async Task ShowAsync(string message, Dictionary<string, Action> commands)
{
var translatedCommands = new Dictionary<string, Action>();
foreach (var element in commands)
translatedCommands.Add(Translate(element.Key), element.Value);
var buttons = new string[translatedCommands.Keys.Count];
translatedCommands.Keys.CopyTo(buttons, 0);
string selectedElement = null;
if (Device.OS == TargetPlatform.Android)
{
Task<string> Result = null;
Device.BeginInvokeOnMainThread(() =>
{
Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
});
selectedElement = await Result;
}
else if (Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone)
{
selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
}
else
throw new NotImplementedException("Only implemented for Android and Windows (Phone)");
if (selectedElement == null)
return;
translatedCommands[selectedElement]?.Invoke();
}