EluciusFTW
EluciusFTW

Reputation: 2615

Caliburn Micro, Binding and Notifying

After a couple of months of hands-on WPF I decided to give Caliburn Micro a shot. I have several things I can't get to work. I'll post the code first, see my questions/problems below:

public class MainViewModel : PropertyChangedBase
{
    BindableCollection<PlayerProfile> _playerProfiles = staticInfos.Load();

    public BindableCollection<PlayerProfile> PlayerProfiles {
        get { return _playerProfiles; }
        set { 
            _playerProfiles = value;
            NotifyOfPropertyChange(() => PlayerList);
        }
    }

    string _tb_AddPlayer;
    public string TB_AddPlayer {
        get { return _tb_AddPlayer; }
        set { 
            _tb_AddPlayer = value;
            NotifyOfPropertyChange(() => TB_AddPlayer);
            NotifyOfPropertyChange(() => CanAddPlayer);
        }
    }

    List<string> _pl = new List<string>(); 
    public List<string> PlayerList {
        get{
            foreach (PlayerProfile p in PlayerProfiles) {
                if (!_pl.Contains(p.Name)) _pl.Add(p.Name);
            }
            return _pl;               
        }
        set {
            _pl = value;
            NotifyOfPropertyChange(()=>PlayerList);
        }
    }

    // Dummy Test String
    string _test;
    public string Test { 
        get { return _test; } 
        set { 
            _test = value; 
            NotifyOfPropertyChange(() => Test); 
        }
    }

    // Button Action
    public void AddPlayer() {
         _playerProfiles.Add(new PlayerProfile(TB_AddPlayer));
         Test = "Pressed";
         NotifyOfPropertyChange(() => PlayerProfiles);
    }

    public bool CanAddPlayer {
        get { return true; }
        // doesnt work: get { return !string.IsNullOrWhiteSpace(TB_AddPlayer); }
    }
}

So here goes: I use the binding convention, i.e., a Property in the MainView should bind to the Element of same Name in the View.

Sorry for these basic questions, I have stared at the 'Hello World' caliburn example for hours and don't see what I am missing... Thx. in advance!

Edit: Here's the .xaml

<UserControl x:Class="MixGameM8_MVVM.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MixGameM8_MVVM.Views">

<UserControl.Resources>
    <Style TargetType="TextBlock" x:Key="TB_A">
        <Setter Property="Margin" Value="5,5,5,5" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontSize" Value="15" />
    </Style>

    <!-- ... Some more of this kind -->
</UserControl.Resources>

<Grid>
    <!-- ... Grid definitions -->
    <Border Style="{StaticResource Border_A}" Grid.Row="0" Grid.Column="0">
        <StackPanel Name="SP_Controls">
            <TextBlock Style="{StaticResource TB_A}" Text="Controls"/>
            <ComboBox Style="{StaticResource CB_A}" Name="PlayerProfiles"/>
            <StackPanel Orientation="Horizontal">
                <TextBox Style="{StaticResource TBox_A}" Name="TB_AddPlayer" MinWidth ="100" />
                <Button Style="{StaticResource Button_AddPlayer}" Content="Add Player" Name="AddPlayer" />
             </StackPanel>
        </StackPanel>
    </Border>

<!-- ... And some more cells in the grid, one containing the dummy textbox -->

</Grid>
</UserControl>

Upvotes: 5

Views: 11332

Answers (2)

Chen Kinnrot
Chen Kinnrot

Reputation: 21015

I think I got the answers

On your text box use updatesourcetrigger=property changed The Can Execute is not updating cause you didn't use the depends on (or dependencies dont remeber the name) attribute.

The combobox not updating cause you should bind it to a bindable collection.

Upvotes: 1

devdigital
devdigital

Reputation: 34369

Firstly, I would start by removing your PlayerList property, and update your PlayerProfiles property like so:

 public BindableCollection<PlayerProfile> PlayerProfiles {
    get { return _playerProfiles; }
    set { 
        _playerProfiles = value;
        NotifyOfPropertyChange(() => PlayerProfiles);
    }
}

Next, I would not call your view model properties something which describes how they are rendered, i.e. change TB_AddPlayer to just AddPlayer (or better still something like PlayerName as that's what it is).

Next, if you call your ComboBox PlayerProfiles, then the binding should automatically happen via convention. In your AddPlayer method, you want to add the new player profile via your property, not the backing field:

Change:

public void AddPlayer() {
     _playerProfiles.Add(new PlayerProfile(TB_AddPlayer));
     Test = "Pressed";
     NotifyOfPropertyChange(() => PlayerProfiles);
}

to:

public void AddPlayer() {
     this.PlayerProfiles.Add(new PlayerProfile(this.PlayerName));
}

Because PlayerProfiles is a BindableCollection, change notifications will be performed, and your ComboBox will be updated.

Also, I would always explicitly specify the access modifier for your backing fields, i.e. private string _playerName; not just string _playerName;

Try these changes, and update your code in the question if you still have problems.

Upvotes: 4

Related Questions