0

Recently I started converting a proof of concept UWP app to a working WPF app.

What I want is to have two dropdowns (combobox) of "characters" I can choose, I want them databound to an ObservableCollection property, where the characters I selected is stored in a different Character property for player 1 then player 2.

I had databinding on dropdowns working in the UWP app, but I can't get it to work in the WPF app.

In the WPF app, the comboboxes stay empty and I can't select an option.

I tried following the answer to this question, but I think I'm missing something: Binding a WPF ComboBox to a custom list

Here is the code, kept minimal:

Character.cs

public class Character : INotifyPropertyChanged
{
    private int _id;
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public Character(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainWindow.xaml

<Window x:Class="SmashWiiUOverlayManager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmashWiiUOverlayManager"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0" Grid.Row="0">
            <ComboBox 
                Name="Player1CharacterDropdown" 
                ItemsSource="{Binding CharacterList, Mode=TwoWay}" 
                SelectedItem="{Binding Player1SelectedCharacter, Mode=TwoWay}" 
                SelectedValuePath="Name" 
                DisplayMemberPath="Name"
                Width="144">
            </ComboBox>
        </StackPanel>

        <StackPanel Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right">
            <ComboBox 
                Name="Player2CharacterDropdown" 
                ItemsSource="{Binding CharacterList, Mode=TwoWay}" 
                SelectedItem="{Binding Player2SelectedCharacter, Mode=TwoWay}" 
                SelectedValuePath="Character" 
                DisplayMemberPath="Name"
                Width="144">
            </ComboBox>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private ObservableCollection<Character> _characterList;
    public ObservableCollection<Character> CharacterList
    {
        get
        {
            return _characterList;
        }
        set
        {
            _characterList = value;
        }
    }

    private Character _player1SelectedCharacter;
    public Character Player1SelectedCharacter
    {
        get
        {
            return _player1SelectedCharacter;
        }
        set
        {
            _player1SelectedCharacter = value;
        }
    }

    private Character _player2SelectedCharacter;
    public Character Player2SelectedCharacter
    {
        get
        {
            return _player2SelectedCharacter;
        }
        set
        {
            _player2SelectedCharacter = value;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();
        CharacterList = new ObservableCollection<Character>
        {
            new Character(0, "Mario"),
            new Character(1, "Luigi"),
            new Character(2, "Wario"),
        };
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

This code currently leaves the comboboxes empty.

When I use:

Player1CharacterDropdown.ItemsSource = new ObservableCollection<Character>
{
    new Character(0, "Mario", ".\\images\\mario.png"),
    new Character(1, "Luigi", ".\\images\\luigi.png"),
    new Character(2, "Wario", ".\\images\\wario.png"),
};

... the combox gets filled, but it's databound to the property, which is what I would like.

What am I missing here?

Gogoku7
  • 27
  • 2
  • 8
  • 1
    This may or may not be relevant to this issue , but it matters: `this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));`: What do you expect to happen when nobody has subscribed to `PropertyChanged`? – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 20:21
  • You're right that nothing is subscribed to it, I just bound all properties to it, and the app now does what I want. – Gogoku7 May 18 '18 at 20:26
  • 1
    The problem here is that `CharacterList` is only initialized after you set `this.DataContext = this;`. There's no notification. The Binding never updates the target when `CharacterList` is finally initialized, because you don't tell it it needs to update. If you initialize `CharacterList` before setting the DataContext, you'll be fine until you expect another of your non-notifying properties (e.g. `Player1SelectedCharacter`) to raise a notification event. Create a main viewmodel that has all these properties. Don't try to do it this way. – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 20:26
  • 1
    I followed your advice, I'm now using a ViewModel instead, everything is now set before the datacontext and everything is subscribed to OnPropertyChanged. Thank you. – Gogoku7 May 18 '18 at 20:45

0 Answers0