wp7学习笔记

Emulator中文叫仿真器,是精确地在一种环境下仿真另一种环境下的运行方式。其目的是完全仿真。Simulator中文叫模拟,是通过某种手段来模拟某些东西,不一定要完全正确的原理,追求的只是尽可能的相像。所以XDE是WP7的Emulator,是一个WP7的虚拟机,我准备写一个XP下开发WP7程序的Simulator。

1、XBox和WP7之间的游戏移植很方便。
2、WP7程序不能运行在后台,不支持多任务。
3、C#是唯一支持的开发语言,不能使用native code,不能PInvoke
4、WP7使用Zune连接电脑,不再支持通过ActiveSync的联系人的同步,而是通过网络同步联系人。
5、使用高级Task的时候必须对模拟器进行Unlock,因为没有Unlock的话模拟器的内容很少。
6、WP7首页上的方框叫Tile,
7、一个程序只能有一个Frame,是所有页面的容器,为SystemTray和ApplicationBar预留空间
8、显示的方向通过Orientation属性来设置:Portrait是竖向,Landscape是横向;SupportedOrientations属性设置支持的方向(默认值是Portrait,也就是只支持竖向。如果设置为PortraitOrLandscape则在转向的时候界面会自动调整);当转向的时候OrientationChanged事件会被触发。
9、WP7中页面的跳转不再是Show这种方式,而是页面Navigation跳转,类似于网页:this.NavigationService.Navigate(new Uri("/Page1.xaml",UriKind.Relative));this.NavigationService.GoBack();this.NavigationService.GoForward();
跳转的时候还可以填值:this.NavigationService.Navigate(new Uri("/Page1.xaml?name=tome",UriKind.Relative));
页面中获取值:this.NavigationContext.QueryString["name"];

可以override OnNavigatedFrom、OnNavigatedTo、OnNavigatingFrom几个方法进行导航的响应。

在普通SL中执行这个的话需要使用“导航Silverlight”模板,参考:http://www.cnblogs.com/steven_gsj/archive/2010/04/24/1719265.html 如果导航失败的话是设置UriMapper的原因,清空即可。NavigationService在Page中才有。

10、shell:SystemTray.IsVisiable属性控制SystemTray可见性
11、ApplicationBar就是菜单栏。ApplicationBarIconButton属性IconUrl、Text,图标要求是48*48png图,前景色一般是白色,微软在C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Icons中提供了一些常用的图标.ApplicationBarIconButton最多只能添加4个,引进图片的时候一定要注意在VS选择图片的属性“BuildAction=Content”、“如果较新则复制”。MenuItems也是放到ApplicationBar中的,MenuItems没有图片、没有二级菜单。

12、Style="{StaticResource PhoneTextNormalStyle}"引用的是资源。代码中用Application.Current.Resources["name"]来加载资源。尽量不要使用自己的颜色,而是引用系统资源中定义的颜色,这个和CSS原理类似。默认系统资源在C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Design\ThemeResources.xaml下

13、独立存储(IsolatedStorage)只有本程序可以访问该区域,安全性高,默认大小为2GB,不能长期保存数据。位于System.IO.IsolatedStorage命名空间下,solatedStorageFile、solatedStorageFileStream两个类。
创建IsolatedStorageFile的方法IsolatedStorageFile.GetUserStoreForApplication(),IsolatedStorageFile类有CreateDirectory()、DirectoryExists()等很多有用的方法。
创建读写流的方法:IsolatedStorageFileStream stream = new IsolatedStorageFileStream("3.txt", FileMode.OpenOrCreate,
                IsolatedStorageFile.GetUserStoreForApplication())

