본문 바로가기

CollectionView에서 부분 업데이트(Partial Update)가 반영되지 않는 이유

@veedeeo 2025. 12. 22. 13:47

INotifyPropertyChanged·Virtualization·재활용 충돌 구조 분석과 완전 해결법


1, 서론

MAUI 초보·중급 개발자에게 가장 혼란스러운 문제 중 하나가 바로 이것이다.

“데이터는 분명 바뀌었는데, 화면은 왜 안 바뀌는가?”

특히 다음 상황에서 자주 나타난다.

  • 하나의 항목 데이터만 갱신했는데 UI는 그대로
  • ObservableCollection인데도 변경 반영 안 됨
  • 바인딩 업데이트가 너무 늦게 일어나거나 스크롤해야 적용
  • 빠른 스크롤 중 UI 업데이트가 누락됨
  • 템플릿의 일부 UI만 반영되고 나머지는 이전 상태 유지

이 문제는 단순한 기능 누락이 아니라
MAUI 리스트 렌더링의 구조적 이유 때문이다.

부분 업데이트 실패의 원인을 정확히 이해해야
UI 안정성과 성능을 모두 확보할 수 있다.

 

요약 카드

제목
CollectionView 부분 업데이트가 반영되지 않는 진짜 이유와 완전 해결법

요약

  • CollectionView는 셀을 자동 전체 갱신하지 않으며, 변경된 속성만 해당 UI 요소로 직접 반영된다. INotifyPropertyChanged가 정확히 동작하지 않거나 PropertyName이 잘못 전달되면 UI는 갱신되지 않는다.
  • 셀 재활용(Recycling) 구조 때문에 이전 UI 상태가 섞이며, 스크롤할 때만 값이 갱신되는 등 UI 오염(State Leakage) 이 발생할 수 있다.
  • ObservableCollection이 아닌 List 사용, 템플릿 변경 감지 불가, 가상화(Virtualization) 구간에서 갱신 누락, Auto Height 컨트롤로 인한 Measure 지연 등이 부분 업데이트 실패의 핵심 원인이다.
  • 해결 핵심은 정확한 INotifyPropertyChanged, ObservableCollection 유지, OnBindingContextChanged UI 초기화, Auto Height 제거, 템플릿 변경 시 전체 갱신, Virtualization을 고려한 업데이트 타이밍 제어다.
  • 고급 전략으로는 수동 Refresh, ScrollTo 기반 재노출, PreMeasure 조합 등을 사용해 빠른 연속 업데이트에서도 완전한 반영을 보장할 수 있다.

CollectionView에서 부분 업데이트(Partial Update)가 반영되지 않는 이유


2, 문제 정의 — 부분 업데이트 실패가 나타나는 대표 증상

✔ 2.1 NotifyPropertyChanged 발동했는데 UI가 그대로

✔ 2.2 텍스트만 갱신되고 이미지나 색상은 이전 상태 유지

✔ 2.3 셀의 일부 요소만 바뀌고 일부는 바뀌지 않음

✔ 2.4 스크롤을 해야 화면이 바뀜

✔ 2.5 빠르게 갱신하면 중간 값이 화면에 반영되지 않음

이 문제는 MAUI 내부 구조를 알면 전부 설명할 수 있다.


3, 내부 구조 분석 — “CollectionView는 셀 UI 전체를 자동 갱신하지 않는다”

핵심 원리:

CollectionView는 항목의 속성이 변화해도 셀 전체를 재렌더링하지 않는다.
바뀐 속성만 개별 라벨·이미지·프레임 등이 직접 반영해야 한다.

즉 다음 두 조건 중 하나라도 충족하지 않으면 UI는 갱신되지 않는다.

1) INotifyPropertyChanged가 정확한 PropertyName으로 호출

2) 해당 UI 요소가 OneWay 바인딩으로 값 반영 가능

또한 재활용 구조 때문에
UI 상태 데이터가 서로 섞여 “오염”될 수도 있다.


4, 부분 업데이트가 실패하는 8가지 주요 원인


✔ 원인 1 — INotifyPropertyChanged의 PropertyName 잘못 전달

가장 흔한 실수:

OnPropertyChanged(nameof(Namee)); // 오타
 
 

또는:

OnPropertyChanged(null); // 전체 갱신이지만 비추천
 
 

또는:

PropertyChanged 이벤트를 아예 호출 안 함.


✔ 원인 2 — 속성이 바뀌었는데 UI는 Auto Height 구조 때문에 다시 렌더링되지 않음

예:

<Frame BackgroundColor="{Binding IsNew, Converter={...}}" />
 
 

IsNew 값은 바뀌었지만
셀 높이가 바뀌지 않아 Measure/Arrange가 동작하지 않으면
일부 플랫폼에서 UI 업데이트 타이밍이 늦어질 수 있다.


✔ 원인 3 — 값이 바뀌어도 실제로는 동일한 참조

예:

리스트 아이템을 새로운 객체로 교체했지만 BindingContext는 이전 객체를 유지.


✔ 원인 4 — DataTemplate 내부 UI가 재활용으로 인해 이전 상태 유지

