1

I am trying to make a simple Unity Standalone build launcher (for an arcade cabinet) - the setup is super-simple - joystick up and down highlights a game (in this case changing the fill colour of a rectangle and button1 lauches the correct game. I foolishly thought I could do this simply in wpf, but have stumbled at the first hurdle.

I have the keyboard input (the arcade joystick is setup through an i-pac2) working (focus lock on the mainwindow) and am changing an integer from 0-6. this works (hurray) through code on the MainWindow and is passed to a static int called position.

I then intend to have a series of rectangles that highlight based on this int value. I have been testing on a single rectangle - using dataTrigger to enact the change of state -but it doesn't update on the keyboard input. code snips...

  <Rectangle x:Name="gameRect01" Height="74" Margin="10,93,32.667,0" VerticalAlignment="Top" Grid.ColumnSpan="2" IsEnabled="False">
        <Rectangle.DataContext>
            <local:Launcher/>
        </Rectangle.DataContext>
        <Rectangle.Style>
            <Style TargetType="Rectangle">
                <Setter Property="Fill" Value="Red" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path = cursorPos, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" Value="1">
                        <Setter Property="Fill" Value="Green" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Rectangle.Style>

and the Launcher class...

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using System.ComponentModel;

    namespace GameLauncher 
    {
      class Launcher : INotifyPropertyChanged
      {
        public static int position = 0;

    public int cursorPos
    {
        get 
        { return position; 
        }
        set
        {
            cursorPos = position;
            RaisePropertyChanged("cursorPos");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
}

}

The XAML code seems to be binding with cursorPos - if I change the value in the binding, the rectangle changes fill.

The keyboard input is definitely changing the value of position but the value is not updating inside cursorPos.

I feel I'm missing something extremely simple, but cannot find anything that helps (I've been searching and trying attempting revisions over the last 3 nights without luck). I would really appreciate some pointers for someone new to this.

Thanks, Peter

Update I've updated the Launcher based on the feedback below to...

namespace GameLauncher 
{
class Launcher : INotifyPropertyChanged
{
    private int _position;

    public int cursorPos
    {
        get {
            return _position;
        }
        set {
            _position = value;
            RaisePropertyChanged(nameof(cursorPos));
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

and my keyboard input code looks like this...

namespace GameLauncher
{ 
public partial class MainWindow : Window
{
    Launcher launcher = new Launcher();
    private string gameGet;


    public MainWindow()
    {
        InitializeComponent();
        this.KeyDown += new KeyEventHandler(OnButtonKeyDown);

    }

    public void OnButtonKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Down || e.Key == Key.F) {
            launcher.cursorPos =  Math.Min(6, launcher.cursorPos + 1); Debug.WriteLine(launcher.cursorPos);
        }

        if (e.Key == Key.Up || e.Key == Key.R) {
            launcher.cursorPos = Math.Max(0, launcher.cursorPos - 1); Debug.WriteLine(launcher.cursorPos);
        }

        if (e.Key == Key.LeftCtrl || e.Key == Key.LeftAlt || e.Key == Key.A || e.Key == Key.S || e.Key == Key.D1 || e.Key == Key.D2){
         //   gameGet = "testGame";
        }

    }

    private void PlayButton_Click(object sender, RoutedEventArgs e)
    {
      //  Launcher.PlayGame("test");
    }
}

}

XAML code is the same, but its not updating - gah. The only thing I can think of now is that by instantiating the Launcher class to call in MainWindow isn't correct and I should be doing it another way?

Peter Freer
  • 11
  • 1
  • 3
  • 1
    The PropertyChanged event is only fired if you assign a value to the `cursorPos` property. Just setting the `position` field won't work. – Clemens Sep 27 '16 at 08:54
  • Thanks for the quick reply This is where I was looking (I had thought updating cursorPos on set would do that) - how would I do that in this situation? – Peter Freer Sep 27 '16 at 09:32

1 Answers1

0

In general it is a good idea to make your fields private and give access over properties:

 public static int position = 0;

should be

 private /*static*/ int position = 0;

I commented static out because you should only use it if it's really needed.

replace all position = ...; with cursorPos = ...;. If you are smarter than me you can even write a RegEx for it and let the IDE do your work ;-)

Another point would be that you can use the nameof keyword for property changed event if you using C# 6.0 RaisePropertyChanged(nameof(cursorPos));. This will save you some more headache if you rename your property one day.

EDIT

 public int cursorPos
    {
        get 
        { return position; 
        }
        set
        {
            postion = value;  // if you call for example "cursorPos = 12;" the value is "12". this is how properties work...
            RaisePropertyChanged(nameof(cursorPos));
        }
    }
Mat
  • 1,960
  • 5
  • 25
  • 38
  • further reading: http://stackoverflow.com/questions/295104/what-is-the-difference-between-a-field-and-a-property-in-c – Mat Sep 27 '16 at 09:42
  • Thanks, that was really helpful - I hadn't quite understood the fields. getting closer - still not quite there :/ I've updated to your recommendation... and it looks pretty good, but still isn't updating - in my MainWindow class that sents the `cursorPos`value Im instantiating the class to be able to call `cursorPos` ..i.e `Launcher launcher = new Launcher();` then changing cursorPos by `launcher.cursorPos = Math.Min(6, launcher.cursorPos + 1` and `launcher.cursorPos = Math.Min(6, launcher.cursorPos - 1` currently. Is this right? – Peter Freer Sep 28 '16 at 08:17
  • you have to set the DataContext of your MainWindow. e.g. MainWindow() { DataContext = launcher; } further reading: http://www.wpf-tutorial.com/data-binding/using-the-datacontext/ – Mat Sep 28 '16 at 09:14
  • Thanks for your help, that worked - I have to remove the datacontext ` ` which was conflicting - I think I was assuming this part of the XAML would be doing what the above was doing. – Peter Freer Sep 29 '16 at 20:17