I have a simple app, that should add SelectedItem from ComboBox to ListBox.
I have Model:Player
public class Player
{
public int ID { get; set; }
public string Name { get; set; }
private bool _isSelected = false;
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; }
}
}
And ObservableCollection property in my ViewModel (Players)
public class ViewModel
{
public ObservableCollection<Player> Players { get; set; }
public ObservableCollection<Player> PlayersInTournament { get; set; } = new ObservableCollection<Player>();
public ICommand AddPlayerCommand { get; set; }
public ViewModel()
{
DataAccess access = new DataAccess();
Players = new ObservableCollection<Player>(access.GetPlayers());//GetPlayers from DataBase
AddPlayerCommand = new RelayCommand(AddPlayer, CanAddPlayer);
}
private void AddPlayer()
{
//Something like PlayersInTournamen.Add(SelectedPlayer);
}
private bool CanAddPlayer()
{
bool canAdd = false;
foreach(Player player in Players)
{
if (player.IsSelected == true)
canAdd = true;
}
return canAdd;
}
}
Property(ItemSource) of my ComboBox is bound to the Players collection. When the application is Loaded my ComboBox is filled with objects from DataBase and when I select one of them it is displayed in my ReadOnly TextBox. I achieved this by binding the Text property to the ItemSelected.Name property of ComboBox. There is an Add button in the app that add selected player to the tournament(ListBox)(the app is about tournament). ListBox's ItemSource is PlayersInTournament collection(see in ViewModel).
XAML(DataContext of Window is set to ViewModel instance after InitializeComponents()):
<Window x:Class="ComboBoxDemoSQL.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:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:ComboBoxDemoSQL"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<StackPanel HorizontalAlignment="Center"
Orientation="Horizontal" Margin="0 40 0 10">
<TextBox x:Name="HoldPlayerTextBox"
Width="100"
Text="{Binding ElementName=PlayersComboBox, Path=SelectedItem.Name}"
IsReadOnly="True">
</TextBox>
<ComboBox Name="PlayersComboBox"
VerticalAlignment="Top"
Margin="10 0 0 0"
HorizontalAlignment="Center" Width="100"
ItemsSource="{Binding Players}"
DisplayMemberPath="Name"
Text="Select player"
IsEditable="True"
IsReadOnly="True"/>
</StackPanel>
<Button Content="Add" Margin="120 0 120 0"
Command="{Binding AddPlayerCommand}"/>
<ListBox Margin="10" ItemsSource="{Binding PlayersInTournament}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding ID}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
Photo to understand better:
So basically there are 2 problems:
- I don't know how to add to the PlayersInTournament collection a
player that is selected in
ComboBoxbecause I can't get the name of that Player fromTexBox(because its' Text property is bound to another Property) - I don't know how to disable
Add Button(CanAddPlayer method) when there is no Player selected, I tried by addingIsSelected(see Player model) property, but for it to work I have to bind to any property in View that would change it, but I don't know which property can be used for this thing.
ICommand implementation:
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private Action methodToExecute;
private Func<bool> canExecuteEvaluator;
public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
{
this.methodToExecute = methodToExecute;
this.canExecuteEvaluator = canExecuteEvaluator;
}
public RelayCommand(Action methodToExecute)
: this(methodToExecute, null)
{
}
public bool CanExecute(object parameter)
{
if (this.canExecuteEvaluator == null)
{
return true;
}
else
{
bool result = this.canExecuteEvaluator.Invoke();
return result;
}
}
public void Execute(object parameter)
{
this.methodToExecute.Invoke();
}
}
