昨天逛論壇,看到一個哥們用WPF做了一個9宮的拼圖游戲,發現初學WPF的人都很容易犯一個錯誤(我也犯過):把WPF當WINFORM用!所以想寫一個比較符合WPF風格的版本,於是就抽工作的空余時間做了一個,其實就是很久沒寫博客了,寫個出來湊數o(╯□╰)o。效果如下:

(圖片為:阿普利亞GPR125)
代碼簡要解釋:主窗口,只是生成核心類,和綁定主要事件(比較簡單,就沒有使用什么Command之類的了),主要邏輯都在VM類里面
public partial class MainWindow : Window { PicManager manager; public MainWindow() { InitializeComponent(); manager = new PicManager("", 3, 3); } private void Window_Loaded(object sender, RoutedEventArgs e) { DataContext = manager; } private void Kong_KeyDown(object sender, KeyEventArgs e) { switch(e.Key) { case Key.Up: manager.MovePic(Direction.D_Up); break; case Key.Down: manager.MovePic(Direction.D_Down); break; case Key.Left: manager.MovePic(Direction.D_Left); break; case Key.Right: manager.MovePic(Direction.D_Right); break; case Key.R: manager.Random(50); break; } if (manager.Step!=0&&manager.CheckOVER()) { MessageBox.Show("YOU WIN!"); manager.Step = 0; } } }
PicModel:小拼圖模型類,只有一個ID,用於保存數據。
class PicMod { public int ID { set; get; } public PicMod(int i) { ID = i; } }
PicViewMod:是每一個小拼圖model的視圖viewmodel封裝類,當小拼圖ID變化,會通過WPF的綁定功能,自動更新界面的圖片,而不是用事件去刷新重繪!這是WPF和WINFROM之間的一個最大區別!
class PicViewMod : INotifyPropertyChanged { PicMod pic; public event PropertyChangedEventHandler PropertyChanged; public PicViewMod(int i) { pic = new PicMod(i); } public int ID { set { if (pic.ID != value) { pic.ID = value; PropertyChanged(this, new PropertyChangedEventArgs("ID")); } } get { return pic.ID; } } }
PicManager :主要封裝了9個小拼圖塊,和一些操作函數,包括移動塊,生成隨機拼圖(只是循環模擬調用了移動塊的函數)
//拼圖面板VM class PicManager : INotifyPropertyChanged { public ObservableCollection<PicViewMod> Pics { set; get; } public event PropertyChangedEventHandler PropertyChanged; int _step; int _pos;//空白塊當前位置 int _colum, _row;//行列數 public int Step { set { if (_step != value) { _step = value; PropertyChanged(this, new PropertyChangedEventArgs("Step")); } } get { return _step; } } public PicViewMod Ori { set; get; }//原圖 public PicManager(string path, int col, int row) { Pics = new ObservableCollection<PicViewMod>(); _colum = col; _row = row; _pos = 0; _step = 0; Ori = new PicViewMod(col * row); for (int x = 0; x < _colum; x++) { for (int y = 0; y < _row; y++) { Pics.Add(new PicViewMod(x * _row + y)); } } } void ClipPic(string path) { } public void MovePic(Direction dir) { switch (dir) { case Direction.D_Up://鍵盤的向上,實際就是空白塊的向下 { if (_pos / _colum < _row - 1) { int id = Pics[_pos + _colum].ID; Pics[_pos + _colum].ID = Pics[_pos].ID; Pics[_pos].ID = id; _pos += _colum; Step++; } } break; case Direction.D_Down: { if (_pos / _colum > 0) { int id = Pics[_pos - _colum].ID; Pics[_pos - _colum].ID = Pics[_pos].ID; Pics[_pos].ID = id; _pos -= _colum; Step++; } } break; case Direction.D_Left: { if (_pos % _colum < _colum - 1) { int id = Pics[_pos + 1].ID; Pics[_pos + 1].ID = Pics[_pos].ID; Pics[_pos].ID = id; _pos += 1; Step++; } } break; case Direction.D_Right: { if (_pos % _colum > 0) { int id = Pics[_pos - 1].ID; Pics[_pos - 1].ID = Pics[_pos].ID; Pics[_pos].ID = id; _pos -= 1; Step++; } } break; } } public bool CheckOVER() { for (int i = 0; i < _row * _colum; i++) { if (Pics[i].ID != i) return false; } return true; }
public void Random(int count) { System.Random rand = new System.Random((int)DateTime.Now.Ticks); for (int i = 0; i < count; i++) { int d = rand.Next(0, 4); MovePic((Direction)d); } Step = 0; } } }
VIEW的XAML定義:使用ItemsContrl來展示Image
<Window x:Class="NineKong.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:NineKong" Title="拼圖游戲" Height="494" Width="849" Loaded="Window_Loaded" KeyDown="Kong_KeyDown"> <Window.Resources> <local:DataConverter x:Key="conver"></local:DataConverter> </Window.Resources> <Canvas Name ="Kong"> <ItemsControl Height="454" Width="607" Name ="Nine" ItemsSource="{Binding Pics}" Background="Cyan"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel ItemHeight="135" ItemWidth="200"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Image Margin="2" Source="{Binding ID,Converter={StaticResource conver}}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <Image Height="145" Width="219" Canvas.Left="612" Source="{Binding Ori.ID ,Converter={StaticResource conver}}" Canvas.Top="10"/> <TextBlock Canvas.Left="726" TextWrapping="Wrap" Text="{Binding Step}" FontSize="35" Canvas.Top="160" Width="105" Height="42"/> </Canvas> </Window>
其他具體實現請查看源代碼,代碼比較簡單,所以並沒有什么注釋。總的來說個人覺得WINFORM和WPF的主要差別:一個是事件驅動,一個是數據驅動!由於時間比較倉促,然后對WPF其實也不是很熟練(很早以前自學過2個月,然后基本沒用過了,其實這是寫的第一個比較完整的WPF程序),很多東西概念知道,但是真的用起來發現比較吃力,邊百度邊實驗,對圖片的操作和GDI+模式差別比較大,所以沒有實現通過指定的圖片按指定大小切圖來自定義游戲。。。不過這篇博客主要是想演示一下WPF和WINFORM差別,真的非常大!所以也就不要太在意某些細節。。。
九宮拼圖源碼 下載
