I have an items control binded to list of parent class.
I need to bind the properties of the child class in the data template.
These are the classes I have
public class Parent {
private string _name;
public string Name
{
get { return _name; }
set
{
if (Equals(value, _name)) return;
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
public class Child1 : Parent{
private string _prob1;
public string Prob1
{
get { return _prob1; }
set
{
if (Equals(value, _prob1)) return;
_prob1= value;
OnPropertyChanged(nameof(Prob1));
}
}
}
public class Child2 : Parent{
private string _prob2;
public string Prob2
{
get { return _prob2; }
set
{
if (Equals(value, _prob2)) return;
_prob2= value;
OnPropertyChanged(nameof(Prob2));
}
}
}
and in my view model I have an observable collection of Parent class
public ObservableCollection<Parent> ParentList { get; set; }
and my xaml code
<ItemsControl ItemsSource="{Binding ParentList }">
<ItemsControl.ItemTemplate>
<DataTemplate
DataType="domainObject:Child1">
<TextBlock Text="{Binding Name}" Margin="5" IsEnabled="False" HorizontalAlignment="Center" Height="22" Background="Transparent" />
<TextBlock Text="{Binding Prob1}" Margin="5"HorizontalAlignment="Center" Height="22" />
I want to bind the 2. textbox to a property of child class.
Is there any simple way to fix this problem?
In case the ParentList collection contains elements of different derived types (either Child1 or Child2) you should have different DataTemplates, which would automatically be chosen by their DataType property.
You may declare these DataTemplates in the Resources of the ItemsControl:
<ItemsControl ItemsSource="{Binding ParentList}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type domainObject:Child1}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" ... />
<TextBlock Text="{Binding Prob1}" ... />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type domainObject:Child2}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" ... />
<TextBlock Text="{Binding Prob2}" ... />
</StackPanel>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Related
I'm creating a WPF application using MVVM pattern (at least I'm trying). There is <TabControl> with bound ItemsSource,which is an ObservableCollection<TabModel> Tabs. Tabs has Name and Items property, where Items is a list of ControlModel, which means Controls. I have problem with binding IsEnabled property to Grid where Items are placed.
Below there is a part of my code presenting the way I'm doing this:
private ObservableCollection<TabModel> tabs;
public ObservableCollection<TabModel> Tabs
{
get
{
if (tabs == null)
{
tabs = new ObservableCollection<TabModel>();
RefreshTabs();
}
return tabs;
}
set
{
tabs = value;
OnPropertyChanged("Tabs");
}
}
\\Tab Model
public string Name { get; set; }
private List<ControlModel> items;
public List<ControlModel> Items
{
get { return items; }
set
{
items = value;
OnPropertyChanged("Items");
}
}
And xaml...
<TabControl Margin="0,100,0,0" ItemsSource="{Binding Tabs,UpdateSourceTrigger=PropertyChanged}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<Grid Margin="5,5,5,5" IsEnabled="{Binding IsProductEditionEnabled}">
<!--<Grid Margin="5,5,5,5">-->
<ItemsControl ItemsSource="{Binding Items,UpdateSourceTrigger=PropertyChanged}" ItemTemplateSelector="{StaticResource ControlTemplateSelector}"/>
</Grid>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
The part...
<Grid Margin="5,5,5,5" IsEnabled="{Binding IsProductEditionEnabled}">
is not working. There is no error. This grid is always disabled. By default it's false.
private bool isProductEditionEnabled = false;
public bool IsProductEditionEnabled
{
get { return isProductEditionEnabled; }
set
{
isProductEditionEnabled = value;
OnPropertyChanged("IsProductEditionEnabled");
}
}
The question is : How to bind IsEnabled in my case properly?
You are inside a DataTemplate so you need to specify where the parent DataContext is when you do the binding, something like this:
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<Grid IsEnabled="{Binding Path=DataContext.IsProductEditionEnabled,
RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}">
</Grid>
</ScrollViewer>
</DataTemplate>
To start off, I have a listbox that is trying to accept a UserControl as the DataTemplate:
<ListBox VerticalAlignment="Stretch" Name="GeneralMcmView" Grid.Column="0" HorizontalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With the contents of the usercontrol looking like:
<ContentControl FontFamily="Segoe UI" VerticalAlignment="Stretch" FontSize="10">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding ElementName=_this, Path=TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding ElementName=_this, Path=Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding ElementName=_this, Path=MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding ElementName=_this, Path=MessageContent}" />
</StackPanel>
</Grid>
</ContentControl>
I then create a couple messages, all with different data (The Listbox's ItemSource is bound to the GeneralMessages ObservableCollection):
GeneralMcmMessage newMsg = new GeneralMcmMessage()
{
MessageId = e.McmMessageViewInfo.Id,
TimeStamp = e.McmMessageViewInfo.MessageDateTime,
Type = e.McmMessageViewInfo.MessageType.ToString(),
MessageName = e.McmMessageViewInfo.MessageName,
MessageContent = e.McmMessageViewInfo.Message.ToString()
};
GeneralMessages.Add( newMsg );
During runtime I interrogate the Items property of the listbox and all the data looks correct, however all I see in the listbox are entries of the GeneralMcmMessage User Control with default data values. Any ideas as to why?
Also, FWIW I am using INotifyPropertyChanged in the usercontrol class:
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private Constants.PiuModule piuModule = Constants.PiuModule.MCM;
private string className = "GeneralMcmMessage";
/// <summary>
/// Event for notifying listeners that a property changed. Part of INotifyPropertyChanged
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public int MessageId { get; set; }
private DateTime timeStamp;
public DateTime TimeStamp
{
get
{
return timeStamp;
}
set
{
timeStamp = value;
OnNotifyPropertyChanged( "TimeStamp" );
}
}
You're saying that the DataTemplate to display a GeneralMcmMessage is to instantiate new GeneralMcmMessage.
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
I'd recommend instead of making a collection of your UserControl to make a collection of your model object instead, and bind to the properties within that within your UserControl.
Either way though - the object you created in code will be the DataContext for the one you created in XAML so removing the ElementName=_this should bind appropriately. Try this simplified XAML in your UserControl instead.
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding MessageContent}" />
</StackPanel>
You don’t post all code of GeneralMcmMessage hence I don’t know if you set DataContext in user control for example in constructor of GeneralMcmMessage.
I tried replicate your problem.
User control GeneralMcmMessage code behind
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private int _messageId;
public int MessageId
{
get
{
return _messageId;
}
set
{
_messageId = value;
OnPropertyChanged("MessageId");
}
}
private DateTime _timeStamp;
public DateTime TimeStamp
{
get
{
return _timeStamp;
}
set
{
_timeStamp = value;
OnPropertyChanged("TimeStamp");
}
}
public GeneralMcmMessage()
{
InitializeComponent();
//don’t set data context here
//DataContext = this;
}
}
User control GeneralMcmMessage XAML
<StackPanel>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=MessageId}"/>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=TimeStamp}"/>
</StackPanel>
User control GeneralMcmMessage usage
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<GeneralMcmMessage> _generalMessages;
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<GeneralMcmMessage> GeneralMcmMessages
{
get { return _generalMessages; }
set
{
_generalMessages = value;
OnPropertyChanged("GeneralMcmMessages");
}
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
GeneralMcmMessages = new ObservableCollection<GeneralMcmMessage>();
for (int i = 0; i < 10; i++)
{
var newMsg = new GeneralMcmMessage
{
MessageId = i,
TimeStamp = DateTime.Now,
};
GeneralMcmMessages.Add(newMsg);
}
}
}
User control GeneralMcmMessage usage XAML
<ListBox x:Name="ListBox"
Margin="5"
ItemsSource="{Binding Path=GeneralMcmMessages}">
<ListBox.ItemTemplate>
<DataTemplate DataType="stackoverflow:GeneralMcmMessage">
<stackoverflow:GeneralMcmMessage/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If this not solve your problem could you please post all GeneralMcmMessage?
If you want I can upload sample project for you.
Thank you
I'm trying to use Caliburn.Micro to bind a view model of a nested ListBox but I'm stuck.
I have a list workspace that is divided in two sections a list of groups containtaining items in a different part of that workspace I want to show the details of either a group or an item in a group depending on what is the SelectedItem. I'm new to Caliburn.Micro and looked at the documentation and samples but don't know how to connect the dots. Specifically I'm trying to model this after the Caliburn.Micro.HelloScreens sample. The code I have so far:
The ViewModel:
public class AnalyzerGroupWorkspaceViewModel : Conductor<AnalyzerGroupWorkspaceViewModel>, IWorkspace
{
private Selected selected = Selected.AnalyzerGroup;
private const string name = "Analyzers";
public AnalyzerGroupWorkspaceViewModel(
IMappingEngine fromMapper,
IRepository<Model.AnalyzerGroup> analyzerGroups)
{
AnalyzerGroups = new ObservableCollection<IAnalyzerGroupViewModel>(analyzerGroups.GetAll().Select(fromMapper.Map<Model.AnalyzerGroup,AnalyzerGroupViewModel>));
}
public ObservableCollection<IAnalyzerGroupViewModel> AnalyzerGroups { get; private set; }
public string Name { get { return name; } }
public Selected Selected
{
get { return selected; }
set
{
if (value == selected) return;
selected = value;
NotifyOfPropertyChange(() => Selected);
}
}
private IConductor Conductor { get { return (IConductor) Parent; } }
public void Show()
{
var haveActive = Parent as IHaveActiveItem;
if (haveActive != null && haveActive.ActiveItem == this)
{
DisplayName = name;
Selected = Selected.AnalyzerGroup;
}
else
{
Conductor.ActivateItem(this);
}
}
}
The view:
<UserControl x:Class="Philips.HHDx.SSW.AnalyzerGroup.AnalyzerGroupWorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<DockPanel>
<GroupBox Header="AnalyzerGroups" DockPanel.Dock="Top">
<ListBox x:Name="AnalyzerGroups">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" />
<ListBox x:Name="Analyzers">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id }"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<GroupBox Header="Details">
<ContentControl cal:View.Context="{Binding Selected, Mode=TwoWay}"
cal:View.Model="{Binding}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
</GroupBox>
</DockPanel>
</UserControl>
Next to that I have two UserControls that display the detailsof a group or item.
My specific question is how can I use the SelectedItem property of the two ListBoxes to modify the Selected property to switch between displaying the AnalyzerGroup details and the Analyzer details?
I've found the solution to the above described problem the solution consists of four parts:
Add a IsSelected property (that notifies changes) to both 'child' ViewModels
Bind the IsSelected property of the ListBox.ItemContainerStyle to the IsSelected property of the respective ViewModels
Attach a Caliburn.Micro Message to the 'outer' ListBox and use the $eventArgs argument
In the ViewModel bound to the entire UserControl implement the method corresponding to the Message and use the AddedItems property of the eventArgs to set the SelectedViewModel property setting the IsSelected property of the previous SelectedViewModel to false
The code then becomes:
The ViewModel:
public class AnalyzerGroupWorkspaceViewModel : PropertyChangedBase, IAnalyzerGroupWorkspaceViewModel
{
private IAnalyzerViewModel selectedViewModel;
private const string WorkspaceName = "Analyzers";
public AnalyzerGroupWorkspaceViewModel(
IMappingEngine fromMapper,
IRepository<Model.AnalyzerGroup> analyzerGroups)
{
AnalyzerGroups = new ObservableCollection<IAnalyzerGroupViewModel>(
analyzerGroups.GetAll().Select(
fromMapper.Map<Model.AnalyzerGroup, AnalyzerGroupViewModel>));
}
public void SelectionChanged(object eventArgs)
{
var typedEventArgs = eventArgs as SelectionChangedEventArgs;
if (typedEventArgs != null)
{
if (typedEventArgs.AddedItems.Count > 0)
{
var item = typedEventArgs.AddedItems[0];
var itemAsGroup = item as IAnalyzerViewModel;
if (itemAsGroup != null)
{
SelectedViewModel = itemAsGroup;
}
}
}
}
public ObservableCollection<IAnalyzerGroupViewModel> AnalyzerGroups { get; private set; }
public string Name { get { return WorkspaceName; } }
public IAnalyzerViewModel SelectedViewModel
{
get { return selectedViewModel; }
set
{
if (Equals(value, selectedViewModel))
{
return;
}
if (SelectedViewModel != null)
{
SelectedViewModel.IsSelected = false;
}
selectedViewModel = value;
NotifyOfPropertyChange(() => SelectedViewModel);
}
}
}
The View:
<UserControl x:Class="Philips.HHDx.SSW.AnalyzerGroup.AnalyzerGroupWorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<DockPanel>
<GroupBox Header="AnalyzerGroups" DockPanel.Dock="Top">
<ListBox SelectionMode="Single"
x:Name="AnalyzerGroups"
cal:Message.Attach="[Event SelectionChanged] = [Action SelectionChanged($eventArgs)]">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="DarkGray">
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Text="{Binding Name}" />
<ListBox SelectionMode="Single" ItemsSource="{Binding Analyzers}" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="DarkGray">
<StackPanel>
<TextBlock Text="{Binding Name }" Margin="10" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<GroupBox Header="Details">
<ContentControl cal:View.Model="{Binding SelectedViewModel}" />
</GroupBox>
</DockPanel>
</UserControl>
The answer to your specific question is yes, you can.
On the ViewModel of your UserControl. You create a property that is a ViewModel of either of the two details.
public interface IAnalyzerViewModel
{
}
Next, create two ViewModels for the Views of your Analyzer and AnalyzerGroup views.
public class AnalyzerGroupViewModel : IAnalyzerViewModel
{
}
public class AnalyzerViewModel : IAnalyzerViewModel
{
}
Next, create a property in your UserControl's ViewModel that implements INPC or PropertyChangedBase of Caliburn Micro.
public class MainViewModel :
{
private IAnalyzerViewModel _analyzerViewModel;
public IAnalyzerViewModel SelectedViewModel { get { return _analyzerViewModel; } set { _analyzerViewModel = value; OnPropertyChanged(() => SelectedViewModel); }
//Hook up the selected item changed event of your listbox and set the appropriate ViewModel to show, so if you either want to show the AnalyzerGroup or AnalyzerView.
}
And lastly, just update your MainView to
<ContentControl x:Name="SelectedViewModel"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
Caliburn will hook up the appropriate bindings and stuff and will pull the View for the associated ViewModel, and also the Name convention part will automatically map it to any public property of its datacontext as long as the names match.
Please note:
The two types in the lists are simplified a lot for this example and must be kept separate.
The use of an int as connection between the types can not be changed.
The problem:
Given the code below, how do I get the ComboBox marked with ??? to:
Display the ColorDefs.Name as its content.
Set SelectedItem to the one where Models.DisplayColorNumber is equal to ColorDefs.ColorNumber.
Update the Models.DisplayColorNumber updated if the selection is changed.
In code-behind
public List<ModelData> Models { get; }
public List<DisplayColorDefinition> ColorDefs { get; }
DataContext=this;
XAML:
<ListBox ItemsSource="{Binding Models}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox ??? />
<TextBlock Text="{Binding Models, Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ModelData type:
public class ModelData
{
private string name;
private int displayColorNumber;
public string Name
{
get { return name; }
set { name = value; }
}
public int DisplayColorNumber
{
get { return displayColorNumber; }
set { displayColorNumber = value; }
}
}
DisplayColorDefinition type:
public class DisplayColorDefinition
{
private int colorNumber;
private string name;
private Color displayColor;
public int ColorNumber
{
get { return colorNumber; }
set { colorNumber= value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
public Color DisplayColor
{
get { return displayColor; }
set { displayColor = value; }
}
}
Use the SelectedValue and SelectedValuePath :
<ListBox ItemsSource="{Binding Models}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=DataContext.ColorDefs, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
DisplayMemberPath="Name"
SelectedValue="{Binding Path=DisplayColorNumber}"
SelectedValuePath="ColorNumber"
/>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding DisplayColorNumber}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
SelectedValue will be the property on the Model object, and SelectedValuePath will indicate which property of the DisplayColorDefinition to use for the binding.
How do I get my class properties to show up in the ListBox?
XAML:
<ListBox x:Name="lstPlayers" >
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Player.FirstName}"></TextBlock>
<TextBlock Text="{Binding Player.LastName}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox>
C#:
public class Player
{
string FirstName { get; set; }
string LastName { get; set; }
}
public void LoadPlayers()
{
foreach (Player player in Players)
{
lstPlayers.Items.Add(player);
}
}
The only thing that shows up in the ListBox is
TestApplication1.Player
You have some problems with you current implementation. First, the DataTemplate should be placed inside the ItemTemplate for the ListBox. Second, the DataContext for each ListBoxItem will be an instance of Player so you should bind directly to FirstName and LastName. Third, the properties in Player should be made public for the DataBinding to work.
<ListBox x:Name="lstPlayers" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"></TextBlock>
<TextBlock Text="{Binding LastName}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class Player
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Also, instead of adding the collection item by item to the ListBox, just set it as ItemsSource
lstPlayers.ItemsSource = Players;
DataTemplate should be inside ListBox.ItemTemplate.
set the collection, Players as ItemSource
and
<ListBox x:Name="lstPlayers" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"></TextBlock>
<TextBlock Text="{Binding LastName}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
you have to add the DataType to your DataTemplate.
<DataTemplate DataType="{x:Type local:Player}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"></TextBlock>
<TextBlock Text="{Binding LastName}"></TextBlock>
</StackPanel>
</DataTemplate>
local is the namespace for your TestApplication1.Player. you can set the datatemplate to the listebox.itemtemplate or as a resource of any "parent object"