14、在Tile中的图片是在项目的属性中修改的。
15、如果采用Grid布局,相当于ColumnDefinitions和RowDefinitions将界面划分成了网格,然后元素通过Grid.Column、Grid.Row属性来设置它显示在哪个格子中。
16、Canvas布局中代码修改元素位置的方法Canvas.SetLeft(img1,30);
17、Popup容器可以将内部的内容放到顶层显示,IsOpen属性用来标志是否显示。因为SL中页面显示一般是用导航的,但是如果想实现WinForm中对话框的效果就可以用Popup
18、ScrollView包含的内容会可以滚动。
19、HyperlinkButton是一个用于本地、Web的超链接。NavigationUri指向地址,如果指向的是Web地址,则必须设定Target属性。HyperlinkButton可以给Background属性设定ImageBrush来显示图片超链接。
20、用模拟器的时候按Pause键就可以用电脑键盘输入了。
21、TextBox设定InputScope属性可以让软键盘换不同的布局,设置为TelephoneNumber会显示为数字键盘,设置为Url键盘会显示“.com”按钮。所有可选值位于InputScopeNameValue这个枚举中。
22、Image控件只支持png和jpg图片,可以通过Source属性显示本地或者网络图像,网络图片直接填路径就行了,不用通过代码先下载。通过代码加载this.img1.Source = new BitmapImage(new Uri("Desert.jpg",UriKind.Reltive));this.img1.Source = new BitmapImage(new Uri("http://www.baidu.com/Desert.jpg",UriKind.Absolute));
23、MediaElement能够播放本地或者网络上的多媒体,支持WAV、MP3等,支持mms、rtspt、rtsp等流媒体协议。主要属性:IsMuted,是否静音;Stretch,填充方式;AutoPlay:自动播放。事件:MediaOpend、MediaEnded、MediaFailed。
24、推荐使用DispatcherTimer来做定时。因为如果用Timer的话在Timer的Elapsed中访问UI的话需要同步到UI线程执行,而DispatcherTimer是运行在Dispatcher上的,所以访问UI的时候不需要委托到UI线程执行。
25、Thumb是一个可拖动的控件,简化了拖动的开发,Thumb是默认没有再ToolBox中的,需要ChooseItem选进来。通过DragCompleted、DragDelta、DragStarted事件来响应。
当一个Thumb拖动的时候跟着鼠标走:
            <Thumb Height="87" HorizontalAlignment="Left" Margin="89,163,0,0" Name="thumb1" VerticalAlignment="Top" Width="91" DragCompleted="thumb1_DragCompleted" DragDelta="thumb1_DragDelta">
                <Thumb.RenderTransform>
                    <TranslateTransform x:Name="tr"></TranslateTransform>
                </Thumb.RenderTransform>
            </Thumb>
        private void thumb1_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            tr.X = tr.X+e.HorizontalChange;
            tr.Y = tr.Y+e.VerticalChange;
        }
        在Silverlight中一般不直接修改元素的坐标、大小,在需要修改元素的坐标、大小的时候一般使用Transform来做。
26、ListBox通过ItemTemplate来定制外观,Template内部用Text="{Binding Text}"进行绑定
绑定的对象的类要是public的,否则会绑定失败
            <ListBox Height="361" HorizontalAlignment="Left" Margin="60,165,0,0" Name="listBox1" VerticalAlignment="Top" Width="311" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Width="100" Height="100" Source="{Binding Avatar}"/>                            
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="{Binding Name}"/>
                                <TextBlock Text="{Binding Age}"/>
                            </StackPanel>
                        </StackPanel>                        
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public ImageSource Avatar { get; set; }
    }

            List<Person> list = new List<Person>();
            list.Add(new Person { Name="Tom",Age=20,Avatar=new BitmapImage(new Uri("Images/1.jpg",UriKind.Relative))});
            list.Add(new Person { Name = "Jim", Age = 22, Avatar = new BitmapImage(new Uri("Images/2.jpg", UriKind.Relative)) });
            listBox1.ItemsSource = list;          

图片的路径不能以“/”开头,也就是不能"/Images/1.jpg"。

