I work with an MVVM WPF application that uses Binding
s. It has the following simplified code:
XAML
<TabControl x:Name="tbcGeneral"
DataContext="{Binding Path=AppCoreInstance, RelativeSource={RelativeSource AncestorType=local:FirstWindow}}">
<Button x:Name="btnAssignPilot"
Command="{Binding Path=JobManagingInstance.AssignPilotCommand}">
<Label x:Name="lblAssignPilot"
Content="_Assign pilot"/>
</Button>
<DataGrid x:Name="dgrMannedSpaceships"
ItemsSource="{Binding Path=HRManagementInstance.AvailableSpaceships}"
AutoGenerateColumns="False"
IsReadOnly="True"
SelectedItem="{Binding Path=HRManagementInstance.CurrentSpaceship}"
IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Spaceship number"
Binding="{Binding NumSpaceship}"/>
<DataGridTextColumn Header="Name"
Binding="{Binding SpaceshipName}"
Width="*"/>
<DataGridTextColumn Header="Pilot ID"
Binding="{Binding PilotId}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</TabControl>
ViewModel
ISpaceShip
public interface ISpaceShip : ISignalModifBase
// ISignalModifBase inherits from INotifyPropertyChanged; as noted
// below, its implementation has a method that manages the contents
// of a standard set method.
{
string NumSpaceship { get; set; }
string SpaceshipName { get; set; }
string PilotId { get; set; }
}
SpaceShip
public class SpaceShip : SignalModifBase, ISpaceShip
{
public string NumSpaceship { get; set; }
public string SpaceshipName { get; set; }
private string _strPilotId = "";
public string PilotId
{
get => _strPilotId;
set => ManagePropertyChange(ref _strPilotId, value);
// ManagePropertyChange is a method from SignalModifBase that does the usual Binding-friendly setting
// stuff of setting the property and invoking PropertyChanged .
}
}
IHRManagement
public interface IHRManagement : IBaseModule
// IBaseModule inherits from ISignalModifBase, which, in turn, inherits from INotifyPropertyChanged
{
ObservableCollection<ISpaceShip> AvailableSpaceships { get; set; }
ISpaceShip CurrentSpaceship { get; set; }
bool AssignPilots();
}
HRManagement
public class HRManagement : BaseModule, IHRManagement
{
private ObservableCollection<ISpaceShip> _obcAvailableSpaceships = new();
public ObservableCollection<ISpaceShip> AvailableSpaceships
{
get => _obcAvailableSpaceships;
set => ManagePropertyChange(ref _obcAvailableSpaceships, value);
}
private ISpaceShip? _objCurrentSpaceship = null;
public ISpaceShip? CurrentSpaceship
{
get => _objCurrentSpaceship;
set => ManagePropertyChange(ref _objCurrentSpaceship, value);
}
bool AssignPilots()
{
string z_strData;
StreamReader z_sreData;
// Set z_sreData
foreach (ISpaceShip z_objShip in AvailableSpaceships)
{
CurrentSpaceship = z_objShip;
string z_strPilotId;
// Figure out which pilot ID goes on this ship and set it in z_strPilotId
CurrentSpaceship.PilotId = z_strPilotId;
}
}
}
I’m leaving out the infrastructure for relative brevity, as well as a lot of other code that doesn’t have a direct impact on the issue.
There’s another method in IHRManagement
and HRManagement
that fills AvailableSpaceships
and is called by another button.
So before I click on btnAssignPilot
, the DataGrid
dgrMannedSpaceships
is full, except its column “Pilot ID” is empty. When I click on the button, the column “Pilot ID” remains empty; when the job ends (or when I interrupt it in debug, jumping to the end of the method), it fills up entirely.
I’d like to see the column fill one cell after another, and from what I’ve seen here, and on various other Web sites it should. (I’ve tried to add Mode=OneWay
to the ItemsSource
Binding
from this, to no avail.) What did I miss?
I’m using .Net 8.0, if it helps.
2