小试MVVM(1)
时间:2010-09-26 来源:DarthVader
这几天偶染小恙,今天继续MVVM。
1、创建工程
首先先用VS2010新建一个Silverlight Application,
不要建立一个新的Web站点,我们使用OOB
然后更改工程的属性,添加OOB支持并增加信任权限,
此时在VS中F5运行,不会启动浏览器,而是直接以OOB方式启动应用。
2、设计界面
用Blend打开工程(为什么用Blend,因为MVVM的主要目标就是分离UI和UI逻辑,UI由美工设计,UI逻辑由程序员完成,这样就避免了程序员设计界面或者美工设计程序的苦恼),然后在工程中添加"UserControl with ViewModel",文件名改为FeedsView.xaml,
这个View用于显示每个订阅的名称。同理添加FeedItemsView用于显示每个订阅的新闻标题。
编译工程,打开MainPage.xaml,在Assets页中找到Locations->SilverReader.xap,
可以看见右侧显示了3个UserControl,把FeedsView和FeedsItemsView拖到MainPage中,然后调整一下布局,下面是XAML代码:
MainPage.xaml<UserControl
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:local="clr-namespace:SilverReader" x:Class="SilverReader.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<local:FeedsView/>
<local:FeedItemsView Grid.Column="1"/>
</Grid>
</UserControl>
我只是简单的使用了左右布局,MainPage不是主要的UI,充其量算UI的一个容器,真正的UI设计是在其他的两个View中。
3、FeedsView
下面是FeedsView的设计界面,
对象结构如下:
在第一行有一个Button用于显示第二行的UI,第二行包括一个TextBox用于输入RSS的网址和一个Button,第三行只是一个简单的ListBox,显示我们订阅的RSS标题。第二行平时应该是隐藏的,只有点击的第一行的Button后才应该显示,所以更改第二行的Grid的Visibility属性的值为Collapsed。
下一步要添加"添加订阅"Button的行为,当点击Button时,第二行的TextBox和Button能够显示,也就是将上述的Visibility属性改为Visible。以前的方法是直接双击Button,然后在后台代码中编写事件响应函数。现在依赖Blend的Behaviors,不用写一行代码就可以做到了。
首先在Blend的Assets中选择Behaviors->ChangePropertyAction,拖到"添加订阅"Button上,
然后设置Action的属性,TargetObject为第二行的Grid,PropertyName为Visibility,Value为Visible。
4、FeedsViewModel
下面就该ViewModel了,现在的ViewModel中还没有任何东西,先添加一个Feed的集合,还要让ViewModel实现INotifyPropertyChanged接口,代码如下:
FeedsViewModelpublic class FeedsViewModel : INotifyPropertyChanged
{
public ObservableCollection<SyndicationFeed> Feeds { get; private set; }
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
5、添加设计数据
在Blend中选择Data页,添加一个新的Sample Data,
选择FeedsViewModel类,在工程中添加FeedsViewModelSampleData.xaml,
6、显示Feed标题
在FeedsView中的ListBox下添加ItemTemplate,用一个TextBox显示Title.Text,代码如下:
代码<ListBox Grid.Row="2" ItemsSource="{Binding Feeds}">
<ListBox.Resources>
<DataTemplate x:Key="ListItemTitleTemplate">
<StackPanel>
<TextBlock TextWrapping="Wrap" Text="{Binding Title.Text, Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<StaticResource ResourceKey="ListItemTitleTemplate"/>
</ListBox.ItemTemplate>
</ListBox>
然后选择"LayoutRoot"Grid,设置DataContent:
此时在设计界面就可以看见显示的结果了。
7、添加命令
在FeedsView中的"添加"Button下添加InvokeCommandAction,绑定Action的Command属性为AddFeedCommand
绑定Action的CommandParameter属性为TextBox的Text属性
然后在FeedsViewModel中添加如下代码:
代码public FeedsViewModel()
{
Feeds = new ObservableCollection<SyndicationFeed>();
AddFeedCommand = new ActionCommand(delegate(object o)
{
string url = (string) o;
Uri feedUri;
Uri.TryCreate(url, UriKind.Absolute, out feedUri);
if (feedUri == null)
return;
WebClient request = new WebClient();
request.DownloadStringCompleted +=
delegate(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
string xml = e.Result;
if (xml.Length == 0)
return;
StringReader stringReader = new StringReader(xml);
XmlReader reader = XmlReader.Create(stringReader);
SyndicationFeed feed = SyndicationFeed.Load(reader);
if (Feeds.Where(f => f.Title.Text == feed.Title.Text).ToList().Count > 0)
return;
Feeds.Add(feed);
};
request.DownloadStringAsync(feedUri);
});
}
public ObservableCollection<SyndicationFeed> Feeds { get; private set; }
public ICommand AddFeedCommand { get; private set; }
最后,看一下运行效果(从VS2010中启动)
8、总结
MVVM模式的主要要点:
- View的设计只是对XAML文件的编辑(通过GUI或者编辑器),没有后台代码,一般是由美工完成;
- ViewModel类直接对应View,View需要显示什么,ViewModel就提供什么,一般由程序员完成;
- ViewModel绑定到View的DataContent属性;
- 用户输入可以通过Blend提供的Behavior绑定到ViewModel上
- 通过d:DataContext和d:DesignData可以绑定设计时间数据,在设计器中就可以预览界面效果
实际上只是试验了MVVM中的V和VM,下一次结合FeedItemsView的实现试验Model。
源码可以从github上下载。