ImgSource属性是ImageSource类型,ImageSource的一个子类是BitmapImage
27、InkPresenter可以产生手写效果。事件:LostMouseCapture、MouseLeftButtonDown、MouseMove。
鼠标画图的典型代码:
        private Stroke stroke;
        private void inkPresenter1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {            
            inkPresenter1.CaptureMouse();
            stroke = new Stroke();
            stroke.DrawingAttributes.Color = Colors.Red;
            inkPresenter1.Strokes.Add(stroke);
        }

        private void inkPresenter1_MouseMove(object sender, MouseEventArgs e)
        {
            stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkPresenter1));
        }
28、WP7中可以使用BMSL来使用BingMaps
29、微软发布了Silverlight控件之外的Silverlight Toolkit,有wp7的版本。提供了额外的控件:AutoCompleteBox、ContextMenu、DatePicker、TimePicker、LongListSelector、ListPicker、ToggleSwitch(很好看的开关)、WrapPanel等控件
1)ContextMenu控件提供了上下文菜单,长按屏幕弹出,因为手机中没有右键。ContextMenu不能用在容器控件中
            <TextBox Height="72" HorizontalAlignment="Left" Margin="17,109,0,0" Name="textBox1" Text="TextBox" VerticalAlignment="Top" Width="384">
                <toolkit:ContextMenuService.ContextMenu>
                    <toolkit:ContextMenu>
                        <toolkit:MenuItem Header="复制"/>
                        <toolkit:Separator/>
                        <toolkit:MenuItem>
                            <toolkit:MenuItem.Header>
                                <Image Width="30" Height="30" Source="ApplicationIcon.png"/>
                            </toolkit:MenuItem.Header>
                        </toolkit:MenuItem>
                    </toolkit:ContextMenu>
                </toolkit:ContextMenuService.ContextMenu>
            </TextBox>
ContextMenu还可以设定Margin属性,这时候Margin属性用来改变菜单相对于控件的位置。
2)WrapPanel会将放到其中的控件按照从左到右、从上到下的顺序依次排列。
3)DatePicker、TimePicker是非常易用的日期、时间选择器,而且可以通过ValueStringFormat来修改显示格式,语法就是DateTime.ToString的格式语法。
4)ListPicker和ListBox的不同在于,如果为FullMode那么当点击ListPicker的时候会弹出一个全屏窗口来选择,用起来更方便。
5)LongListSelector用来对数据进行快速的分类定位,非常方便,用起来比较复杂,看例子就行。

30、Panorama控件是一个全景视图控件,像一个窗口,能够查看内容的一部分。全景视图由Background、Title、Items组成。可以自己加这些控件,也可以用项目向导中的“WindowsPhone Panorama Application”快速创建一个完整的Panorama控件项目,用来学习很方便。用法看向导生成的代码即可。
31、Pivot控件是一个竖向滚动的控件。
32、WP7中可以使用DeepZoom技术。
wp7社区 http://social.msdn.microsoft.com/Forums/en-US/windowsphone7series
33、Blend的使用:
1)向左下角倾斜的按钮是渐变工具,可以设置控件的渐变。渐变有线性渐变、径向渐变两种。
2)笔刷变换工具是对控件的Brush进行变形的工具,和控件变形不一样。
3)转换(Transform)中的RenderTransfer可以用来实现旋转、缩放、位移等效果。
4)可以选中一个控件然后再在控件里添加子控件
5)新建时间线、可以选择不同的关键帧,在关键帧处设置控件属性变化的目标值。
6)可以将Brush等转换为资源,这样可以服用,类似于CSS。可以设置一个画刷,然后点击旁边的小方块图标,选择“转换为新资源”,保存的时候可以保存为UserControl中还是单独的文件中,类似于在htm中声明样式和单独的css中声明样式。一旦转换为资源,就可以在“画笔资源”面板中选择了。

