I have a development environment with the 4.8 .net framework. I am trying to display a dictionary of this RemoteUnit class in a ListView, but the list view is remaining unpopulated even when I've confirmed the dictionary has items.
Here is my code
RemoteUnit.cs
public class RemoteUnit : INotifyPropertyChanged
{
public string Id { get { return _uid; } set { _uid = value; NotifyPropertyChanged(); } }
public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged(); } }
public bool Alive { get { return _alive; } set { _alive = value; NotifyPropertyChanged(); } }
public bool Subscribed { get { return _subscribed; } set { _subscribed = value; NotifyPropertyChanged(); } }
}
RemoteUnitTab.xaml
<ListView Grid.Row="0" Name="LstRemoteUnits" Height="Auto" Margin="5,5,5,5" Background="White" ItemsSource="{Binding Path=RemoteUnits.UnitDict}">
<ListView.View>
<GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Remote Units On Network">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Foreground" Value="Black" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn DisplayMemberBinding="{Binding Path=Value.Name}" Header="Name" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Value.Alive}" Header="Alive" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Value.Subscribed}" Header="Subscribed" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Value.Id}" Header="Uid" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
RemoteUnitTab.xaml.cs
public partial class UnitsOnNetworkControl : UserControl
{
private UnitsData RemoteUnits;
public UnitsOnNetworkControl()
{
InitializeComponent();
RemoteUnits = GlobalUnitReference.GetReference();
// .. other initialization stuff
LstRemoteUnits.ItemsSource = RemoteUnits.UnitDict;
LstRemoteUnits.DisplayMemberPath = "Value";
LstRemoteUnits.SelectedValuePath = "Key";
}
}
Like I said, the listview is remaining empty.
I found some stackoverflow answers which suggested setting the view to details, which I did like this:
LstRemoteUnits.View = System.Windows.Forms.View.Details;
but I got this error
Cannot implicitly convert type 'System.Windows.Forms.View' to 'System.Windows.Controls.ViewBase'
I am on a tight schedule and need this to work (project demonstration is due next week and I need to be working on more important things), so I am considering scrapping the dictionary binding for a temporary solution such as inserting RemoteUnit items in manually. Problem is, when I directly add the RemoteUnit class (after disabling ItemsSource) in with this:
LstRemoteUnits.Items.Add(remote_unit);
I get empty rows with no text. I tried manually setting sub items, but apparently "subitems" don't exist with my current environment because this code:
ListViewItem item = new ListViewItem();
item.SubItems.Add("foo");
returns the error
'ListViewItem' does not contain a definition for 'SubItems' and no accessible extension method 'SubItems' accepting a first argument of type 'ListViewItem' could be found (are you missing a using directive or an assembly reference?)
Like I said, I am on a tight schedule and need this field to work because its part of the primary interface. Can anyone help me with this?
Thanks.
[Edit - replaced reference to the project's name]
[Edit 2] Figured out the ListViewItem was coming from System.Windows.Controls and not System.Windows.Forms. Using the item from System.Windows.Forms fixes that part of the question.
CodePudding user response:
You have defined the ItemsSource="{Binding Path=RemoteUnits.UnitDict}" in your RemoteUnitTab.xaml.cs
To display binding source you have to define the DataContext of your control. the DataContext must contain a public property RemoteUnits or add the remote units as DataContext and change ItemsSource.
Try to add LstHo2Units.DataContext = Ho2Units and ItemsSource="{Binding Path=UnitDict}"
CodePudding user response:
I think the reason that you don't see anything in your view is because the UI isn't getting notified properly.
Try changing
public partial class UnitsOnNetworkControl : UserControl
{
private UnitsData RemoteUnits;
public UnitsOnNetworkControl()
{
InitializeComponent();
RemoteUnits = GlobalUnitReference.GetReference();
// .. other initialization stuff
LstRemoteUnits.ItemsSource = RemoteUnits.UnitDict;
LstRemoteUnits.DisplayMemberPath = "Value";
LstRemoteUnits.SelectedValuePath = "Key";
}
}
to
public partial class UnitsOnNetworkControl : UserControl, INotifyPropertyChanged
{
private Dictionary<int, RemoteUnit> _remoteUnits = new();
public Dictionary<int, RemoteUnit> RemoteUnits
{
get { return _remoteUnits; }
set
{
_remoteUnits = value;
NotifyPropertyChanged(nameof(RemoteUnits));
}
}
public UnitsOnNetworkControl()
{
InitializeComponent();
DatContext = this;
RemoteUnits = GlobalUnitReference.GetReference();
// .. other initialization stuff
}
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
And then in your xaml Changed your Itemssource Property on your ListView to
ItemsSource="{Binding RemoteUnits}"
You can remove the Path in these cases or keep them. Shouldn't make a difference either way.
So what I did is I implemented the INotifyPropertyChanged Interface in the Code Behind, set Code Behind as the DataContext and made that little change in the xaml Code. With this I managed to get it to work with the code you have provived.
I have also changed the type of your RemoteUnits property from UnitsData to RemoteUnit because I don't see UnitsData anywhere else in your code so I assumed this to be a copy paste error or something.