초기화 누락 문제:

  • 이전 셀의 색상
  • 이전 셀의 체크박스
  • 이전 셀의 이미지를 그대로 표시

즉, UI가 갱신되기 전에 재활용된 상태가 먼저 그려짐.


✔ 원인 5 — ObservableCollection이 아닌 일반 List 사용

List는 부분 갱신을 CollectionView에 알리지 않는다.


✔ 원인 6 — DataTemplateSelector가 변경되었지만 템플릿이 다시 적용되지 않음

MAUI는 템플릿 변화를 감지하지 못한다.


✔ 원인 7 — 빠른 부분 갱신 중 Binding이 여러 프레임에 걸쳐 지연

특히 이미지나 색상 업데이트는 프레임 기반이다.


✔ 원인 8 — CollectionView Virtualization이 덮어쓰기

빠르게 스크롤하는 중에 PropertyChanged가 발생하면
현재 셀 UI보다 “가상화 재활용”이 우선하여 UI가 갱신되지 않을 수 있다.


5, 해결 전략 — 부분 업데이트 안정화를 위한 전문가 패턴


✔ 전략 1 — INotifyPropertyChanged 100% 정확 구현

 
private string _title;
public string Title
{
    get => _title;
    set { _title = value; OnPropertyChanged(); }
}
 
 

반드시 CallerMemberName을 활용하라.


✔ 전략 2 — ObservableCollection + 개별 속성 갱신 조합

부분 업데이트는 Collection 변경이 아닌
“항목의 속성 변화”로 처리해야 한다.

나쁜 예:

Items[index] = new Item(); // BindingContext 변경됨
 
 

좋은 예:

Items[index].IsNew = true;

✔ 전략 3 — OnBindingContextChanged에서 UI 초기화 필수

이전 셀의 UI 상태가 섞여서 업데이트가 사라지는 문제 방지.


✔ 전략 4 — ValueChanged에 의존하는 UI는 강제 Refresh 필요

예:

 
Device.BeginInvokeOnMainThread(() =>
{
    Frame.BackgroundColor = Item.IsNew ? Colors.Gold : Colors.Transparent;
});
 
 

이는 비싼 구조이지만 정밀 제어가 가능하다.


✔ 전략 5 — DataTemplateSelector 사용 시 템플릿 변경은 셀 갱신 불가

템플릿을 바꿔야 하는 경우:

  1. ItemsSource 전체 재할당 or
  2. 해당 아이템 Remove/Add

둘 중 하나가 필요하다.


✔ 전략 6 — Virtualization 중 업데이트하려면 ScrollTo로 셀 강제 노출

가상화된 항목은 PropertyChanged가 호출되어도 UI가 없다.
따라서 업데이트가 “나중에” 적용될 수 있다.

필요하면:

CollectionView.ScrollTo(index);

✔ 전략 7 — 색상·이미지·아이콘 등 UI 변동 요소는 “불변 구조”로 설계

예:

Frame 높이 변동 금지
Image HeightRequest 지정
Label MaxLines 설정

UI 크기가 변하지 않으면 업데이트가 안정적으로 반영된다.


✔ 전략 8 — 빠른 갱신은 배치(Batch) 처리

 
foreach(var item in Items)
    item.IsNew = false;
 
 

→ 이때 PropertyChanged가 수십 번 발생한다.

Batch 방식:

 
foreach(var item in Items)
    item.SetFlagSilently = false;

OnPropertyChanged(nameof(Items));
 
 

효율 + 갱신 안정성 증가.


6, 고급 전략 — 강력한 “셀 수동 업데이트(Cell Manual Refresh)”

큰 앱에서는 다음과 같은 직접 갱신 방식을 사용한다.

예: 특정 셀 UI만 강제 Refresh

 
var view = CollectionView.GetItemView(item);
view.InvalidateMeasure();
view.Handler?.UpdateValue(nameof(View.BindingContext));
 
 

이 방식은 UI 변동이 매우 미세한 경우에 사용되는 상급 기술이다.


7, 결론

CollectionView 부분 업데이트 실패의 핵심 원인:

  • PropertyChanged 전달 누락
  • 재활용된 셀의 이전 상태가 먼저 그려짐
  • DataTemplate 내부 UI의 Auto Height
  • Virtualization이 UI 업데이트를 덮어씀
  • 이미지·색상 등 비동기 요소가 업데이트 순서 뒤엎음

완전 해결 핵심:

✔ 정확한 INotifyPropertyChanged
✔ ObservableCollection 유지
✔ UI 초기화
✔ Auto 크기 제거
✔ DataTemplateSelector 변경 시 전체 갱신
✔ Virtualization을 고려한 업데이트 타이밍
✔ 필요한 경우 수동 Refresh

이 원리를 이해하면
MAUI CollectionView의 가장 까다로운 문제 중 하나인
부분 업데이트 실패 문제를 100% 재현·해결 할 수 있다.

veedeeo
@veedeeo :: .net MAUI·Netlify·SEO·웹 최적화 기술 블로그

.net MAUI·Netlify·SEO·웹 최적화 기술 블로그

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차