Имея ObservableCollection, которая заполняется наблюдаемой, я хотел бы знать, какой самый эффективный и правильный способ обновить элемент ViewModel в коллекции, если он уже существует. Я придумал 2 решения:
Раствор 1
Сделайте MainViewModel ответственным, чтобы определить, существует ли элемент в ObservableCollection, если да, выполните обновление:
MainViewModel.cs
private readonly SortedObservableCollection<IConversationPreviewViewModel> _conversationPreviews = new SortedObservableCollection<IConversationPreviewViewModel>();
public void SubscribeOnConversations()
{
_observeConversationsUseCase
.Conversations
.ObserveOn(_schedulerProvider.Dispatcher)
.Subscribe(OnNext);
}
private void OnNext(Conversation conversation)
{
var previewViewModel = _conversationPreviews.FirstOrDefault(it => it.ConversationId == conversation.ConversationId);
if (previewViewModel == null)
{
IConversationPreviewViewModel conversationPreview = _conversationPreviewFactory.Create(conversation);
_conversationPreviews.Add(conversationPreview);
}
else
{
previewViewModel.UpdateConversation(conversation);
}
}
Решение 2
Модель основного вида отвечает только за добавление новых элементов, но за обновление отвечает каждая модель представления самого элемента, подписывая каждую на наблюдаемую:
public class Conversation
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ConversationItemViewModel
{
private int Id { get; set; }
public string Text { get; private set; }
public ConversationItemViewModel(Conversation conversation, ObserveConversations observeConversations)
{
Id = conversation.Id;
Text = conversation.Name;
PrintStatus("ctor");
observeConversations.Conversations.Where(it => it.Id == Id).Subscribe(OnNext);
}
private void OnNext(Conversation conversation)
{
Text = conversation.Name;
PrintStatus("OnNext");
}
private void PrintStatus(string from)
{
Console.WriteLine($"Id:{Id} Text:{Text} From: {from}");
}
}
public class ObserveConversations
{
public IConnectableObservable<Conversation> Conversations { get; }
public ObserveConversations()
{
Conversations = ConversationsArriving();
Conversations.Connect();
}
public IConnectableObservable<Conversation> ConversationsArriving()
{
var list = new List<Conversation>() { new Conversation(){Id = 1, Name = "name1"},
new Conversation() {Id = 2, Name = "name2" },
new Conversation() {Id = 3, Name = "name3"},
new Conversation() {Id = 2, Name = "updatedname2"}, // Update this
new Conversation() {Id = 4, Name = "name4"},
new Conversation() {Id = 3, Name = "updatedname3"}, // Update this
};
return list.ToObservable().Delay(TimeSpan.FromSeconds(1)).Publish();
}
}
public class MainViewModel
{
private readonly ObserveConversations _observeConversations;
public MainViewModel(ObserveConversations observeConversations)
{
_observeConversations = observeConversations;
}
private ObservableCollection<ConversationItemViewModel> ConversationItemViewModels { get; } = new ObservableCollection<ConversationItemViewModel>();
public void Start()
{
_observeConversations.Conversations
.Distinct(it => it.Id)
.Subscribe(OnNext);
}
private void OnNext(Conversation conversation)
{
ConversationItemViewModels.Add(new ConversationItemViewModel(conversation, _observeConversations));
}
}
class Program
{
static void Main(string[] args)
{
var observeConversations = new ObserveConversations();
var mainViewModel = new MainViewModel(observeConversations);
mainViewModel.Start();
Console.ReadLine();
}
Лично я считаю решение 2 лучше, так как оно делегирует ответственность за обновление каждому ViewModel
каждому себе.
- Есть ли более мелкозернистый раствор, чем те?
- Может ли создание нескольких подписок для каждого элемента
ViewModel
в решении 2 создать проблемы с производительностью?