“在芭蕉”为你分享9篇“Silverlight中使用MVVM基础”,经本站小编整理后发布,但愿对你的工作、学习、生活带来方便。
篇1:Silverlight中使用MVVM基础
这是我第一篇关于设计模式方面的文章,以前除了对单例模式等几个常用的 模式有所研究之外,对设计模式不是太重视,总觉得要到一定的程度才需要接触 ,最近的项目中使用了MVVM模式,所以这段时间查阅了大量这方面模式的文章, 理论上的东西大家都说的比较好,这里我也不大谈MVVM模式的优势了,只是美中 不足的是大部分给出的示例中,对于一个没有用过MVVM模式的人而言,这些例子 总是给人一种摸不着头绪的感觉,所以我想将我学习MVVM的过程一步步写下来, 希望对于和我一样,刚刚接触MVVM这个模式的人有一点点帮助,
如果你不知道MVVM模式,我建议你先了解一下MVVM模式,至少要知道实现该 模式的意图是什么。
那么我主要通过我认为是已经算是比较简单的例子进行讲解这个模式,当然 后面我们会在这个例子的基础上一步一步的进行扩展。
先来看一看我们的项目架构:
很典型的MVVM的分层方式
我们先来构建Model,首先在Person.cs中简单声明了一个类型
public class Person
{
public int age { get; set; }
public string name { get; set;}
}
类型定义好后,我们在Persons.cs中得到一个Person的集合
public class Persons
{
public List
person;
public List
getPerson
{
person = new List
()
{
new Person{name = “Tom”, age = 21 },
new Person{name = “Jack”, age = 22 },
new Person{name = “Rose”, age = 23 },
};
return person;
}
}
那么这里我们就简单的完成了Model的工作,下面开始完成ViewModel部分的 工作
public class PageViewModel
{
public List
Human { get; set; }
public PageViewModel()
{
Human = new Persons().getPerson();
}
}
ViewModel也设计的很简单,只是简单的获取了之前定义的集合。
下面就是PageView部分了,这里用DataGrid进行显示数据
这里我们将DataGrid的源设为Human,这样我们就完成了MVVM模式各个层次的 初步构建,关键的问题是怎样将这几个部分有效的联系起来
我们将PageView,PageViewModel引入到MainPage中
xmlns=“http://schemas.microsoft.com/winfx//xaml/presentation”
xmlns:x=“http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:d=“http://schemas.microsoft.com/expression/blend/”
xmlns:mc=“http://schemas.openxmlformats.org/markup- compatibility/2006”
mc:Ignorable=“d”
xmlns:viw=“clr-namespace:UseMVVMInApp.View”
xmlns:vmmodel=“clr-namespace:UseMVVMInApp.ViewModel”
d:DesignHeight=“300” d:DesignWidth=“400”>
这里的工作就是将PageViewModel声明为一个资源,然后通过页面引用它,这 样就实现了我们所谓的MVVM模式,
当然了,这个例子是很简单的,似乎用MVVM模式未免小题大作,但是实际上 ,页面与逻辑分离的情况下,我们改动其中任何一个部分都是比较清楚的。
好吧,这篇就到这里
篇2:Silverlight中使用MVVM―提高
在第一篇文章中的示例中,我们已经简单的了解了应用MVVM模式的流程,我 的本意是你已经了解了一点MVVM的概念,然后又没有一个较好的例子学习,可以 跟着我一起学习MVVM模式,所以这个部分,都是没有理论知识的,当然整个例子 学完后,我们会回过头探讨一下,将其总结出来,
现在我们主要在前面的示例上进行扩展,前面的示例中我们主要是将一个源 对象绑定到DataGrid中的,接下来我们继续使用MVVM模式,将 DataGrid选择行 的变化体现界面中,其实通过这个需求变化,你会发现UI与逻辑分离带来的优势 ,尽管才开始似乎有点不习惯,但是相信你会不自觉的在项目倾向于中使用MVVM 模式。
需求:通过单击DataGrid,将当前的选择行的数据反映到TextBox中。
Model未发生变化,我们还用前面的Person.cs和Persons.cs两个类,那么对 于ViewModel,我们给其增加一个属性
private Person _getOnePerson;
public Person GetOnePerson
{
get { return _getOnePerson; }
set { _getOnePerson = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(“GetOnePerson”));
}
}
}
因为这里的属性将发生变化,所以我们对PageViewModel类实现了 INotifyPropertyChanged借口
UI层: 这里我们将GetOnePerson属性绑定到DataGrid的SelectedItem属性上
SelectedItem=“{Binding GetOnePerson,Mode=TwoWay}”
Height=“200” Name=“dataGrid1” VerticalAlignment=“Top” />
Name=“textBox1” VerticalAlignment=“Top” Width=“120” />
Name=“textBox2” VerticalAlignment=“Top” Width=“120” />
我们在UI上增加了2个TextBox,用于反映页面上的变化,主要就是注意一下 Binding的对象
这些都完成后,其它部分就不用改动了,我们已经完成了这个功能,我们可 以看看页面的效果:
单击前后的变化
功能虽较为简单,但是刚接触MVVM时, 要很顺利的实现也不算是一件容易的 事情,后面我会在这个例子的基础上,
通过使用Command实现一个较简单的查询,
篇3:Silverlight中使用MVVM―进阶
这篇主要引申出Command结合MVVM模式在应用程序中的使用
我们要做出的效果是这样的
就是提供了一个简单的查询功能将结果绑定到DataGrid中,在前面的基础上 ,这个部分相对比较容易实现了
我们在PageViewModel中添加两个属性
private string _searchText;
//查询关键字
public string SearchText
{
get { return _searchText; }
set { _searchText = value;
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(“SearchText”));
}
}
}
private List
_resultText;
//查询结果
public List
ResultText
{
get { return _resultText; }
set { _resultText = value;
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(“ResultText”));
}
}
}
这两个属性我们后面将绑定到View中,下面实现查询方法
//查询方法
public void Searhing
{
List
person = null;
if (!string.IsNullOrEmpty(SearchText))
{
person = new List
();
foreach (Person p in Human)
{
if (p.name.Contains(SearchText))
{
person.Add(p);
}
}
}
if (person != null)
{
ResultText = person;
}
}
我们这里就是通过查询到的集合person赋值给查询结果,这两步比较好理解, 然后我们需要在ViewModel中声明一个Command对象来执行页面的单击事件
private ICommand _cmd;
//声明Command
public ICommand Cmd
{
get { return _cmd; }
}
public PageViewModel()
{
Human = new List
();
Human = new Persons().getPerson();
_cmd = new QueryCommand(this);
}
在构造函数中实例了Command对象,在这里我们仍然有一步工作需要完成,就 是对QueryCommand的实现
public class QueryCommand:ICommand
{
public PageViewModel _pageVM = null;
public QueryCommand(PageViewModel vm)
{
_pageVM = vm;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
public void Execute(object parameter)
{
_pageVM.Searhing();
}
}
你可以看出来Command类是用ViewModel来实例的,自然这里面由Execute()完 成查询这个工作,
最后我们将UI上做点小小的变动
我们将DataGrid的ItemSource属性绑定到ResultText上,对于输入框我们则 将其绑定到SearchText属性上,这样我们就完成了大部分的工作
下面就是将View和ViewModel两者之间如何关联了,因为Sl3中不支持Commnad 这个属性,所以这里我们就在后台进行声明
PageViewModel pageviewmodel=new PageViewModel();
public PageView()
{
InitializeComponent();
this.btnSearch.Click += new RoutedEventHandler (btnSearch_Click);
this.DataContext =pageviewmodel;
}
void btnSearch_Click(object sender, RoutedEventArgs e)
{
pageviewmodel.SearchText = this.textBox1.Text.Trim ();
pageviewmodel.Cmd.Execute(null);
}
这一步完成后,我们就实现了开头的功能,这个功能虽然实现了,但是你可 能会发现一个问题,我们将Searching()的执行写在了QueryCommand.Execute() 中,
在这种情况下我们需要为每一个方法声明一个Command类,自然这不是我们期 望做的事情,所以我们下面将这个问题优化一下:
我们先声明一个RelayCommand类
public class RelayCommand : ICommand
{
private Action _handler;
public RelayCommand(Action handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
这里RelayCommand类可以作为一个派生类用于与页面Command的实现,那么 ViewModel中,我们声明一个ICommand属性
private readonly ICommand _searchCommand;
public ICommand SearchCommand
{
get { return _searchCommand; }
}
自然我们需要将构造函数变动一下
public PageViewModel()
{
Human = new List
();
Human = new Persons().getPerson();
_searchCommand = new RelayCommand(Searhing) { IsEnabled = true };
}
通过第3行代码,我们其实就是将ViewModel与Command分离了,最后我们将 button事件代码修改一下
void btnSearch_Click(object sender, RoutedEventArgs e)
{
pageviewmodel.SearchText = this.textBox1.Text.Trim ();
pageviewmodel.SearchCommand.Execute(null);
}
这样的话,看起来似乎优雅了点,关于这部分内容网上资源也比较多,就不 多解释了,
下篇我将结合MVVM与Command实现一个简单的CRUD操作
本文配套源码
篇4:Sharepoint中使用Silverlight的相关问题
Silverlight越来越多的应用到了Web开发环境,在Sharepoint中也不例外,下面是一些关于在Sharepoint 中使用Silverlight的备注事项:
1、IE版本问题:Silverlight的xap文件在64bit的IE里是不能加载的,因此,请用32bit的IE进行加载,
2、Safari浏览器支持问题:Silverlight WebPart不支持Mac机上的Safari浏览器,但在Pc机上的Safari浏览器能加载。
3、Xap文件调用路径问题: 在Sharepoint开发代码中调用xap文件时要使用xap文件的相对路径(Relative Path),因为你某天把现在的Web application扩展到其它区域时,你会使用不同的url来访问你的web,如果你使用的是full path,你的Silverlight WebPart就必然会因为url的改变而加载失败,
4、Xap文件部署位置问题: 至于如何部署你的xap文件,常见的有两种选择,一种是在你的Sharepoint网站上创建一个Document Library,然后在那儿存放你的xap文件。另一种是部署到“layouts”的“ClientBin”目录下,此方法的好处是便于在VS2010环境中对此位置进行操作。
5、WCF与Silverlight结合问题: 在WCF proxy generation与Silverlight的结合时会出现当升级了WCF service后,想进一步升级Silverlight 项目中对此WCF service的引用(reference),而此时你会发现proxy generation失败,项目里也无法创建proxy classes。试着通过reflecting你的Sharepoint网站里已经部署好的WCF service并修改web.config的有关设置来解决此问题。
篇5:学Silverlight 2系列(9):使用控件
本文为系列文章第九篇,主要介绍如何使用控件模板定制控件的观感, Silverlight提供了极其强大的功能,允许用户完全定制控件的外观。
定制控件内容
在Silverlight中,WatermarkedTextBox控件可以为用户的输入提供一段提示 信息,如果只是简单的一点文字信息,有时候未免显得单调,如果加上相应的图 片说明效果会更好,如下图所示的一个简单的用户登录界面:
这样看起来界面显的就生动多了,XAML声明如下:
Width=“320” Height=“48”>
Width=“320” Height=“48” HorizontalAlignment=“Left”>
Width=“120” Height=“48”>
很多控件都有Content或者Text属性,我们完全可以充分发挥自己的想象力去 进行定制,定制后控件仍然具有原来的功能行为,如上面的示例,当输入用户名 控件获得焦点时文字和图片都将消失:
使用控件模板定制控件
前面的示例中我们只是定制了控件的内容,Silverlight允许我们完全对控件 进行定制,而不仅仅是内容,
下面的示例中我们定制一个渐变色的圆角矩形按钮 。首先我们在App.xaml中创建一个RoundButton样式,改写按钮的Template属性 :
其中的渐变等内容在Graphics相关内容里将会写到。现在在XAML中使用该样 式:
Canvas.Top=“80” Canvas.Left=“150”/>
运行后就可以看到下面的效果:
创建模板
上面的示例中,控件的文字以及控件的大小都是固定的,我们希望在开发人 员使用中再设定,可以在控件模板中通过使用 {TemplateBinding ControlProperty} 的标识扩展句法来绑定到控件的属性来实现,使用 ContentPresenter控件可以灵活的设置各个属性。修改RoundButton样式如下所 示:
这样在使用RoundButton时我们可以设定控件的文本及控件的大小:
Canvas.Top=“80” Canvas.Left=“50”
Content=“提 交” FontSize=“26”
HorizontalContentAlignment=“Center”
VerticalContentAlignment=“Center”
Foreground=“White” Width=“200” Height=“60”/>
Canvas.Top=“80” Canvas.Left=“260”
Content=“取 消” FontSize=“26”
HorizontalContentAlignment=“Center”
VerticalContentAlignment=“Center”
Foreground=“White” Width=“100” Height=“100”/>
运行时效果如下:
结束语
本文简单的介绍了如何定制控件的内容以及通过控件模板完全定制控件,你 可以从下载本文示例代码。
本文配套源码
篇6:Silverlight:以编程方式使用动画
有时您可能要动态(即时)更改动画的属性,例如,您可能要调整应用到对象 的动画行为,这取决于对象当前在布局中的位置、对象包含何种内容等等。可以 通过使用程序代码(例如 C# 或 Visual Basic)动态操作动画。
先决条件
您应熟悉 Silverlight 动画。有关简介,请参见动画概述。
通过名称访问动画
访问动画对象以更改其属性的最直接方法是:命名该动画对象,然后在代码中 通过该名称引用它。下面的示例包含一个 Ellipse,当您在屏幕上单击时它将显 示动画效果。为了实现此动画,在单击 Canvas 时,事件处理程序更改 PointAnimation 对象的 To 属性,然后启动动画。
运行此示例:http://go.microsoft.com/fwlink/? LinkId=139798&sref=change_animation_properties_1
XAML
Background=“Gray” Width=“600” Height=“500”>
x:Name=“myPointAnimation”
Storyboard.TargetProperty=“Center”
Storyboard.TargetName=“MyAnimatedEllipseGeometry”
Duration=“0:0:2”/>
Center=“200,100” RadiusX=“15” RadiusY=“15” />
VB
Private Sub Handle_MouseDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
' Retrieve current mouse coordinates.
Dim newX As Double = e.GetPosition(Nothing).X
Dim newY As Double = e.GetPosition(Nothing).Y
Dim myPoint As Point = New Point
myPoint.X = newX
myPoint.Y = newY
myPointAnimation.To = myPoint
myStoryboard.Begin
End Sub
C#
private void Handle_MouseDown(object sender, MouseButtonEventArgs e)
{
// Retrieve current mouse coordinates.
double newX = e.GetPosition(null).X;
double newY = e.GetPosition(null).Y;
Point myPoint = new Point();
myPoint.X = newX;
myPoint.Y = newY;
myPointAnimation.To = myPoint;
myStoryboard.Begin();
}
使所有动画具有唯一的名称有时不易做到。这时您可以使用集合来访问动画或 动画的关键帧。例如,如果要以编程方式访问 DoubleAnimationUsingKeyFrames 对象中的所有关键帧,可以使用与以下代码类似的代码:
XAML
Width=“600” Height=“500” Background=“Gray”>
x:Name=“myPointAnimationUsingKeyFrames”
Storyboard.TargetProperty=“Center”
Storyboard.TargetName=“MyAnimatedEllipseGeometry”
Duration=“0:0:3”>
Center=“200,100” RadiusX=“15” RadiusY=“15” />
C#
public void Handle_MouseDown(object sender, MouseEventArgs e)
{
int i;
for (i = 0; i < myPointAnimationUsingKeyFrames.KeyFrames.Count; i++)
{
// Do something with each keyframe; for example, set values.
}
}
下面的示例与上一个示例类似,即在用户单击屏幕的地方出现椭圆,只是此示 例中使用了关键帧。对关键帧的集合进行迭代并为关键帧动态设置值,以便使椭 圆动画出现在合适的位置。
运行此示例:http://go.microsoft.com/fwlink/? LinkId=139798&sref=access_keyframe_collection
XAML
Width=“600” Height=“500” Background=“Gray”>
x:Name=“myPointAnimationUsingKeyFrames”
Storyboard.TargetProperty=“Center”
Storyboard.TargetName=“MyAnimatedEllipseGeometry”
Duration=“0:0:3”>
Center=“200,100” RadiusX=“15” RadiusY=“15” />
C#
' Global variables that keep track of the end point
' of the last animation.
Private lastX As Double = 200
Private lastY As Double = 100
Private Sub Handle_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
' Retrieve current mouse coordinates.
Dim newX As Double = e.GetPosition(Nothing).X
Dim newY As Double = e.GetPosition(Nothing).Y
Dim i As Integer
i = 0
Do While (i < myPointAnimationUsingKeyFrames.KeyFrames.Count)
Dim keyFrame. As PointKeyFrame. = myPointAnimationUsingKeyFrames.KeyFrames(i)
If (keyFrame.GetType.Name = “DiscretePointKeyFrame”) Then
keyFrame.SetValue (DiscretePointKeyFrame.ValueProperty, New Point(lastX, lastY))
ElseIf (keyFrame.GetType.Name = “LinearPointKeyFrame”) Then
' The LinearKeyFrame. has a value that is part way to the
' final end point. In addition, this value has to be on
' the correct line, therefore, you need to use the line
' formula y = mx + b to find the values of x and y.
' Calculate the slope
Dim m As Double = ((newY - lastY) / (newX - lastX))
' Calculate the y-intercept.
Dim b As Double = (newY - (m * newX))
' Set X to a third of the way to the end point.
Dim intermediateX As Double = (lastX + ((newX - lastX) / 3))
' Find the value Y from X and the line formula.
Dim intermediateY As Double = ((m * intermediateX) + b)
' Set the keyframe. value to the intermediate x and y value.
keyFrame.SetValue (LinearPointKeyFrame.ValueProperty, New Point(intermediateX, intermediateY))
ElseIf (keyFrame.GetType.Name = “SplinePointKeyFrame”) Then
keyFrame.SetValue (SplinePointKeyFrame.ValueProperty, New Point(newX, newY))
End If
i = (i + 1)
Loop
myStoryboard.Stop()
myStoryboard.Begin()
lastX = newX
lastY = newY
End Sub
注意说明:
Storyboard 具有 Children 属性,该属性允许您访问指定 Storyboard 中的 所有动画对象。
动态更改 TargetName
动态更改 Storyboard.TargetName 属性最常见的情况是您想将同一动画应用 到多个对象。当具有要应用相似动画的大量对象时,这特别有用。例如,您可能 要显示几行图像并使用动画突出显示鼠标当前所指示的图像。为每个图像创建单 独的 Storyboard 对象非常麻烦。重用同一 Storyboard 更为合适。
下面的示例涉及很多矩形,当您单击这些矩形时,它们会逐渐消失,接着重新 显示。所有这些矩形使用同一 Storyboard,因为呈现 Opacity 动画效果的 DoubleAnimation 将 TargetName 更改为所单击的矩形。
运行此示例:http://go.microsoft.com/fwlink/? LinkId=139798&sref=change_targetname_1
XAML
Storyboard.TargetProperty=“Opacity”
From=“1.0” To=“0.0” Duration=“0:0:2”
AutoReverse=“True” />
x:Name=“MyAnimatedRectangle1”
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
x:Name=“MyAnimatedRectangle2”
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
x:Name=“MyAnimatedRectangle3”
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
x:Name=“MyAnimatedRectangle4”
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
VB
Private Sub Start_Animation(ByVal sender As Object, ByVal e As MouseEventArgs)
' If the Storyboard is running and you try to change
' properties of its animation objects programmatically,
' an error will occur.
myStoryboard.Stop()
' Get a reference to the rectangle that was clicked.
Dim myRect As Rectangle = CType(sender, Rectangle)
' Change the TargetName of the animation to the name of the
' rectangle that was clicked.
myDoubleAnimation.SetValue(Storyboard.TargetNameProperty, myRect.Name)
' Begin the animation.
myStoryboard.Begin()
End Sub
在前面的代码中,请注意您在动态更改动画对象的属性前必须停止 Storyboard,否则将出错,在此示例中,可能不希望只有停止一个矩形的动画才 能启动另一个矩形的动画。可能您想同时运行这两个动画。但是,您不能使用同 一个动画对象同时运行两个独立的动画,因为只有一个 TargetName。这并不意味 着您不得不重新为每个对象创建单独的 Storyboard。您只需要为并发(同步)运 行的每个动画提供一个 Storyboard。下面的示例与上一个示例类似,只是它包含 三个而不是一个 Storyboard 对象。您单击矩形时,事件处理程序查找当前未使 用的 Storyboard 并使用它来创建动画。
运行此示例:http://go.microsoft.com/fwlink/? LinkId=139798&sref=change_targetname_2
XAML
Storyboard.TargetProperty=“Opacity”
From=“1.0” To=“0.0” Duration=“0:0:2” AutoReverse=“True” />
Storyboard.TargetProperty=“Opacity”
From=“1.0” To=“0.0” Duration=“0:0:2”
AutoReverse=“True” />
Storyboard.TargetProperty=“Opacity”
From=“1.0” To=“0.0” Duration=“0:0:2”
AutoReverse=“True” />
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
Margin=“3” Width=“100” Height=“100” Fill=“Blue”
MouseLeftButtonDown=“Start_Animation” />
VB
Private storyboard1Active As Boolean = False
Private storyboard2Active As Boolean = False
Private storyboard3Active As Boolean = False
Private Sub Start_Animation(ByVal sender As Object, ByVal e As MouseEventArgs)
' Get a reference to the rectangle that was clicked.
Dim myRect As Rectangle = CType(sender, Rectangle)
If Not storyboard1Active Then
myStoryboard1.Stop()
myDoubleAnimation1.SetValue (Storyboard.TargetNameProperty, myRect.Name)
myStoryboard1.Begin()
storyboard1Active = True
ElseIf Not storyboard2Active Then
myStoryboard2.Stop()
myDoubleAnimation2.SetValue (Storyboard.TargetNameProperty, myRect.Name)
myStoryboard2.Begin()
storyboard2Active = True
ElseIf Not storyboard3Active Then
myStoryboard3.Stop()
myDoubleAnimation3.SetValue (Storyboard.TargetNameProperty, myRect.Name)
myStoryboard3.Begin()
storyboard3Active = True
End If
End Sub
Private Sub Storyboard_Completed(ByVal sender As Object, ByVal e As EventArgs)
Dim myStoryboard As Storyboard = CType(sender, Storyboard)
Select Case (myStoryboard.GetValue (NameProperty).ToString)
Case “myStoryboard1”
storyboard1Active = False
Case “myStoryboard2”
storyboard2Active = False
Case “myStoryboard3”
storyboard3Active = False
End Select
End Sub
在上面的示例中,同时只能运行三个动画(等于 Storyboard 对象的数目)。 如果您不需要同时运行更多动画,这个示例就可以满足要求了,否则将需要更多 的 Storyboard 对象。如果要同时运行很多独立的动画,可能要动态创建 Storyboard 对象。有关在代码中创建演示图板对象的示例,请参见下一节。
在程序代码中创建动画
您还可以完全在程序代码中创建动画。下面的示例演示如何创建一个动画,在 其中用动画呈现矩形的 Canvas.Top 和 Canvas.Left 附加属性。
运行此示例:http://go.microsoft.com/fwlink/? LinkId=139798&sref=programmatic_animation
VB
Private Sub Create_And_Run_Animation(ByVal sender As Object, ByVal e As EventArgs)
' Create a red rectangle that will be the target
' of the animation.
Dim myRectangle As Rectangle = New Rectangle
myRectangle.Width = 200
myRectangle.Height = 200
Dim myColor As Color = Color.FromArgb(255, 255, 0, 0)
Dim myBrush As SolidColorBrush = New SolidColorBrush
myBrush.Color = myColor
myRectangle.Fill = myBrush
' Add the rectangle to the tree.
LayoutRoot.Children.Add(myRectangle)
' Create a duration of 2 seconds.
Dim duration As Duration = New Duration (TimeSpan.FromSeconds(2))
' Create two DoubleAnimations and set their properties.
Dim myDoubleAnimation1 As DoubleAnimation = New DoubleAnimation
Dim myDoubleAnimation2 As DoubleAnimation = New DoubleAnimation
myDoubleAnimation1.Duration = duration
myDoubleAnimation2.Duration = duration
Dim sb As Storyboard = New Storyboard
sb.Duration = duration
sb.Children.Add(myDoubleAnimation1)
sb.Children.Add(myDoubleAnimation2)
Storyboard.SetTarget(myDoubleAnimation1, myRectangle)
Storyboard.SetTarget(myDoubleAnimation2, myRectangle)
' Set the attached properties of Canvas.Left and Canvas.Top
' to be the target properties of the two respective DoubleAnimations
Storyboard.SetTargetProperty(myDoubleAnimation1, New PropertyPath(“(Canvas.Left)”))
Storyboard.SetTargetProperty(myDoubleAnimation2, New PropertyPath(“(Canvas.Top)”))
myDoubleAnimation1.To = 200
myDoubleAnimation2.To = 200
' Make the Storyboard a resource.
LayoutRoot.Resources.Add(“unique_id”, sb)
' Begin the animation.
sb.Begin()
End Sub
注意说明:
不要试图在页面的构造函数中调用 Storyboard 成员(例如 Begin 方法)。 这将导致动画失败,且无任何提示。
篇7:iOS开发中MVC、MVVM模式详解
iOS中的MVC(Model-View-Controller)将软件系统分为Model、View、Controller三部分
Model: 你的应用本质上是什么(但不是它的展示方式) Controller:你的Model怎样展示给用户(UI逻辑) View:用户看到的,被Controller操纵着的
Controller可以直接访问Model,也可以直接控制View, 但Model和View不能互相通信。
View可以通过action-target的方式访问Controller,比如我们在StoryBoard中拖UIButton到代码中所创建的@IBAction,当按钮被点击时,View就会传递该信息给Controller。 有时候Controller需要实时监控View的状态,这时Controller会通过protocol将其自身设为View的delegate,这样当View will change、should change、did change 的时候Controller也会接到相应通知。 View不存储数据,但View可以通过协议获取Controller而不是Model中的数据用来展示。 Controller整理Model中的数据用于给View展示。
Model不能直接与Controller通讯,因为Model是独立于UI存在的。 但当Model发生改变想通知Controller时可使用广播机制,在iOS中有NSNotification和KVO(Key-value observing)可供使用。
NSNotification:
letcenter =NSNotificationCenter.defaultCenter()
center.addObserverForName(UIContentSizeCategoryDidChangeNotification,
object:UIApplication.sharedApplication(),
queue:NSOperationQueue.mainQueue())
{ notificationin
letc = notification.userInfo?[UIContentSizeCategoryNewValueKey]}
UIContentSizeCategoryDidChangeNotification以及UIContentSizeCategoryNewValueKey均为系统中定义好的String
KVO:
在ViewDidLoad中:webView.addObserver(self, forKeyPath:estimatedProgress, options: .New, context:nil)
overridefuncobserveValueForKeyPath(keyPath:String?, ofObject object:AnyObject?, change: [NSObject:AnyObject]?, context:UnsafeMutablePointer
MVP模式从经典的MVC模式演变而来,将Controller替换成Presenter,依据MVP百度百科中的解释,MVP的优点相比较于MVC是完全分离Model与View,Model与View的信息传递只能通过Controller/Presenter,我查阅资料发现在其他平台上的MVC模式View与Model能否直接通讯有着不同的说法,但在iOS开发中,Apple是这么说的,
在MVC下,所有的对象被归类为一个model,一个view,或一个controller。Model持有数据,View显示与用户交互的界面,而View Controller调解Model和View之间的交互,在iOS开发中我按照Model与View无法相互通讯来理解。
MVVM(Model View View-Model)
上图展示了MVVM与MVC的差别。
在MVC模式的iOS开发中,Controller承担了太多的代码,包含着我们的视图处理逻辑和业务逻辑。
在MVVM中,我们将视图处理逻辑从C中剥离出来给V,剩下的业务逻辑部分被称做View-Model。 使用MVVM模式的iOS应用的可测试性要好于MVC,因为ViewModel中并不包含对View的更新,相比于MVC,减轻了Controller的负担,使功能划分更加合理。
MVVM模式的正确实践是,我们应该为app delegate的根视图创建一个ViewModel,当我们要生成或展示另一个次级ViewController时,采用当前的ViewModel为其创建一个子ViewModel。
而这些ViewModel的代码并不放在ViewController中,我们的View请求自己的ViewModel来获取所需的数据,ViewController完全归于View。
篇8:Python中关于使用模块的基础知识
这篇文章主要介绍了Python中关于使用模块的基础知识,是Python入门的基础,需要的朋友可以参考下
一个模块可以在逻辑上组织Python代码,将相关的代码到一个模块中,使代码更容易理解和使用。模块是可以绑定和借鉴任意命名属性的Python对象。
简单地说,一个模块是由Python代码的文件。一个模块可以定义函数,类和变量。模块还可以包括可运行的代码。
例子:
Python代码的模块名为aname通常位于一个名为aname.py。下面是一个简单的模块,support.py作为例子
def print_func( par ): print “Hello : ”, par return
import语句:
可以通过在其他一些Python源文件执行import语句来使用任何Python源文件作为一个模块。import的语法如下:
import module1[, module2[,... moduleN]
当解释器遇到import语句,它导入(import)模块如果模块出现在搜索路径。搜索路径是一个目录列表,该解释器导入模块之前搜索。例如,导入模块hello.py,需要把下面的命令在脚本的顶部:
#!/usr/bin/python# Import module supportimport support# Now you can call defined function that module as followssupport.print_func(“Zara”)
当执行上面的代码,产生以下结果:
Hello : Zara
一个模块被加载一次,不管导入的次数。这可防止模块执行发生多次导入。
from...import 语句
Python的from语句可以从一个模块中导入特定的属性到当前的命名空间。from...import 语法如下:
from modname import name1[, name2[, ... nameN]]
例如,从模块fib导入函数fibonacci,使用下面的语句:
from fib import fibonacci
此语句不导入整个模块fib到当前的命名空间;它只是介绍了fibonacci从模块fib导入模块的全局符号表列。
from...import * 语句:
它也可以通过使用下面的import语句导入从模块到当前的命名空间的所有名称:
from modname import *
这提供了导入从模块到当前的命名空间中的所有项目一个简单的方法;不过,这个语句应谨慎使用。
定位模块:
当导入一个模块,在下列序列模块由Python解释器搜索:
当前目录
如果未找到该模块,然后Python搜索在shell变量PYTHONPATH每个目录
如果这些方法都失败,Python会检查默认路径。在UNIX上,默认路径是正常是/usr/local/lib/python/
模块搜索路径被存储在系统模块sys作为所述的sys.path变量。在sys.path的变量包含当前目录,PYTHONPATH和相关的默认安装。
PYTHONPATH变量:
在PYTHONPATH是一个环境变量,包括目录列表中。 PYTHONPATH的语法shell变量PATH相同。
下面是Windows系统的典型PYTHONPATH:
set PYTHONPATH=c:python20lib;
这里是UNIX系统的典型PYTHONPATH:
set PYTHONPATH=/usr/local/lib/python
命名空间和作用域:
变量名称(标识)映射到对象。名称空间是变量名(键)及其相应的对象(的值)的字典。
Python语句可以在本地命名空间和全局命名空间访问变量。如果局部和全局变量同名,局部变量屏蔽全局变量。
每个函数都有自己的命名空间。类方法遵循相同的作用域规则为普通函数。
Python对变量是否为局部或全局进行假定猜测。它假定任何变量赋值函数中的值是局部的。
因此为了使一个函数内的值赋给一个全局变量,必须先使用global语句,
声明 global VarName 告诉Python VarName是一个全局变量。Python 停止寻找该变量的局部命名空间。
例如,我们在全局命名空间中定义的变量Money 。在该函数的Money ,我们给定Money 的值,因此Python 假定Money 为局部变量。但是,我们设定它,所以一个UnboundLocalError是结果之前访问的局部变量Money 的值。取消global语句解决了这个问题。
#!/usr/bin/pythonMoney = def AddMoney: # Uncomment the following line to fix the code: # global Money Money = Money + 1print MoneyAddMoney()print Money
dir( ) 函数:
使用dir()内置函数返回一个包含一个模块中定义名称的字符串的排序列表。
该列表包含在一个模块中定义的所有模块,变量和函数的名称。下面是一个简单的例子:
#!/usr/bin/python# Import built-in module mathimport mathcontent = dir(math)print content;当执行上面的代码,产生以下结果:[‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘acos‘, ‘asin‘, ‘atan‘, ‘atan2‘, ‘ceil‘, ‘cos‘, ‘cosh‘, ‘degrees‘, ‘e‘, ‘exp‘, ‘fabs‘, ‘floor‘, ‘fmod‘, ‘frexp‘, ‘hypot‘, ‘ldexp‘, ‘log‘,‘log10‘, ‘modf‘, ‘pi‘, ‘pow‘, ‘radians‘, ‘sin‘, ‘sinh‘, ‘sqrt‘, ‘tan‘, ‘tanh‘]
在这里,特殊字符串变量__name__是模块的名称,__file__是从中加载的模块的文件名。
globals()和 locals()函数:
globals() 和 locals() 函数可用于返回在根据在它们被称为位置的全局和局部名称空间的名称。
如果locals()被一个函数中调用时,它会返回所有可以在局部从函数访问的名称。
如果globals()从一个函数中调用时,它会返回所有可以从全局函数进行访问的名称。
这两个函数的返回类型是字典。因此,名称可以使用keys()函数提取出来。
reload()函数:
当该模块被导入到一个脚本,在一个模块的顶层部分的代码只执行一次。
因此,如果你想重新执行的顶级代码模块中,可以使用reload()函数。reload()函数导入先前导入的模块了。reload()函数的语法是这样的:
reload(module_name)
在这里,module_name是要重装,不包含模块名字符串的模块的名称。例如,要重新加载hello模块,请执行以下操作:
reload(hello)
Python中的包:
包是用于定义由模块和子包和子子包等的单一的Python应用环境的分层文件目录结构。
考虑一个文件Pots.py在Phone目录中可用。此文件的源代码如下一行:
#!/usr/bin/pythondef Pots(): print “I‘m Pots Phone”
类似的方法,我们具有不同功能的另两个文件具有相同的名称如上:
Phone/Isdn.py文件有函数 Isdn()
Phone/G3.py 文件有函数 G3()
现在,创建在Phone目录中多了一个文件__init__.py:
Phone/__init__.py
为了让所有的功能可用,当导入Phone,需要把__init__.py明确的import语句如下:
from Pots import Potsfrom Isdn import Isdnfrom G3 import G3
当添加完这些行到__init__.py,那么已经导入了Phone包所有这些类的使用。
#!/usr/bin/python# Now import your Phone Package.import PhonePhone.Pots()Phone.Isdn()Phone.G3()
当执行上面的代码,产生以下结果:
I‘m Pots PhoneI‘m 3G PhoneI‘m ISDN Phone
在上面的例子我们采取示例每个文件单个函数,但可以保留文件中多个函数。还可以在这些文件定义不同的Python类,可以在包外创建那些类。
篇9:使用MEF构建可扩展的Silverlight应用
“托管扩展性框架(Managed Extensibility Framework,简称MEF),是微软 .NET框架下为提高应用和组件复用程度而推出的,用于使组件能够最大化的重用 ,使用MEF能够使静态编译的.NET应用程序转换为动态组合,这将是创建可扩展应 用、可扩展框架和应用扩展的好途径。它将做为.NET Framework 4.0的组成部分 之一发布。现在,MEF也将被包含在Silverlight 4.0中。
那么MEF是怎样工作的呢?简单分为三个步骤:
Export (输出)
Import (输入)
Compose (组合)
简短说一下MEF的工作原理,MEF的核心包括一个catalog和一个 CompositionContainer。category用于发现扩展,而container用于协调创建和梳 理依赖性。每个可组合的Part提供了一个或多个Export,并且通常依赖于一个或 多个外部提供的服务或 Import。每个Part管理一个实例为应用程序运行。
下面我们做一个小型可扩展计算器示例来解释这三个过程
1.首先下载MEF框架包,Silverlight 4.0会自带,不过微软已经将其开源了。
http://www.codeplex.com/MEF
2.创建一个Silverlight Navigate Application ,并添加程序集引用 (MEF_Beta_2binSL目录下 System.ComponentModel.Composition.dll)
在项目下添加两个类文件Package.cs和PackageCatalog.cs,这两个文件在最 新的MEF版本中没有提供,主要用于加载silverlight的Xap包。
这两个文件在MEF框架的Sample中提供了(MEF_Beta_2 SamplesPictureViewerpic.ruiwen.common),将这两个类的访问修饰符改 为public, 添加后注意修改命名空间。
3.修改Home.cs 类
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using System.ComponentModel;
namespace MefDemo
{
//用于更新界面的委托
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
///
/// 加法运算器
///
[Export(typeof(IOperate))]
public class AddButton : Button, IOperate
{
[Import (“AddButtonContract”,AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“AddSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left + right;
}
#endregion
public AddButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 减法运算器
///
[Export(typeof(IOperate))]
public class SubButton : Button, IOperate
{
[Import (“SubButtonContract”,AllowRecomposition=true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“SubSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left - right;
}
#endregion
public SubButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 为每个运算器的属性提供值
///
public class ComponentAttributeProvider
{
[Export(“AddButtonContract”)]
public string AddLabel { get { return “Add”; } }
[Export(“AddSybomContract”)]
public string AddSymbol { get { return “+”; } }
[Export(“SubButtonContract”)]
public string SubLabel { get { return “Sub”; } }
[Export(“SubSybomContract”)]
public string SubSymbol { get { return “-”; } }
}
}
4.修改 Home.xaml
代码
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”
xmlns:navigation=“clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navi gation”
mc:Ignorable=“d” d:DesignWidth=“640” d:DesignHeight=“480”
Title=“Home”
Style=“{StaticResource PageStyle}”>
5.新建类 OperatorComponent.cs
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using System.ComponentModel;
namespace MefDemo
{
//用于更新界面的委托
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
///
/// 加法运算器
///
[Export(typeof(IOperate))]
public class AddButton : Button, IOperate
{
[Import (“AddButtonContract”,AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“AddSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left + right;
}
#endregion
public AddButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 减法运算器
///
[Export(typeof(IOperate))]
public class SubButton : Button, IOperate
{
[Import (“SubButtonContract”,AllowRecomposition=true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“SubSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left - right;
}
#endregion
public SubButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 为每个运算器的属性提供值
///
public class ComponentAttributeProvider
{
[Export(“AddButtonContract”)]
public string AddLabel { get { return “Add”; } }
[Export(“AddSybomContract”)]
public string AddSymbol { get { return “+”; } }
[Export(“SubButtonContract”)]
public string SubLabel { get { return “Sub”; } }
[Export(“SubSybomContract”)]
public string SubSymbol { get { return “-”; } }
}
}
6.运行,
这样就构建了一个简单的运算器,其中的Export、Import就像一个 个管道一样相互连接。
# 按照这样的设计,我们想要对其进行扩展,就必须把接口分离。新建一个 Silverlight ClassLibrary Project(Named ContractLibrary),这个Library用来 封装所有的扩展接口,定义Import/Export契约。
现在把原项目中的OperatorComponent.cs 类中的接口迁移到Library项目中, 新建类文件OperateContract.cs 。
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ContractLibrary
{
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
}
编译通过后在Silverlight主工程(MefDemo)中添加对ContractLibrary项目的 引用
# 再新建一个Silverlight ClassLibrary Project (Named StaticExtension),,这个工程就是我们用来静态扩展的DLL。
a).在工程下新建我们的运算器类,AddButton.cs , SubButton.cs.(代码不变 ).
b).但注意要添加对ContractLibrary项目的引用和MEF的框架集引用) 。
c).添加全局属性配置类(ComponentConfiguration.cs)
d).删除主工程中的ComponetOperater.cs.
e).添加对StaticExtension的引用.
OK,这样我们就可以任意扩展运算器,添加更多的扩展运算了。
那么下面是添加一个新的乘法运算所要做的工作。
在StaticExtension中添加新类 Multiply.cs
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using ContractLibrary;
namespace StaticExtension
{
///
/// 乘法运算器
///
[Export(typeof(IOperate))]
public class MultiplyButton : Button, IOperate
{
[Import(“MultiplyButtonContract”, AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“MultiplySybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left * right;
}
#endregion
public MultiplyButton()
{
this.Click += (s, e) => ClickAction (this);
}
}
}
# 上面的是静态加载,那么现在我们使用MEF实现动态扩展运算器。桌面程序 的动态扩展是动态加载DLL,而对于Silverlight的Web程序则是动态加载Xap包了 。
新建普通Silverlight Application(Named DynamicExtension).
11.去掉勾选Add a test page that references the application.
1).删掉App和Main等不必要的文件,只留一个空的Silverlight项目,以减少 Xap包的大小。
2).添加ContractLibrary和MEF框架集的引用(可以将引用程序集属性 CopyLocal设置为false,因为我们在主工程中已经添加了,可以重用)
3).添加类Division.cs.
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using ContractLibrary;
namespace DynamicExtension
{
///
/// 乘法运算器
///
[Export(typeof(IOperate))]
public class DivisionButton : Button, IOperate
{
[Import(“DivisionButtonContract”, AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“DivisionSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left * right;
}
#endregion
public DivisionButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
}
4).添加配置类ComponentConfiguration.cs
代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
namespace DynamicExtension
{
///
/// 为每个运算器的属性配置值
///
public class ComponentConfiguration
{
[Export(“DivisionButtonContract”)]
public string AddLabel { get { return “Div”; } }
[Export(“DivisionSybomContract”)]
public string AddSymbol { get { return “/”; } }
}
}
5).修改Home.cs ,为其注册下载包的相关事件和回调
1.代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.ComponentModel.Composition;
using ContractLibrary;
namespace MefDemo
{
public partial class Home : Page
{
[ImportMany(typeof (IOperate),AllowRecomposition = true)]
public ObservableCollection
[Export(“ClickHandler”)]
public OperateHandler ClickHandler { get { return OperateButton_Click; } }
private PackageCatalog Catalog;
///
/// 用于界面控件响应运算后的一些更新工 作
///
///
Ok,最终界面。
点击DynamicLoadOperate按钮后
程序中还有很多细节没有展开说明,理论性的介绍可以参考MSDN和CodePlex上 的文档。
源码下载:http://download.csdn.net/source/2062158
★ 年终总结程序员
★ Expression Blend实例中文教程 控件快速入门ControlTempla
★ 程序员年终总结
【Silverlight中使用MVVM基础(合集9篇)】相关文章:
软件开题报告2023-07-04
项目管理工程硕士开题报告2023-10-23
ntlm验证机制学习札记2022-12-12
前端架构师的岗位职责2022-12-21
ios项目总结怎么写2022-12-04
Silverlight游戏设计:(五)面向对象的思想塑造游戏对象2022-11-21
图形的变换课件2022-05-24
六年级上册《图形的变换》说课稿2022-09-19
.net面试项目介绍范文2022-11-16
如何屏蔽弹出的广告窗口2022-10-19