新浪微博客户端围脖七开发笔记(4) 实现SinaService接口

经过前面的准备,现在可以动手实现SinaService接口和界面布局啦!

SinaService的实现不难,用linq解析下xml就好了。AppKey,用户名,密码就要自己去申请啦。

代码
private void InitWebClient(ref WebClient wc)
{
wc
= new WebClient();
string usernamePassword = Settings.Username + ":" + Settings.Password;
wc.Credentials
= new NetworkCredential(Settings.Username, Settings.Password);
wc.Headers[
"Authorization"] = "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(usernamePassword));
}

/// <summary>
/// Gets the statuses.
/// </summary>
/// <param name="onGetStatusesCompleted">The on get Statuses completed.</param>
/// <param name="onError">The on error.</param>
public void GetStatuses(Int64 sinceId, Int64 maxId,
Action
<List<Status>> onGetStatusesCompleted = null, Action<Exception> onError = null, Action onFinally = null)
{
WebClient wcRefreshHome
= null;

InitWebClient(
ref wcRefreshHome);

//if (wcRefreshHome.IsBusy) wcRefreshHome.CancelAsync();

// register on download complete event
wcRefreshHome.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
{
try
{
// report error
if (e.Error != null)
{
if (onError != null)
{
onError(e.Error);
}
return;
}

XElement xmlResult
= XElement.Parse(e.Result);

List
<Status> list = new List<Status>();

ParseService.ParseTimeLine(xmlResult,
ref list);

// notify completed callback
if (onGetStatusesCompleted != null)
{
onGetStatusesCompleted(list);
}
}
catch(Exception ex)
{
Trace.DetailMsg(ex.Message);
if (onError != null)
{
onError(ex);
}
return;
}
finally
{
// notify finally callback
if (onFinally != null)
{
onFinally();
}
}
};

string requestUrl = Settings.RefreshHomeURL + "?source=" + Settings.AppKey;

//The list is empty, just get some status
if (sinceId == 0 && maxId == 0)
{
requestUrl
= requestUrl + "&count=" + Settings.NumberPerRequest;
}

//Get status later than sinceId
if (sinceId != 0 && maxId == 0)
{
requestUrl
= requestUrl + "&since_id=" + (sinceId+1) + "&count=" + Settings.NumberPerRequest;
}

//Get status early than maxId
if (sinceId == 0 && maxId != 0)
{
requestUrl
= requestUrl + "&max_id=" + (maxId-1) + "&count=" + Settings.NumberPerRequest;
}

wcRefreshHome.DownloadStringAsync(
new Uri(requestUrl), Settings.RefreshHomeURL);

}

}

相应的ParseService如下:

 

代码
public static class ParseService
{
public static void ParseTimeLine(XElement xElement, ref List<Status> statusList)
{
try
{
foreach (XElement status in xElement.Descendants("status"))
{
statusList.Add(ParseStatus(status));
}
}
catch (FormatException ex)
{
Deployment.Current.Dispatcher.BeginInvoke(()
=>
{
MessageBox.Show(ex.Message.ToString());
});
}
}

private static void ParseUserList(XElement xElement, ref List<User> userList )
{
try
{
foreach (XElement user in xElement.Descendants("user"))
{
User friend
= new User();

userList.Add(ParseUser(user));
}
}

catch (FormatException ex)
{
Deployment.Current.Dispatcher.BeginInvoke(()
=>
{
MessageBox.Show(ex.Message.ToString());
});
}
}

private static Status ParseStatus(XElement status)
{
Status newStatus
= new Status();
try
{
newStatus.Id
= long.Parse(status.Element("id").Value);
newStatus.Text
= status.Element("text").Value;

Regex regex
= new Regex(">.*<");
newStatus.Source
= status.Element("source").Value;
Match match
= regex.Match(newStatus.Source);
if (match.Success)
{
newStatus.Source
= match.ToString().Replace("<", string.Empty).Replace(">", string.Empty);
}

newStatus.CreatedAt
= DateTime.ParseExact(status.Element("created_at").Value,
"ddd MMM dd HH:mm:ss zzzz yyyy",
CultureInfo.CurrentCulture,
DateTimeStyles.AllowWhiteSpaces);

newStatus.Favorited
= bool.Parse(status.Element("favorited").Value);

//newTweet.Retweeted = bool.Parse(status.Element("retweeted").Value);

//newTweet.RetweetCount = int.Parse(status.Element("retweet_count").Value);

newStatus.User
= ParseUser(status.Element("user"));

//if (!status.Element("thumbnail_pic").IsEmpty)
//{
// newStatus.ThumbnailPic = status.Element("thumbnail_pic").Value;
//}

newStatus.ThumbnailPic
= status.Element("thumbnail_pic").Value;

}
catch (Exception ex)
{
Trace.DetailMsg(
"ParseStatus Error: " + ex.Message);
}

return newStatus;
}

private static User ParseUser(XElement User)
{
User user
= new User();
try
{
user.Id
= ulong.Parse(User.Element("id").Value);
user.ScreenName
= User.Element("screen_name").Value;
user.Name
= User.Element("name").Value;
user.ImageUrl
= User.Element("profile_image_url").Value;
user.Url
= User.Element("url").Value;
user.Followers
= int.Parse(User.Element("followers_count").Value);
user.Friends
= int.Parse(User.Element("friends_count").Value);
user.Description
= User.Element("description").Value;
user.Location
= User.Element("location").Value;
user.CreatedAt
= DateTime.ParseExact(User.Element("created_at").Value,
"ddd MMM dd HH:mm:ss zzzz yyyy",
CultureInfo.CurrentCulture,
DateTimeStyles.AllowWhiteSpaces);
}
catch (Exception ex)
{
Trace.DetailMsg(
"ParseUser Error: " + ex.Message);
}
return user;
}

}

