這一篇到MVVM了,心里很是忐忑,聽說MVVM很長時間了但是一直也沒有真正用過,兩年前做Silverlight那會項目里也沒怎么用,而且那時候還沒有windows phone和win8,所以也沒太在意,悔不當初啊。這一篇我就多用代碼實例說話,少用描述性的文字,以免誤人子弟。
打開前幾篇的代碼,上一篇我們把json轉換成了實體類中的數據並且用彈出框顯示了一下,那么怎么顯示到界面上呢,也許會這么做
1 HttpClient hc = new HttpClient(); 2 var task = await hc.GetAsync("http://www.weather.com.cn/data/cityinfo/101010100.html"); 3 string result = await task.Content.ReadAsStringAsync(); 4 JObject obj = JObject.Parse(result); 5 WeatherModel1 details = (WeatherModel1)JsonConvert.DeserializeObject(obj["weatherinfo"].ToString(), typeof(WeatherModel1)); 6 this.DataContext = details;
在頁面里面這樣
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 2 <Button Content="Button" HorizontalAlignment="Left" Margin="137,103,0,0" VerticalAlignment="Top" Click="Button_Click"/> 3 <TextBlock HorizontalAlignment="Left" Margin="119,265,0,0" TextWrapping="Wrap" Text="{Binding city}" VerticalAlignment="Top"/> 4 5 </Grid>
可以顯示沒問題,但是太丑陋了,要在code-behid里寫很多代碼,搞的顯示和邏輯混亂不堪,刷新一次請求就要重新綁定一次頁面的DataContext,而且這個DataContext要是新的引用(也就是說要重新new一個model出來)顯示上才會刷新。下面我們引入ViewModel
新建一個類叫WeatherViewModel
1 public class WeatherViewModel : INotifyPropertyChanged 2 { 3 //public WeatherViewModel() 4 //{ 5 // if (updateCmd == null) 6 // { 7 // updateCmd = new UpdateCmd(this); 8 // } 9 //} 10 public event PropertyChangedEventHandler PropertyChanged; 11 //public ICommand updateCmd { get; private set; } 12 private string _city; 13 public string city 14 { 15 get 16 { 17 return _city; 18 } 19 set 20 { 21 _city = value; 22 if (PropertyChanged != null) 23 { 24 PropertyChanged(this, new PropertyChangedEventArgs("city")); 25 } 26 } 27 } 28 }
里面有幾行注釋掉的代碼,不用管它那是一會要用的。這個類實現了INotifyPropertyChanged接口,它的作用就是通知UI屬性變更了,UI知道后就會重新調用屬性的get獲取。
下面幾個地方我們這么改,打開app.xaml,找到添加資源的<Application.Resources>標簽,對,就是添加動畫那里。然后在里面添加下面代碼
<my:WeatherViewModel xmlns:my="clr-namespace:PhoneApp3" x:Key="weather"/>
在頁面的頭部添加DataContext="{StaticResource weather}"
把最開始寫在code-behind里的this.DataContext = details改成((WeatherViewModel)this.DataContext).city = details.city;
一樣可以顯示,而且我們只是給屬性重新賦值了。不過codebehind里的代碼還是太多,層次還是不清晰,需要繼續改造。不在code-behind里響應點擊事件,改用command
新建一個類就叫UpdateCmd
1 public class UpdateCmd : ICommand 2 { 3 private WeatherViewModel _weather; 4 public UpdateCmd(WeatherViewModel weather) 5 { 6 _weather = weather; 7 } 8 public bool CanExecute(object parameter) 9 { 10 if (parameter != null) 11 { 12 CanExecuteChanged(parameter, new EventArgs()); 13 } 14 return true; 15 16 //throw new NotImplementedException(); 17 } 18 19 public event EventHandler CanExecuteChanged; 20 21 public async void Execute(object parameter) 22 { 23 //System.Windows.MessageBox.Show("a"); 24 //throw new NotImplementedException(); 25 HttpClient hc = new HttpClient(); 26 var task = await hc.GetAsync("http://www.weather.com.cn/data/cityinfo/101010100.html"); 27 string result = await task.Content.ReadAsStringAsync(); 28 JObject obj = JObject.Parse(result); 29 WeatherModel1 details = (WeatherModel1)JsonConvert.DeserializeObject(obj["weatherinfo"].ToString(), typeof(WeatherModel1)); 30 _weather.city = details.city; 31 } 32 }
把WeatherViewModel里注釋的代碼打開。把xaml中button的click換成command
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 2 <Button Content="Button" HorizontalAlignment="Left" Margin="137,103,0,0" VerticalAlignment="Top" Command="{Binding updateCmd}"/> 3 <TextBlock HorizontalAlignment="Left" Margin="119,265,0,0" TextWrapping="Wrap" Text="{Binding city}" VerticalAlignment="Top"/> 4 </Grid>
現在我們可以把code-behind里所有不是自帶的,前幾篇添加的代碼全部注釋掉了。測試一下看看,我們沒有在code-behind里寫一句代碼就實現了數據的顯示。而且我們也完成了view-view model-model分層。上面的代碼里,Command中Excute部分也應該提取出來成為service。
關於INotifyPropertyChanged和ICommand更多的信息感興趣的還是baidu吧,我就不這里獻丑了,網上還是很多的。今天這篇就到這,下一篇簡單應用一下DependencyProperty。