I have a ListBox on a form that is bound to a BindingList<T> in code behind but is not displaying the items within the BindingList<T>.
XAML:
<Window x:Class="MessageServer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MessageServer"
Name="mainWindow" Title="Message Exchange Server"
Height="350" Width="525" Closing="Window_Closing">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox Name="OutputList" Grid.Row="0" />
<ListBox Name="Connected" Grid.Row="1" ItemsSource="{Binding ElementName=mainWindow, Path=ConnectedClients}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FullIPAddress}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
CodeBehind:
private BindingList<Client> _ConnectedClients;
public BindingList<Client> ConnectedClients
{
get { return _ConnectedClients; }
set { _ConnectedClients = value; }
}
public class Client : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private TcpClient _tcpClient;
public TcpClient tcpClient
{
get { return _tcpClient; }
set
{
_tcpClient = value;
NotifyPropertyChanged();
}
}
public string FullIPAddress
{
get { return _tcpClient.Client.RemoteEndPoint.ToString(); }
}
public string IPAddress
{
get { return _tcpClient.Client.RemoteEndPoint.ToString().Split(':').ElementAt(0); }
}
public string PortNumber
{
get { return _tcpClient.Client.RemoteEndPoint.ToString().Split(':').ElementAt(1); }
}
public Client(TcpClient tcpClient)
{
this.tcpClient = tcpClient;
NotifyPropertyChanged();
}
private void NotifyPropertyChanged()
{
NotifyPropertyChanged("tcpClient");
NotifyPropertyChanged("FullIPAddress");
NotifyPropertyChanged("IPAddress");
NotifyPropertyChanged("PortNumber");
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Any Ideas why the list box is not displaying the items?
Not sure if this is worth mentioning but When added items to the BindingList this is done on a seperate thread to the UI Thread. but I have tried using Dispatcher.BeginInvoke() but still does not work...
It sounds like you really want to use ObservableCollection. It sounds like BindingList should work, but on this SO post they seem say ObservableCollection is for WPF and BindingList for Winforms: Differences between BindingList and ObservableCollection
Try using an ObservableCollection<T>. It was designed specifically for WPF.
You are trying to bind to Window.ConnectedClients, which is a property that doesn't exist.
You need to change your binding to DataContext.ConnectedClients to bind to Window.DataContext.ConnectedClients
ItemsSource="{Binding ElementName=mainWindow, Path=DataContext.ConnectedClients}"
Related
I have a UserControl called "UserControllerIo" and this is what it has:
public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
Messages = new ObservableCollection<string>();
InitializeComponent();
IoComponentViewModel.Instance = new IoComponentViewModel();
Label1.DataContext = IoComponentViewModel.Instance;
Messages.Add(Label1.Text);
}
I consume this in my xml like so:
<Grid>
<Label>
<TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding Path=XState, Mode=OneWay}">
</TextBlock>
</Label>
<ListView
x:Name="ListView"
ItemsSource="{Binding Messages}" />
</Grid>
I have a view model for this control:
class IoComponentViewModel : INotifyPropertyChanged
{
public static IoComponentViewModel Instance { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private string _xState;
public string XState
{
get { return _xState; }
set
{
_xState = value;
OnPropertyChanged($"XState");
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And I invoke to populate the list on another class like so:
case x:
IoComponentViewModel.Instance.XState = msg;
break;
My problem is, it is not showing in my Listview although I can see it in my label. Can you please show me how. Thank you.
I don't know how much I understood your task from the provided code, but look at this implementation variant.
IoComponentViewModel:
public class IoComponentViewModel : INotifyPropertyChanged
{
public static IoComponentViewModel Instance { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private string _xState;
public string XState
{
get { return _xState; }
set
{
if (_xState == value)
return;
XStates.Add(_xState = value);
OnPropertyChanged($"XState");
}
}
public ObservableCollection<string> XStates { get; } = new ObservableCollection<string>();
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Grid x:Name="PART_Grid">
<Grid.DataContext>
<local:IoComponentViewModel/>
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--<Label>-->
<TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding XState, Mode=OneWay}">
</TextBlock>
<!--</Label>-->
<ListView Grid.Row="1"
x:Name="ListView"
ItemsSource="{Binding XStates}" />
</Grid>
Code Behind:
//public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
//Messages = new ObservableCollection<string>();
InitializeComponent();
// IoComponentViewModel.Instance = new IoComponentViewModel();
//Label1.DataContext = IoComponentViewModel.Instance;
IoComponentViewModel.Instance = (IoComponentViewModel)PART_Grid.DataContext;
//Messages.Add(Label1.Text);
}
I misread the question initially. There are two problems. Your list is not binding to the view model, so you need an element reference.
<UserControl x:Class="StackOverflow.UserControllerIo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:StackOverflow"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="MyUserControl"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label>
<TextBlock Foreground="Black" x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding Path=XState, Mode=OneWay}">
</TextBlock>
</Label>
<ListView Grid.Row="1"
x:Name="ListView"
ItemsSource="{Binding Messages, ElementName=MyUserControl}" >
</ListView>
</Grid>
Secondly, at the point where you add Label1.Text to your data binding is not ready. So you will need to wait for binding before you read the text, for example in load event like this:
public partial class UserControllerIo : UserControl
{
public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
Messages = new ObservableCollection<string>();
InitializeComponent();
IoComponentViewModel.Instance = new IoComponentViewModel();
Label1.DataContext = IoComponentViewModel.Instance;
IoComponentViewModel.Instance.XState = "Something";
Loaded += UserControllerIo_Loaded;
}
private void UserControllerIo_Loaded(object sender, RoutedEventArgs e)
{
Messages.Add(Label1.Text);
}
}
EDIT:
my first tests mislead me, by testing with an int property for adding values to the List on runtime.
ObservableCollection updates anyway!
The problem is how you declared the Messages Property. If you have a Property on a Control it needs to be a dependency Property to notify the UI.
replace
public ObservableCollection<string> Messages { get; set; }
with
public ObservableCollection<string> Messages
{
get { return (ObservableCollection<string>)GetValue(MessagesProperty); }
set { SetValue(MessagesProperty, value); }
}
public static readonly DependencyProperty MessagesProperty =
DependencyProperty.Register("Messages", typeof(ObservableCollection<string>), typeof(UserControllerIo), new PropertyMetadata(null));
and you should be fine.
OR
you could imlpement INotifyPropertyChanged on your UserControl class.
And don't forget to maintain #Clemens' comment about binding!!!
ItemsSource="{Binding Messages, RelativeSource={RelativeSource AncestorType=UserControl}}
The situation:
I have a little app that works with fantasy classes. In the example below I boiled it down to the bare bones. In a ComboBox, situated in the Main Window, the user selects a fantasy class (warrior, rogue, mage etc.) from a list loaded from a DB. This information is passed to a UserControl sitting in Main Window which exposes details about the class using MVVM and data binding. All of this works so far.
The DB has a value (in this case Gear) saved as an int which at the moment displays as an int on screen. It's the app's responsibility to parse that to a string.
So the question is: How do I wire up a method in the UserControl's ViewModel to trigger whenever it's associated View has a DataContext (the selected CharacterClass) change?
Main Window:
<Window x:Class="ExampleApp.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:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExampleApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Height="22" MinWidth="70"
ItemsSource="{Binding Classes}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedClass}"/>
<local:DetailsView Grid.Column="1" DataContext="{Binding SelectedClass}"/>
</Grid>
</Window>
Main Window ViewModel:
namespace ExampleApp
{
class MainWindowViewModel : Observable
{
private ObservableCollection<CharacterClass> _Classes;
private CharacterClass _SelectedClass;
public ObservableCollection<CharacterClass> Classes
{
get { return _Classes; }
set { SetProperty(ref _Classes, value); }
}
public CharacterClass SelectedClass
{
get { return _SelectedClass; }
set { SetProperty(ref _SelectedClass, value); }
}
public MainWindowViewModel()
{
LoadCharacterClasses();
}
private void LoadCharacterClasses()
{
//simulated data retrieval from a DB.
//hardcoded for demo purposes
Classes = new ObservableCollection<CharacterClass>
{
//behold: Gear is saved as an int.
new CharacterClass { Name = "Mage", Gear = 0, Stats = "3,2,1" },
new CharacterClass { Name = "Rogue", Gear = 1, Stats = "2,2,2" },
new CharacterClass { Name = "Warrior", Gear = 2, Stats = "1,2,3" }
};
}
}
}
My CharacterClass definition. Inheriting from Observable which encapsulates INotifyPropertyChanged
namespace ExampleApp
{
public class CharacterClass : Observable
{
private string _Name;
private int _Gear;
private string _Stats;
public string Name
{
get { return _Name; }
set { SetProperty(ref _Name, value); }
}
public int Gear
{
get { return _Gear; }
set { SetProperty(ref _Gear, value); }
}
public string Stats
{
get { return _Stats; }
set { SetProperty(ref _Stats, value); }
}
}
}
Details about the Observable baseclass:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ExampleApp
{
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName] string propertyName = null)
{
if (object.Equals(member, val)) return;
member = val;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The DetailsView UserControl:
<UserControl x:Class="ExampleApp.DetailsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ExampleApp"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:DetailsViewModel}">
<local:DetailsView/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Label Content="Name:"/>
<Label Content="Base Stats"/>
<Label Content="Starting Gear"/>
</StackPanel>
<StackPanel Grid.Column="1">
<Label Content="{Binding Name}"/>
<Label Content="{Binding Stats}"/>
<Label Content="{Binding gearToString}"/>
</StackPanel>
</Grid>
</UserControl>
and finally: the DetailsViewModel:
public class DetailsViewModel : Observable
{
public string GearToString;
//The method I would like to have called whenever the selected
//CharacterClass (DetailsView.DataContext, so to speak) changes.
private void OnCharacterClassChanged(int gearNumber)
{
switch (gearNumber)
{
case 0:
GearToString = "Cloth";
break;
case 1:
GearToString = "Leather";
break;
case 2:
GearToString = "Plate";
break;
default:
GearToString = "*Error*";
break;
}
}
}
I've fiddled around with attempting to have a command fire when the DetailsView Label updates.
Made a failed attempt to convert DetailsViewModel.GearToString to a dependencyproperty.
I've attempted to override Observable's SetProperty inside of DetailsViewModel.
I don't know which, if any of, those attempts would be viable, if I managed to implement them properly (I've only been coding for several months now :))
I could get it to work using DetailsView code-behind, however that's not MVVM'y.
Because you change your DetailViews DataContext via the combobox, you can access the "current" DetailDataContext before the combobox changes SelectedItem.
You can do this right here:
public CharacterClass SelectedClass
{
get { return _SelectedClass; }
set {
_SelectedClass.DoWhatever();
SetProperty(ref _SelectedClass, value);
}
}
Or you can handle the ComboBoxes SelectionChanged event via a command. Your old value is in e.RemovedItem.
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0)
(e.RemovedItems[0] as CharacterClass).DoSomething();
}
I tend to prefer that approach since it can get confusing quickly if you put too much logic in the setters. It leads to chain reactions that are pretty hard to follow and debug.
In general viewmodels communicate with each other via events. In more complex / disconnected situations with the help of an EventAggregator, MessageBus or something similiar.
I would like to get content from my combobox. I already tried some ways to do that, but It doesn't work correctly.
This is example of my combobox:
<ComboBox x:Name="cmbSomething" Grid.Column="1" Grid.Row="5" HorizontalAlignment="Center" Margin="0 100 0 0" PlaceholderText="NothingToShow">
<ComboBoxItem>First item</ComboBoxItem>
<ComboBoxItem>Second item</ComboBoxItem>
</ComboBox>
After I click the button, I want to display combobox selected item value.
string selectedcmb= cmbSomething.Items[cmbSomething.SelectedIndex].ToString();
await new Windows.UI.Popups.MessageDialog(selectedcmb, "Result").ShowAsync();
Why this code does not work?
My result instead of showing combobox content, it shows this text:
Windows.UI.Xaml.Controls.ComboBoxItem
You need the Content property of ComboBoxItem. So this should be what you want:
var comboBoxItem = cmbSomething.Items[cmbSomething.SelectedIndex] as ComboBoxItem;
if (comboBoxItem != null)
{
string selectedcmb = comboBoxItem.Content.ToString();
}
I have expanded on my suggestion regarding using models instead of direct UI code-behind access. These are the required parts:
BaseViewModel.cs
I use this in a lot of the view models in my work project. You could technically implement it directly in a view model, but I like it being centralized for re-use.
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Hashtable values = new Hashtable();
protected void SetValue(string name, object value)
{
this.values[name] = value;
OnPropertyChanged(name);
}
protected object GetValue(string name)
{
return this.values[name];
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
ComboViewModel.cs
This what you'll bind to make it easy to get values. I called it ComboViewModel because I'm only dealing with your ComboBox. You'll want a much bigger view model with a better name to handle all of your data binding.
public class ComboViewModel : BaseViewModel
{
public ComboViewModel()
{
Index = -1;
Value = string.Empty;
Items = null;
}
public int Index
{
get { return (int)GetValue("Index"); }
set { SetValue("Index", value); }
}
public string Value
{
get { return (string)GetValue("Value"); }
set { SetValue("Value", value); }
}
public List<string> Items
{
get { return (List<string>)GetValue("Items"); }
set { SetValue("Items",value); }
}
}
Window1.xaml
This is just something I made up to demonstrate/test it. Notice the various bindings.
<Window x:Class="SO37147147.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox x:Name="cmbSomething" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" HorizontalAlignment="Center" MinWidth="80"
ItemsSource="{Binding Path=Items}" SelectedIndex="{Binding Path=Index}" SelectedValue="{Binding Path=Value}"></ComboBox>
<TextBox x:Name="selectedItem" MinWidth="80" Grid.Row="2" Grid.Column="0" Text="{Binding Path=Value}" />
<Button x:Name="displaySelected" MinWidth="40" Grid.Row="2" Grid.Column="1" Content="Display" Click="displaySelected_Click" />
</Grid>
</Window>
Window1.xaml.cs
Here's the code-behind. Not much to it! Everything is accessed through the dataContext instance. There's no need to know control names, etc.
public partial class Window1 : Window
{
ComboViewModel dataContext = new ComboViewModel();
public Window1()
{
InitializeComponent();
dataContext.Items=new List<string>(new string[]{"First Item","Second Item"});
this.DataContext = dataContext;
}
private void displaySelected_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(String.Format("Selected item:\n\nIndex: {0}\nValue: {1}", dataContext.Index, dataContext.Value));
}
}
You can add business logic for populating models from a database, saving changes to a database, etc. When you alter the properties of the view model, the UI will automatically be updated.
I have the following XAML:
<Window x:Class="ListBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListBoxTest"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Model />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Items}" Grid.Row="0"/>
<Button Content="Add" Click="Button_Click" Grid.Row="1" Margin="5"/>
</Grid>
</Window>
and the following code for the Model class, which is put into main window's DataContext:
public class Model : INotifyPropertyChanged
{
public Model()
{
items = new Dictionary<int, string>();
}
public void AddItem()
{
items.Add(items.Count, items.Count.ToString());
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Items"));
}
private Dictionary<int, string> items;
public IEnumerable<string> Items { get { return items.Values; } }
public event PropertyChangedEventHandler PropertyChanged;
}
and main window's code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var model = this.DataContext as Model;
model.AddItem();
}
}
When pressing the button, the contents of the list are not being updated.
However, when I change the getter of the Items property to this:
public IEnumerable<string> Items { get { return items.Values.ToList(); } }
it starts to work.
Then, when I comment out the part which sends PropertyChanged event it stops working again, which suggests that the event is being sent correctly.
So if the list receives the event, why can't it update its contents correctly in the first version, without the ToList call?
Raising the PropertyChanged event for the Items property is only effective if the property value has actually changed. While you raise the event, the WPF binding infrastructure notices that the collection instance returned by the property getter is the same as before and does nothing do update the binding target.
However, when you return items.Values.ToList(), a new collection instance is created each time, and the binding target is updated.
A listbox data template doesn't show and I cannot figure out why.
If I don't use a DataTemplate and copy the contents into the control section itself, it's fine.
I don't do very much binding in XAML, I usually do it all in code. What did I do wrong?
XAML
<UserControl x:Class="Cis.CustomControls.CisArrivalsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="296" Width="876">
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate">
<ListBoxItem>
<StackPanel>
<TextBlock Background="Blue" Text="{Binding Path=StationName}" />
<TextBlock Background="Brown" Text="{Binding Path=ArrivalPlatform}" />
</StackPanel>
</ListBoxItem>
</DataTemplate>
</UserControl.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<ListBox Width="487" Margin="0,66,0,33" ItemTemplate="{StaticResource DataTemplate}">
</ListBox>
</StackPanel>
</Grid>
</UserControl>
CS
public partial class CisArrivalsPanel : UserControl
{
public CisArrivalsPanel()
{
InitializeComponent();
this.DataContext = new ArrivalRowItem();
}
}
Model
public class ArrivalRowItem : INotifyPropertyChanged
{
public ArrivalRowItem()
{
this.StationName = "Lincoln";
this.ArrivalPlatform = "1";
}
private string _stationName;
public string StationName
{
get
{
return _stationName;
}
set
{
_stationName = value;
NotifyPropertyChanged("StationName");
}
}
private string _arrivalPlatform;
public string ArrivalPlatform
{
get
{
return _arrivalPlatform;
}
set
{
_arrivalPlatform = value;
NotifyPropertyChanged("ArrivalPlatform");
}
}
private DateTime _arrivalDateTime;
public DateTime ArrivalDateTime
{
get
{
return _arrivalDateTime;
}
set
{
_arrivalDateTime = value;
NotifyPropertyChanged("ArrivalDateTime");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
You have everything set up, but you don't actually have any data.
ListBox, like other ItemsControls acts against a collection of data, and generates an instance of the template for each item it finds.
Given that you haven't set ItemsSource or populated any collection I can see, you need to create a collection (probably an ObservableCollection) and set the ItemsSource to it via binding. Then add some items to it, and the ListBox will display them!