При добавлении\удалении элемента в коллекции, View не отображает изменения количества элементов. Так же как и при изменении статуса в вложенном объекте.
public class GroupComputersVM : BaseVM
{
public GroupComputersVM(string name)
{
Name = name;
}
private string _Name;
public string Name { get { return _Name; } set { _Name = value; OnPropertyChanged("Name"); } }
public string Online { get { return ComputersList.Where(x => x.Status).Count().ToString() + @"/" + ComputersList.Count.ToString(); } }
private ObservableCollection<ComputerVM> _ComputersList = new ObservableCollection<ComputerVM>();
public ObservableCollection<ComputerVM> ComputersList { get { return _ComputersList; } set { _ComputersList = value; } }
}
public class ComputerVM : BaseVM
{
private string _Name;
public string Name { get { return _Name; } set { _Name = value; OnPropertyChanged("Name"); } }
private bool _Status;
public bool Status { get { return _Status; } private set { _Status = value; OnPropertyChanged("Status"); } }
}
MainWindowViewModel:
public class MainWindowViewModels : ViewModelBase
{
public MainWindowViewModels(LogicVM logicVM)
{
GroupList = logicVM.GroupList; // поле: public ObservableCollection<GroupComputersVM> GroupList
}
public ObservableCollection<GroupComputersVM> GroupList { get; set; }
}
View:
<ListBox ItemsSource="{Binding GroupList}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140*"/>
<ColumnDefinition Width="30*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Name}" Padding="3,0,0,0" VerticalContentAlignment="Center"/>
<Label Content="{Binding Online}" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
UPD
Посмотрев на ваш скриншот я понял, что вам нужно просто вывести группы и кол-во объектов. Ок, давайте разберемся сколько уровней у нас будет:
Я сделал пометки "(обновляемое)" у тех свойств, которым надо реализовать INPC. Ну что, давайте приступим к реализации!
Что это и как использовать?
Ну для начала представим, что на нашей View есть некое текстовое поле в которое мы вводим текст. Как поведет себя программа, если у нас сделана простая привязка к некому свойству Text? В основном из кода вы увидите изменения свойства, но что если наоборот, нам надо изменить значение в коде и что бы оно изменилось в нашей View? Вот в таком случае наш интерфейс не будет знать о том, что свойство было изменено. Для оповещений собственно и используется INPC. Есть как минимум 2 коллекции, которые уже реализуют подобные интерфейсы - это ObservableCollection и BindingList. Для них нет необходимости городить сотню INPC (как у вас).
Хорошо, давайте сделаем базовый класс, который в последующим будем использовать:
public class VM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ViewModel - это некая прослойка между Model и View в которой реализуется логика для определенного элемента. В нашем случае нужно создать 3 VM (item, group и main).
ItemViewModel - как мы уже определили, в ней должно находится 2 свойства, это имя и статус. Статус у нас может обновится из кода, по этому надо реализовать INPC (наследуемся от ранее созданного класса). Код у нас будет примерно таким:
public class ItemViewModel : VM
{
public string Name { get; set; }
private bool status;
public bool Status
{
get => status;
set
{
status = value;
OnPropertyChanged();
}
}
}
GroupViewModel - тут также потребуется имя, кол-во онлайн и коллекция. Счетчик онлайн у нас обновляется (реализуем INPC). Что касается коллекции, то нам надо отслеживать статус элементов. Для этого я буду использовать BindingList и подпишусь на ListChanged событие, которое будет вызывать обновление счетчика онлайн. Код в итоге будет примерно следующим:
public class GroupViewModel : VM
{
public GroupViewModel()
{
List.ListChanged += ListOnListChanged;
}
public string Name { get; set; }
public BindingList<ItemViewModel> List { get; set; } = new BindingList<ItemViewModel>();
private int online;
public int Online
{
get => online;
set
{
online = value;
OnPropertyChanged();
}
}
private void ListOnListChanged(object sender, ListChangedEventArgs e)
{
//if (e.ListChangedType == ListChangedType.ItemChanged)
UpdateOnline();
}
private void UpdateOnline() => Online = List.Count(x => x.Status);
}
Видите закомментированную строку? Так мы можем сделать ограничение, при котором будет обновлять статус (к примеру только при изменении, или только при добавление).
MainViewModel - Это уже наша основная VM, которая в свою очередь привязывается. В ней мы создаем основную коллекцию наших групп, ну и для теста заполним ее:
public class MainViewModel
{
public MainViewModel()
{
Groups.Add(new GroupViewModel{Name = "Машины"});
var machine = Groups.FirstOrDefault(x => x.Name == "Машины")?.List;
machine?.Add(new ItemViewModel{Name = "Машина 1", Status = true});
machine?.Add(new ItemViewModel{Name = "Машина 2", Status = true});
machine?.Add(new ItemViewModel{Name = "Машина 3", Status = false});
}
public ObservableCollection<GroupViewModel> Groups { get; set; } = new ObservableCollection<GroupViewModel>();
}
Супер, осталось только привязать это все дело, я это сделаю в MainWindow таким способом:
private MainViewModel MainViewModel { get; } = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = MainViewModel;
}
В самом XAML я лично нечего мудрить не буду, сделаю просто вывод кол-ва элементов коллекции и саму коллекцию:
<StackPanel>
<TextBlock Text="{Binding Groups.Count, StringFormat=Группы: {0}}"/>
<ListBox ItemsSource="{Binding Groups}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="5,0"/>
<TextBlock>
<Run Text="{Binding Online, Mode=OneWay}"/>
<Run Text="/"/>
<Run Text="{Binding List.Count, Mode=OneWay}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
Вот и все. Вообще по хорошему группировку делать с помощью GroupDescriptions, но в вашем случае без вывода я не знаю, есть ли смысл...
Сам результат:
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
1Получить от пользователя (путем ввода с консоли) множество строк и сформировать из них список (список 1)