9宮拼圖小游戲(WPF MVVM實現)


  昨天逛論壇,看到一個哥們用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差別,真的非常大!所以也就不要太在意某些細節。。。

 

九宮拼圖源碼 下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM