Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

  • First of all, notice that PlayerList is just a list of the names of the Players in PlayerProfiles, which I created because when binding to a Combobox, they don't show up when I name the Combobox PlayerProfiles, yet they do when I go via the list and name it PlayerList - although I have overridden the ToString method in the PlayerProfile class. Why? This seems clumsy... (The staticInfos.Load() method populates the PlayerProfiles with several dummy names, if you are wondering...)

  • When I type something in the Textbox (called TB_AddPlayer) and press the button (called AddPlayer) the Test string appears, so I know the action took place, but the new name does not appear in the combobox

  • Also, If I use the commented line in the CanAddPlayer Property, the button never is enabled, not if I start typing, nor when the textbox looses focus with text in it. Why?

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>
like image 370
EluciusFTW Avatar asked Oct 22 '12 12:10

EluciusFTW


2 Answers

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.

like image 58
devdigital Avatar answered Sep 30 '22 02:09

devdigital


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.

like image 38
Chen Kinnrot Avatar answered Sep 30 '22 03:09

Chen Kinnrot