很久没有写博客了,今天我给大家介绍一个我自己写的一个WP7开发框架G.Controls,首先我将罗列下目前WP7开发遇到的问题。
1.页面之间如何传递复杂的对象?
2.从当前页面返回前一页时如何将当前页的某些数据传递给前一页?
3.如何使得ListBox拥有分页功能?如何使得ListBox中数据在墓碑后自动回复到原来的数据?如何使得ListBox在墓碑后恢复到墓碑前滑动到的项?
4.如何截获附加属性的值的变化
5.如何获取某个UIElement所有子孙控件?在ScrollView滚动的时候如何获取屏幕最上边的控件?
以上种种问题在使用了本框架之后将得到很容易的解决,本人在设计的时候尽量的使得用最少的代码就可以实现以上功能,所以只要使用了本框架,那么你只需写很少的代码就能实现以上的功能。极大的提高开发一个复杂的应用程序的效率,我已经使用该框架开发了多个程序,包括一个电子商务的WP7软件,本人目前使用该框架开发的新浪微博客户端也是使用的该框架,单纯在列表的滑动流畅度方面绝对比新浪官方的流畅,欢迎大家试用。由于已经很长时间没有维护了,所以目前该微博程序还是有不少的Bug,还处于半成品状态,如有问题请直接在设置中给我发送邮件,谢谢!
如果要使用以上的功能,必须确保当前的页面是继承自GBasePage,添加命名空间: xmlns:gNavigate="clr-namespace:G.Navigate;assembly=G.Controls",然后将PhoneApplicationPage节点改成gNavigate:GBasePage。
我将使用新浪微博的数据来演示。
先添加两个类:Message和UserInfo
下面是Message的类
public class Message
{
[XmlElement("created_at")]
public string CreatedTime { get; set; }
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("text")]
public string Text { get; set; }
[XmlElement("thumbnail_pic")]
public string Thumbnail_pic { get; set; }
[XmlElement("bmiddle_pic")]
public string Bmiddle_pic { get; set; }
[XmlElement("original_pic")]
public string Original_pic { get; set; }
[XmlElement("user")]
public UserInfo User { get; set; }
[XmlElement("source")]
public Source Source { get; set; }
[XmlElement("retweeted_status")]
public Message Retweeted { get; set; }
private Count count;
public Count Count
{
get
{
return count;
}
set
{
if (count != value)
{
count = value;
}
}
}
}
public class Count
{
[XmlElement("id")]
public string ID { get; set; }
[XmlElement("comments")]
public int Comments { get; set; }
[XmlElement("rt")]
public int Rt { get; set; }
}
public class Source
{
[XmlElement("a")]
public string Name { get; set; }
}
以下是UserInfo的类:
public class UserInfo
{
[XmlElement("name")]
public string NickName
{
get;
set;
}
[XmlElement("screen_name")]
public string ScreenName
{
get;
set;
}
[XmlElement("id")]
public string Id
{
get;
set;
}
[XmlElement("description")]
public string Description
{
get;
set;
}
[XmlElement("gender")]
public string Gender
{
get;
set;
}
[XmlElement("profile_image_url")]
public string HeadImage
{
get;
set;
}
[XmlElement("province")]
public string Province
{
get;
set;
}
[XmlElement("city")]
public string City
{
get;
set;
}
[XmlElement("location")]
public string Location
{
get;
set;
}
/// <summary>
/// 博客地址
/// </summary>
[XmlElement("url")]
public string Url
{
get;
set;
}
/// <summary>
/// 微博数
/// </summary>
[XmlElement("statuses_count")]
public string StatusesCount
{
get;
set;
}
/// <summary>
/// 关注数
/// </summary>
[XmlElement("friends_count")]
public string FriendsCount
{
get;
set;
}
/// <summary>
/// 粉丝数
/// </summary>
[XmlElement("followers_count")]
public string FollowersCount
{
get;
set;
}
[XmlElement("following")]
public bool Following
{
get;
set;
}
[XmlElement("verified")]
public bool verified
{
get;
set;
}
[XmlElement("status")]
public Message Message
{
get;
set;
}
public string MaxHeadImag
{
get
{
return this.HeadImage.Replace("/50/", "/180/");
}
}
}
这里使用PageListBox来展示数据,添加命名空间: xmlns:gControls="clr-namespace:G.Controls;assembly=G.Controls"
然后使用PageListBox来展示数据:
<gControls:PageListBox x:Name="listbox"
SelectionChanged="listbox_SelectionChanged"
BeginLoadData="listbox_BeginLoadData">
<gControls:PageListBox.ItemTemplate>
<DataTemplate>
<Border toolkit:TiltEffect.IsTiltEnabled="True"
BorderBrush="{StaticResource PhoneBorderBrush}"
BorderThickness="0,1,0,1"
Margin="0,0,0,10"
CornerRadius="5">
<StackPanel Margin="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<gControls:TextButton Foreground="{StaticResource PhoneAccentBrush}"
Text="{Binding User.NickName}"
FontSize="22"
HorizontalAlignment="Left"
x:Name="btnNickName" />
<TextBlock Text="{Binding Source.Name}"
Grid.Column="1"
HorizontalAlignment="Right"
Foreground="{StaticResource PhoneAccentBrush}" />
</Grid>
<TextBlock Text="{Binding Text}"
FontSize="18"
TextWrapping="Wrap" />
<gControls:ImageButton ImageSource="{Binding Thumbnail_pic}"
Tag="{Binding Original_pic}"
Click="ImageButton_Click"
HorizontalAlignment="Center">
</gControls:ImageButton>
</StackPanel>
</Border>
</DataTemplate>
</gControls:PageListBox.ItemTemplate>
</gControls:PageListBox>
然后在cs代码中插入以下代码:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.listbox.EnableTombstoneListBox<Message>(this);
}
上面这段代码是每当导航到当前页的时候就启用墓碑功能,这样,当墓碑后PageListBox会自动到恢复原来的数据。
private void listbox_BeginLoadData(object sender, G.Controls.PageEventArgs e)
{
System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Tick += (a, b) =>
{
XmlAttributes rootAttrs = new XmlAttributes();
rootAttrs.XmlRoot = new XmlRootAttribute("statuses");
XmlAttributeOverrides attrOvrs = new XmlAttributeOverrides();
attrOvrs.Add(typeof(GetMessagesResponse), rootAttrs);
System.Xml.Serialization.XmlSerializer se = new System.Xml.Serialization.XmlSerializer(typeof(GetMessagesResponse), attrOvrs);
GetMessagesResponse response = se.Deserialize(Application.GetResourceStream(new Uri("/PhoneApp2;component/weibo.xml", UriKind.Relative)).Stream) as GetMessagesResponse;
this.listbox.LoadData<Message>(response.Messages);
this.ShowState(string.Format("当前页{0},每页{1}条数据", e.PageNum, e.PageSize));
timer.Stop();
};
timer.Start();
}
以上代码是模拟从服务端获取数据,并且将XML数据转换成相对应的类,使用 this.listbox.LoadData<Message>(response.Messages);添加数据,this.ShowState(string.Format("当前页{0},每页{1}条数据", e.PageNum, e.PageSize));方法将会以一个黄条状的提示信息在屏幕最上那边提示信息。
以上工作以后,PageListBox就已经拥有了分页、墓碑、墓碑后自动滑动到墓碑前项的功能。
以下演示页面间数据的传递功能,就是将一个Message对象传递给下一页。
private void listbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (listbox.SelectedItem != null)
{
Message message = listbox.SelectedItem as Message;
this.NavigationService.Navigate("/Page1.xaml", message);
this.listbox.SelectedItem = null;
}
}
以上代码的核心是 this.NavigationService.Navigate("/Page1.xaml", message);这个方法将会将message传递给下一页。
在下一页中如何取数据?
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Message message = this.NavigationContext.Param as Message;
this.ContentPanel.DataContext = message;
}
以上代码的核心就是this.NavigationContext.Param ,Param 就是前一页传递过来的参数,是要该参数能够被序列化,那么就不用担心墓碑后丢失的问题,因为我已经处理过了。
下面演示如何将当前页的数据传递给前一页:加入当前页有一个TextBox,当我返回到前一页的时候需要将TextBox的值传递给前一页,
首先在当前页添加TextBox和一个按钮
<StackPanel Orientation="Horizontal"
Grid.Row="2">
<TextBox Width="300"
x:Name="txt" />
<Button Content="返回"
Click="Button_Click" />
</StackPanel>
然后在当前页的cs后台代码中插入以下代码:
protected override void OnNavigatingFromBack(NavigateBackFromEventArgs e)
{
base.OnNavigatingFromBack(e);
e.HasHandle = true;
e.Param = txt.Text;
}
注意,必须将HasHandle设置为True,否则返回的时候接收不到数据的!
然后在前一页添加以下代码:
protected override void OnNavigatingBackFrom(NavigateBackFromEventArgs e)
{
base.OnNavigatingBackFrom(e);
MessageBox.Show(e.Param as string);
}
以上就实现了从当前页返回前一页传递数据的功能。
现在演示如何截获ScrollView的VerticalOffset属性值的更改:
首先在页面中添加一个ScrollView,然后在后台代码或者直接在XAML插入代码,下面演示使用后台代码的方式实现:
G.PropertyValueChangedNotify.Create("VerticalOffset", scrollView).PropertyValueChanged += new G.PropertyValueChangedHandle(ScrollView_PropertyValueChanged);
使用上面的代码注册VerticalOffset属性更改后的事件通知
void ScrollView_PropertyValueChanged(DependencyObject d, G.PropertyValueChangedEventArgs e)
{
txtScroll.Text = e.NewValue.ToString();
}
以上代码就可以将ScrollView的当前VerticalOffset的属性值截获。
以下演示框架中的一个ChildWindow控件:当我点击微博的某张图片的时候,需要查看大图,这时候就需要使用ChildWindow来实现该功能了。
添加一个XAML文件,代码如下:
<childWindow:ChildWindow x:Class="PhoneApp2.BrowserImageChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:childWindow="clr-namespace:G.Controls;assembly=G.Controls"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480"
d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="Black">
<Image Source="{Binding}" />
</Grid>
</childWindow:ChildWindow>
修改后台代码
public BrowserImageChildWindow(string url)
{
InitializeComponent();
this.LayoutRoot.DataContext = url;
}
然后当单击图片的时候浏览大图:
private void ImageButton_Click(object sender, RoutedEventArgs e)
{
ImageButton btn = sender as ImageButton;
BrowserImageChildWindow windows = new BrowserImageChildWindow(btn.Tag as string);
windows.Show();
}
框架中还有其他很多的功能,如果大家有兴趣的话可以自己研究下该框架。
后面我会写一篇博客专门讨论如何提升WP7程序性能的文章,相信各位都曾被WP7的性能问题困扰吧?
以下贴出Demo源码下载链接:
以上源码只是demo的源码,并未贴出框架的源码。如果需要的可以向我索取源码,如果索要的人多的话我会直接把源码发出来的,嘿嘿!
未经本人允许,不得私自使用本框架进行商业行为!