45、SL控件包含Parts、States Model两部分,Parts就是子控件。StatesModel包含:Visual States(控件在不同状态下显示的效果)、Visual State Groups(为有互斥效果的控件提供的,相同的Visual State Groups是互斥的,不同的Visual State Groups是不互斥的)、Visual Transition(视觉状态转换时切换动画效果)。
1)快速设置控件的Visual State的方法:绘制Ellipse等图形,然后点击右键选择“构成控件(Make Into Control)”,然后选择要修改的控件即可。假设选择的是Button控件,这时候编辑器就进入了按钮的Templates编辑器,这时候设计器中的修改都是反映到Button的Template中的,要想退出需要点击设计器左上角的“[Button]”,想再次继续则需要选中按钮,然后点击设计器左上角的“Template”,也可以点击控件,右键选择“编辑模板”→“Editi Current”。
2)如果设置了“构成控件(Make Into Control)”,则默认所有状态都是一个样子,点击按钮将不会有效果,可以修改不同的状态的样子。编辑控件的Template进入Template编辑模式,选择“状态(States)”面板中的“Pressed”,调整控件的大小或者颜色,这样就可以设置按钮按下的样式了。
3)除了可以用“构成控件(Make Into Control)”修改控件之外,也可以在控件上点击右键,选择“编辑模板(Edit Template)”→“编辑副本(Edit Copy)”来修改Template。
4)应用已有样式模板的方法,点击控件、右键“编辑模板”→“引用资源”
5)控件之间状态转换的时候是瞬间切换的,如果想要动画转换效果,则需要在状态上点击“添加过渡”按钮添加过渡效果,需要设置过渡时间,注意Normal和Pressed之间一般不能直接转换,因为还隔着一个MouseOver呢。
6)可以用自定义Visual State技术来自定义ProgressBar,因为可以在State内部也是用动画,这样就可以实现Indeterminate状态下一个心脏跳来跳去的效果或者一个星星一闪一闪的效果。

46、WP7没有提供直接操作SMS、Phone、Email、Camera等的API,需要通过Task来执行,因此无法批量操作、免界面操作。当Task启动后,自己的应用程序就会被终止,通过Tombstone机制再次唤起自己的程序,并需要维护相关的状态。
47、Task:
1)PhoneCallTask用来拨号,主要两个属性:DisplayName、PhoneNumber,调用Show方法即可启动。
2)SmsComposeTask用来打开系统SMS程序,并且设置所要发的短信内容和发送人,可以发送彩信,但是只能发图片和摄像头拍照,不能发送声音和视频。Body、To两个属性。
3)SavePhoneNumberTask用来调用联系人程序,将电话号码保存到选中的联系人或者新建联系人。属性:PhoneNumber,事件Completed,无法设置联系人的姓名,必须用户手工填写。
4)PhoneNumberChooserTask用来打开联系人界面,选择一个联系人的号码。在Completed事件中获得选择的号码。
5)EmailComposeTask用来发邮件。EmailAddressChooserTask用来选择邮件地址。SaveEmailAddressTask。
6)PhotoChooserTask用来调用图片程序选择图片,并可以进行裁切。ShowCamera用来控制是否显示拍照程序,PixelWidth、PixelHeight属性设置裁切的大小,Completed事件用来监听选择完成事件。Completed事件中e.ChosenPhoto获得选中图像的流。
BitmapImage img = new BitmapImage();
img.SetSource(e.ChosenPhoto);
image1.Source = img;

需要注意PhotoChooserTask不能声明为局部变量,必须声明为类成员。因为启动照相机以后应用就被结束了,因此如果在按钮Click事件中如下写:
PhotoChooserTask task = new PhotoChooserTask();
task.Completed += new EventHandler<PhotoResult>(task_Completed);
task.PixelHeight = 100;
task.PixelWidth = 100;
task.ShowCamera = true;            
task.Show();

task_Completed事件不会正确触发的,因为再次回来已经不是上次引用程序的实例了,因此需要如下编写:
PhotoChooserTask task = new PhotoChooserTask();
 public MainPage()
        {
            InitializeComponent();
            task.Completed += new EventHandler<PhotoResult>(task_Completed);
        }
 private void Button_Click(object sender, RoutedEventArgs e)
        {
            task.PixelHeight = 100;
            task.PixelWidth = 100;
            task.ShowCamera = true;
            
            task.Show();
        }  