主页面用到了Pivot Control

 

 

代码
<Grid x:Name="LayoutRoot" Background="Transparent">

<ProgressBar IsIndeterminate="{Binding IsHomeRefreshing}" VerticalAlignment="Top"
Visibility
="{Binding IsHomeRefreshing, Converter={StaticResource VisibilityConverter}}"/>

<!--Pivot Control-->
<controls:Pivot Title="围脖七">
<!--Pivot item one-->
<controls:PivotItem>
<controls:PivotItem.Header>
<ContentControl>
<StackPanel>
<TextBlock Text="主页" FontSize="54"/>
</StackPanel>
</ContentControl>
</controls:PivotItem.Header>
<ListBox d:LayoutOverrides="Height" Grid.Row="1" d:IsHidden="True"
ItemsSource
="{Binding HomeList, Mode=OneWay}" ItemTemplate="{StaticResource TweetItemTemplate}"
SelectionChanged
="ListBox_SelectionChanged"/>
</controls:PivotItem>

<!--Pivot item two-->
<controls:PivotItem>
<controls:PivotItem.Header>
<ContentControl>
<TextBlock Text="消息" FontSize="54" FontFamily="Segoe WP Light"/>
</ContentControl>
</controls:PivotItem.Header>
<Grid VerticalAlignment="Top">
<ListBox x:Name="TopicList" ItemsSource="{Binding TopicList, Mode=OneWay}"/>
</Grid>
</controls:PivotItem>
</controls:Pivot>
</Grid>

每条微博的DataTemplate如下

 

 

代码
<DataTemplate x:Name="TweetItemTemplate">
<Grid Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding User.ImageUrl}"
Height
="73" Width="73" VerticalAlignment="Top" Margin="0,5,7,0"
HorizontalAlignment
="Left"/>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<Grid Width="380">
<TextBlock Text="{Binding User.ScreenName}" VerticalAlignment="Center" Foreground="#FFC8AB14" FontSize="24"/>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center">
<Image Source="/Images/Tulips.png" Visibility="{Binding ThumbnailPic, Converter={StaticResource VisibilityConverter}}"/>
<TextBlock Text="{Binding CreatedAt, Converter={StaticResource TimeConverter}}"
FontSize
="20" Foreground="LightGray"
Margin
="5,0"/>
</StackPanel>
</Grid>
<!--TextBlock Text="{Binding Text}" FontSize="22" TextWrapping="Wrap"/-->
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" FontFamily="Arial"/>
</StackPanel>
</Grid>
</DataTemplate>

记得在MainPageViewModel的构造函数中调用RefreshHomeList

 

代码
if (!DesignerProperties.IsInDesignTool)
{
if (HomeList.Count == 0)
{
RefreshHomeList(
0, 0);
}
}

最后把viewmodel和view联系起来,在App.xaml中声明

 

 

代码
xmlns:viewModels="clr-namespace:WeiBo7.ViewModels"

<Application.Resources>
<misc:VisibilityConverter x:Key="VisibilityConverter"/>
<misc:TimeConverter x:Key="TimeConverter"/>
<viewModels:MainPageViewModel x:Key="MainPageViewModel" />

</Application.Resources>

在MainPage.xaml中声明就大功告成了!

 

 

DataContext="{StaticResource MainPageViewModel}"

 

因为间隔时间比较长,上面只是提到了些关键实现,有些地方可能忘记了。如有问题请留言给我!

 

 

posted @ 2010-12-10 17:48  上尉  阅读(1033)  评论(0编辑  收藏  举报
View Hao Wang's profile on LinkedIn