c# WPF help needed: How to show values from a object via WPF

[Edited 2019-02-23; I hope it is correct to edit the question]

I am complete newbie to WPF, and strugling. I have looked at alot of tutorials etc., but have not found the answer (in a way I understand).

I am building an Yatzy game, and the Yatzy class it self is almost complete. Now I would like to add a GUI using WPF to the yatzy class.

Thanks to the input from Reginald Blue answering v1 of my question. I am working on a view model.

Mark Whitall have made a good example, but I cant migrate it to my needs:

But it also troubles me. I hope that the code suplied are suffiecent, if not - ask :-)

It looks like my view model, has "contact" to my model. Thats super But regarding my view connecting to my viewmodel, something seems to be wrong.

What I would like to, as a start: 1) When Fields GameStatus and GameName should have default values from my model. Before making my viewmodel, that worked fine - but I have messed it up. I declare my thisYatzy object, in maincontrol.cs (in the viewmodel). Should I declare it at app.xaml level? 2) When I click on "button" ShiftState, I would call my viewmodel to shift state, and update the view. But from the view i cant call the viewmodel?

I hope that I have explained OK, and that someone of you can help :-)

VIEW:

app.xalm

<Application x:Class="WPFYatzy.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WPFYatzy"
             StartupUri="Views/MainWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>

app.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFYatzy.Views
{
    /// <summary>
    /// Interaction logic for Page1.xaml
    /// </summary>
    public partial class Page1 : Page
    {
        public Page1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
                 }
    }
}

mainwindow.xaml

<Window x:Class="MinimalMVVM.Views.ConvertWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Views="clr-namespace:WPFYatzy.Views"
        xmlns:ViewModels="clr-namespace:WPFYatzy.ViewModel"
        Title="YatzyGame - mainwindow"
        MinWidth="300"
        ResizeMode="NoResize"
        SizeToContent="WidthAndHeight">

    <Window.DataContext>
        <ViewModels:MainControl/>
    </Window.DataContext>

    <Views:Page1/>

</Window>

mainwindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using YatzyGameCL;

namespace WPFYatzy
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //YatzyGame thisYatzy = new YatzyGame();

        public MainWindow()
        {
            //InitializeComponent();
        }

        private void OnInit(object sender, EventArgs e)
        {

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {

        }
    }

}

page1.xaml

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFYatzy.Views
{
    /// <summary>
    /// Interaction logic for Page1.xaml
    /// </summary>
    public partial class Page1 : Page
    {
        public Page1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
                 }
    }
}

page1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFYatzy.Views
{
    /// <summary>
    /// Interaction logic for Page1.xaml
    /// </summary>
    public partial class Page1 : Page
    {
        public Page1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
                 }
    }
}

Viewmodel

ObservableObject.cs

using System.ComponentModel;

namespace WPFYatzy.ViewModel
{
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChangedEvent(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

DelegateCommand.cs

using System;
using System.Windows.Input;

namespace WPFYatzy.ViewModel
{
    public class DelegateCommand : ICommand
    {
        private readonly Action _action;

        public DelegateCommand(Action action)
        {
            _action = action;
        }

        public void Execute(object parameter)
        {
            _action();
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

#pragma warning disable 67
        public event EventHandler CanExecuteChanged { add { } remove { } }
#pragma warning restore 67
    }
}

MainControl.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using YatzyGameCL;

namespace WPFYatzy.ViewModel
{
    class MainControl : ObservableObject
    {
        private YatzyGame thisYatzy = new YatzyGame();

        private string _strGameName;
        private string _strGameStatus;

        public string GameName
        {
            get { return _strGameName; }
            set
            {
                _strGameName = value;
                RaisePropertyChangedEvent("GameName");
            }

        }

        public string GameStatus
        {
            get { return _strGameStatus; }
            set {
                _strGameStatus = value;
                RaisePropertyChangedEvent("GameStatus");
            }
        }

        public void ShiftState()
        {
            thisYatzy.GameStatus.NextAround();

            GameStatus = thisYatzy.GameStatus.ToString();

        }
    }
}

Model YatzyGameCL.DLL

Methods to be used to make the framework "hang together"

Upvotes: 0

Views: 547

Answers (1)

Reginald Blue
Reginald Blue

Reputation: 1002

This is going to be hard to express succinctly. You should go and read up on the MVVM (Model-View-ViewModel) pattern. While it's not strictly necessary to use MVVM with WPF, for what you're doing, it's really where you need to be.

Specifically:

You have a model created. That's your YatzyGame. It knows how Yatzy works, has all the rules. It's "the game".

You have a View. That's your XAML file (and the code behind). It knows how to draw a screen and it knows how to do updates if it's told about them.

But... you have no ViewModel. That's the bridge between the two worlds. It knows how to tell the view to update. Your model doesn't (and shouldn't) know how to do that, so the view (screen) never changes.

The very very specific answer to your question is that you need to send property change notifications so that the view knows that a property (e.g. GameStatus) has changed. You will be tempted to do that in your model. Don't do that.

Good luck!

Upvotes: 1

Related Questions