我有一个问题,我在LINQ语句中调用Task<>
方法并尝试从Task<>
方法返回数据(图像)。我无法使用Task<>
方法返回数据(图片),我收到以下错误:
无法隐式转换类型System.Threading.Tasks.Task&#39; 到&#39; System.Uri&#39;。
这是带有LINQ语句的DownloadStringCompleted方法,其中我调用了GetTest Task&lt;&gt;方法:
private async void GetGamesListRequestCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
var feedXml = XDocument.Parse(e.Result);
var gameData = feedXml.Root.Descendants("Game").Select(x => new GetGamesList
{
ID = (int)x.Element("id"),
GameTitle = (string)x.Element("GameTitle"),
ReleaseDate = (string)x.Element("ReleaseDate"),
Platform = (string)x.Element("Platform"),
Front = GetTest((int)x.Element("id")), // THE METHOD WITH PROBLEM.
})
.ToList();
foreach (var item in gameData)
{
GetGamesListItems.Add(item);
}
}
}
任务&lt;&gt;尝试返回数据(图像)时遇到问题的GetTest方法:
public Task<string> GetTest(int id)
{
var tcs = new TaskCompletionSource<string>();
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
var feedXml = XDocument.Parse(e.Result);
var gameData = feedXml.Root.Descendants("Images").Select(x => new GetArt
{
BoxArtFrontThumb = new Uri(GetBoxArtFront(x)),
})
.ToList();
foreach (var item in gameData) GetArtItems.Add(item);
foreach (var i in GetArtItems)
{
tcs.SetResult("http://thegamesdb.net/banners/" + i.BoxArtFrontThumb.ToString());
}
}
else
{
tcs.SetException(e.Error);
}
};
client.DownloadStringAsync(new Uri("http://thegamesdb.net/api/GetArt.php?id=" + id.ToString()));
return tcs.Task;
}
我存储图像的ObservableCollection: private ObservableCollection _GetArtItems = new ObservableCollection();
public ObservableCollection<GetArt> GetArtItems
{
get
{
return this._GetArtItems;
}
}
我从XML获取图像:
private static string GetBoxArtFront(XElement gameNode)
{
return "http://thegamesdb.net/banners/" + (string)gameNode.Descendants("boxart")
.FirstOrDefault(b => (string)b.Attribute("side") == "front");
}
这是我用来存储数据(图像)的类:
public class GetArt
{
public Uri BoxArtFrontThumb { get; set; }
}
这是我的LongListSelector我想在下面显示数据(图像):
<phone:LongListSelector Name="llsGameList" Background="#242424" ItemsSource="{Binding}" Tap="llsGameList_Tap" Margin="0,90,0,0">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu Name="ContextMenu">
<toolkit:MenuItem
Name="addToFavorite"
Header="Add to favorite"
Click="addToFavorite_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel>
<Border Background="{StaticResource PhoneAccentBrush}"
Padding="{StaticResource PhoneTouchTargetOverhang}"
Margin="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Name="tblGameTitle" Style="{StaticResource PhoneTextGroupHeaderStyle}" ManipulationStarted="tblGameTitle_ManipulationStarted" ManipulationCompleted="tblGameTitle_ManipulationCompleted">
<Run Text="{Binding GameTitle}"></Run>
</TextBlock>
</Border>
<Image Source="{Binding Front}" Height="200" Width="200"></Image> // HERE IM BINDING TO MY FRONT PROPERTY TO SHOW THE IMAGES
<TextBlock TextWrapping="Wrap" Foreground="YellowGreen" Style="{StaticResource PhoneTextNormalStyle}" Padding="{StaticResource PhoneTouchTargetOverhang}"
FontSize="{StaticResource PhoneFontSizeNormal}">
<Run Text="Platform: "></Run>
<Run Text="{Binding Platform}"></Run>
</TextBlock>
<TextBlock Foreground="YellowGreen" Style="{StaticResource PhoneTextNormalStyle}" Padding="{StaticResource PhoneTouchTargetOverhang}"
FontSize="{StaticResource PhoneFontSizeNormal}">
<Run Text="Release Date: "></Run>
<Run Text="{Binding ReleaseDate}"></Run>
</TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
这是我的DataContext,它获取gd.GetGamesListItems,其中包含我想在LongListSelector中显示的图像:
public MainPage()
{
InitializeComponent();
llsGameList.DataContext = gd.GetGamesListItems;
}
我希望有人可以帮助我:)。感谢。
答案 0 :(得分:3)
每当你有Task<T>
时,你需要花一点时间思考你想要(异步)等待结果的方式。请注意,Task<T>
代表 future 结果,而非当前结果。
根据@Sriram的答案,有一个选项,它将(异步)一次一个地等待结果,并在它们到达时将它们添加到列表中。另一种选择是做这样的事情:
var feedXml = XDocument.Parse(e.Result);
var gameDataTasks = feedXml.Root.Descendants("Game").Select(
async x => new GetGamesList
{
ID = (int)x.Element("id"),
GameTitle = (string)x.Element("GameTitle"),
ReleaseDate = (string)x.Element("ReleaseDate"),
Platform = (string)x.Element("Platform"),
Front = new Uri(await GetTestAsync((int)x.Element("id"))),
}).ToList();
var gameData = await Task.WhenAll(gameDataTasks);
foreach (var item in gameData)
{
GetGamesListItems.Add(item);
}
这将启动所有元素的所有GetTestAsync
调用,然后(异步)等待它们全部完成(并检索结果)。
其他说明:
GetTestAsync
以符合Task-based Asynchronous Pattern。HttpClient
,我会发现代码更清晰,await
内置了对HttpClient
的支持。以下是使用public async Task<string> GetTestAsync(int id)
{
var client = new HttpClient();
var result = await client.GetStringAsync("http://thegamesdb.net/api/GetArt.php?id=" + id);
var feedXml = XDocument.Parse(result);
var gameData = feedXml.Root.Descendants("Images").Select(x => new GetArt
{
BoxArtFrontThumb = new Uri(GetBoxArtFront(x)),
}).ToList();
foreach (var item in gameData) GetArtItems.Add(item);
return "http://thegamesdb.net/banners/" + gameData.Single().BoxArtFrontThumb.ToString()
}
:
{{1}}
答案 1 :(得分:1)
要解决此问题,您可以调用Task.Result
但是方法将同步执行,等待异步操作。
您必须将调用方法也标记为异步并等待GetTest
异步。
var feedXml = XDocument.Parse(e.Result);
List<GetGamesList> gameData = new List<GetGamesList>();
foreach (var item in feedXml.Root.Descendants("Game"))
{
var gl = new GetGamesList();
gl.ID = (int)x.Element("id");
gl.GameTitle = (string)x.Element("GameTitle");
gl.ReleaseDate = (string)x.Element("ReleaseDate");
gl.Platform = (string)x.Element("Platform");
gl.Front = new Uri(await GetTest((int)x.Element("id")));//Note the await keyword
gameData.Add(gl);
}
foreach (var item in gameData)
{
GetGamesListItems.Add(item);
}
答案 2 :(得分:0)
我不确定我认为调用这样的任务是个好主意但是......问题是你没有从任务中得到结果。
您需要:
Front = GetTest().Result
或
Front = await GetTest()