也就是把注册Completed监听放到构造函数中,这样程序重启启动以后如果是从照相机返回的事件就会被触发。
注:这是旧SDK的Bug,新SDK已经没有这个问题。
 
7)CameraCaptureTask用于启动拍照程序,同样响应Completed事件。
8)MediaPlayerLauncher用来调用系统的MediaPlayer程序播放本地或者Web的媒体。模拟器上无法播放Video。
9)WebBrowserTask用来在浏览器中打开URL,只要设定URL属性即可。
10)SearchTask用来启动搜索程序,设置SearchQuery属性。

48、WP7应用程序只支持在前台执行,如果一个程序在你的程序正在运行的时候启动,程序收到一个将要被终止的事件通知。在程序关闭状态下,可以通过WebService来向程序发送信息以及更新程序状态,这叫PushNotification。
49、Tombstone课执行模式:Tombstoning、PageState、ApplicationState、PersistentData、TransientState。Tombstoning、TransientState下模拟多任务,在Tombstone模式下,应用被操作系统终止,就需要保存TransientState,以便于应用程序复活后恢复应用原状态。应用程序Lifecycle包括Launching、Running、Closing、Deactivating、Activating这五种运行状态,在App.xaml.cs中影响这些事件。Deactivating、Activating就是Tombstone下的运行态。通过PhoneApplicationService来保存状态信息。
可以在Page中override OnNavigatedFrom、OnNavigatedTo方法来保存、恢复状态。
实现保存文本框中用户正在输入的值的代码:
protected override OnNavigatedFrom(e)
{
    PhoneApplicationService.Current.State["Test"] = textbox1.Text;
    base.OnNavigatedFrom(e);
}

protected override OnNavigatedTo(e)
{
    if(PhoneApplicationService.Current.State.ContainsKey("Test"))
    {
        textbox1.Text = PhoneApplicationService.Current.State["Test"] as string;
    }
    base.OnNavigatedTo(e);
}

50、PushNotification的几个概念:TileNotification可以改变QuickLauchArea内的图标内容(图片、文字等)的方式,需要程序被Pin to Start。ToastNotification在屏幕的提示栏中显示内容,点击提示栏可以打开应用程序。RawNotification可以用Http方式来接收通知,不可见,以后台方式传送通知。WP7上只能有15个PushNotification,如果多个程序都有PushNotification能力,则有的程序可能运行不正常。详细看视频。
51、Microsoft.Phone.Info.UserExtendedProperties获得用户信息,目前只能获得一个用于MarketPlace的ANID。DeviceExtendedProperties用来获取设备信息,可以取道的信息如下:http://msdn.microsoft.com/en-us/library/ff941122(v=vs.92).aspx

52、Microsoft.Devices.Sensors.Accelerometer可以获取传感器信息。主要用于游戏开发。todo:开发一个重力传感器模拟器。
Accelerometer am = new Accelerometer();
Accelerometer.ReadingChanged+=....;
am.Start();
am.Stop();

53、System.Device.Location命名空间下有获得定位数据的类。
watcher = new GeoCoordinateWatercher(GeoPositionAccuracy.Default);
watcher.MovementThreshold=35;
watcher.PositionChanged+=....

54、Microsoft.Devices.Radio下的FMRadio类是收音机设备。因为只有一个收音机,因此是单件模式。todo:作品,带SNS功能的网络收音机,能显示这个频率的电台名。能听友在线交流。
FMRadio radio = FMRadio.Instance;
radio.CurrentRegion = RadioRegion.Europe;
radio.Frequency = 100.5;
radio.PowerMode = RadioPowerMode.On;

55、Microsoft.Devices下的VibrateController可以控制振动器。
VibrateController vc = VibrateController.Default;
vc.Start(TimeSpan.FromMilliseconds(100));//设置震动时间。
vc.Stop()

56、可以用Reactive Extension来实现模拟设备数据(重力、位置等),参考WebCast20101214am_设备开发.zip
57、XNA是基于Managed DirectX的游戏开发环境。
58、即使不开发游戏,也可以使用XNA中的一些类。在WP7中使用XNA的时候需要使用定时器定时的执行FrameworkDispatcher.Update()以驱动XNA,否则可能会报错,一般如下调用:
 DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(50);
            timer.Tick += (sender, e) => { FrameworkDispatcher.Update(); };
            timer.Start();
            
(1)用SoundEffect来播放wav格式的音频。
SoundEffect sound = new SoundEffect(stream.ToArray(),SampleRate,AudioChannels.Mono);
SoundEffectInstance inst = sound.CreateInstance();
inst.Play();
wav格式文件可以以资源的形式放到程序中。

Windows Phone7或者SL中加载一个资源的方法,以加载wav文件为例:首先将wav文件的“Build Action”属性设置为“Embedded Resource”,假设文件名为Speech Off.wav放到项目根目录下:
嵌入资源的名字一般是“Assembly名字.文件夹名.文件名”,如果忘了的话可以用assembly.GetManifestResourceNames()方法获得所有的资源名。使用string asmName = new AssemblyName(Assembly.GetExecutingAssembly().FullName).Name获得当前Assembly的名字,不能用Assembly.GetExecutingAssembly().GetName() 方法取,因为会报错。
string asmName = new AssemblyName(Assembly.GetExecutingAssembly().FullName).Name;
            using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(asmName+".Speech Off.wav"))
            {
                SoundEffect sound = new SoundEffect(ReadFully(stream), 48000, AudioChannels.Mono);
                SoundEffectInstance inst = sound.CreateInstance();
                inst.Play();
            }  
        public static byte[] ReadFully(Stream stream)
        {
            byte[] buffer = new byte[32768];
            using (MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                        return ms.ToArray();
                    ms.Write(buffer, 0, read);
                }
            }
        }            
       


(2)Song类播放mp3等格式的音乐,可以播放背景音乐
Song song = Song.FromUri("MyMusic",new Uri("Media/TestMusic.mp3",UriKind.Relative));
MediaPlayer.Play(song);
MediaPlayer类功能非常丰富,提供了播放列表、进度报告、播放状态事件等,完全可以用来做一个播放器。Song类也提供了获得专辑、声道等的方法。
(3)Microphone类(Microsoft.Xna.Framework.Audio)可以调用麦克风录音,buffer是wav格式的,可以直接传给SoundEffect播放
Microphone m = Microphone.Default;
m.BufferReady+=...()=>{m.GetData(buffer);};
m.Start();
m.Stop();

        private byte[] ReadAllData(Microphone m)
        {
            List<byte> list = new List<byte>();
            byte[] buffer = new byte[1024];
            int readlen;
            while ((readlen = m.GetData(buffer)) > 0)
            {
                if (readlen < buffer.Length)
                {
                    list.AddRange(buffer.Take(readlen));
                }
                else
                {
                    list.AddRange(buffer);
                }               
            }
            return list.ToArray();
        }
(4)与用户交互的方法:手势和触控。位于Microsoft.Xna.Framework.Input和Microsoft.Xna.Framework.Input.TouchPanel下。
触控状态只有Move、Press、Release三种。
TouchCollection touchState = TouchPanel.GetState();
foreach(TouchLocation location in toucheState)
{
   
}

TouchPanel.GetState()不是阻塞的,因此要在DispatchTimer中不断的读取获取触控状态。

手势的编程:
TouchPanel.EnabledGestures = GestureType.Flick|GestureType.VerticalDrag;//设置程序要监听的手势类型。
定时器中不断的读取手势:
if(TouchPanel.EnabledGestures!=GestureType.None&&TouchPanel.IsGestureAvailable)//只有IsGestureAvailable=true才能ReadGesture
GestureType t = TouchPanel.ReadGesture().GestureType;

59、Properties下的WMAppManifest.xml中的Capabilities节点下定义的是程序要求的访问权限,应该保持权限最小。DefaultTask定义的是启动页面。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值