1. 서론 — MAUI에서 Command가 두 번 실행되는 문제, 단순한 버그가 아니다
MAUI에서 Button, ImageButton, CollectionView의 ItemTapped, 또는 TapGestureRecognizer를 사용할 때 다음과 같은 현상이 보고된다.
- Command가 한 번 눌렀는데 두 번 실행된다
- TapGestureRecognizer가 연속해서 두 번 호출된다
- Button Command와 TapGestureRecognizer가 동시에 호출된다
- ItemSelected와 TapGestureRecognizer가 중복 호출된다
- Navigation도 두 번 실행돼 화면이 두 번 push되는 현상이 나타난다
이 문제는 단순한 실수가 아니라 MAUI 이벤트 구조의 특성 때문이다.
MAUI는 이벤트가 Native → Handler → VirtualView → BindingContext(Command)로 전달되며, 특히 GestureRecognizer의 버블링(Bubbling), 터치 중복 처리, ItemTapped와 TapGestureRecognizer 간 충돌이 주요 원인이 된다.
이 글에서는 Command가 두 번 실행되는 구조적 원인을 깊이 있게 분석하고, 실전 프로젝트에서 문제를 예방하고 해결하는 전략을 정리한다.

2. Command가 두 번 실행되는 핵심 원인 분석
원인 1: Button 클릭 + TapGestureRecognizer가 동시에 작동
예를 들어 다음과 같은 구조:
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" />
</StackLayout.GestureRecognizers>
<Button Text="OK" Command="{Binding TapCommand}" />
</StackLayout>
Button을 눌렀을 때:
- Button.Command 실행
- 부모 StackLayout의 TapGestureRecognizer 실행
따라서 Command가 2번 호출된다.
원인 2: CollectionView의 SelectionChanged와 TapGestureRecognizer 중복 호출
많이 발생하는 패턴:
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ItemClickCommand}" />
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
문제는 CollectionView가 기본적으로 다음 이벤트를 가지고 있다는 점이다.
- SelectionChanged
- ItemTapped(플랫폼별)
- TapGestureRecognizer
즉, 하나의 터치가 다음 같은 흐름으로 전달된다.
- 셀 선택 (SelectionChanged)
- 셀 탭 이벤트 (ItemTapped)
- GestureRecognizer 호출
그 결과 Command가 2~3번씩 실행될 수 있다.
원인 3: TapGestureRecognizer가 "Pressed"와 "Released"를 모두 감지하는 구조
MAUI의 TapGestureRecognizer는 단순한 “탭”이 아니라
Native Touch 이벤트 두 개를 감지한다.
- Touch Down
- Touch Up
일부 플랫폼에서는 이게 두 번 전달되며,
MAUI가 이를 완전히 통합하지 못해 Command가 중복 호출되기도 한다.
원인 4: Button과 GestureRecognizer의 터치 버블링(Bubbling)
MAUI 이벤트는 다음 방향으로 전달된다.
자식 → 부모 → Shell (Root)
즉, Button을 눌러도 부모 레이아웃의 GestureRecognizer가 호출되는 구조다.
이벤트를 “막지” 않으면 Command는 여러 번 동작하게 된다.
원인 5: CommandParameter null 비교나 Task 실행 지연으로 인한 중복 처리
Command 내부 로직이 다음과 같을 경우:
{
_isRunning = true;
await Task.Delay(10);
_isRunning = false;
}
UI 스레드 이벤트가 두 번 발생할 경우
딜레이 때문에 두 번 진입하는 상황도 발생한다.
3. 실전에서 실제로 발생하는 중복 호출 문제 사례
❌ 사례 1 — CollectionView 셀 클릭 시 Navigation이 두 번 실행됨
원인: SelectionChanged + TapGestureRecognizer 충돌
❌ 사례 2 — Button을 눌렀는데 상위 StackLayout TapGestureRecognizer도 작동
원인: 터치 버블링
❌ 사례 3 — 동일 Command가 Pressed/Released에 의해 2회 호출
원인: GestureRecognizer 처리 방식
❌ 사례 4 — Custom Control 내부에서 Button과 TapRecognizer를 함께 사용
원인: NativeHandler 중복 전달

4. MAUI에서 Command 중복 실행을 방지하는 정석 해결 전략
여기서는 실무에서 가장 안정적으로 검증된 방법 5가지를 제시한다.
✔ 해결 전략 1: Button 내부에는 GestureRecognizer를 절대 섞지 않는다
가장 중요한 원칙:
Button 클릭은 Button만 담당하게 하라.
GestureRecognizer는
- 이미지
- 카드
- 레이아웃 전체
같은 “광역 클릭 UI”에만 사용해야 한다.
✔ 해결 전략 2: CollectionView에서는 TapGestureRecognizer 대신 SelectionChanged를 사용
SelectionMode="Single"
SelectionChanged="OnItemSelected">
TapGestureRecognizer를 쓰면:
- Pressed
- Released
- Tapped
- Native Tap
등이 모두 섞여 중복 실행 위험이 높아진다.
SelectionChanged가 가장 안정적인 방식이다.
✔ 해결 전략 3: GestureRecognizer에서 터치 이벤트 버블링을 막기
MAUI는 이벤트 취소(Handled)를 기본 제공하지 않지만
이 패턴으로 간접적으로 해결할 수 있다.
void OnTapped(object sender, TappedEventArgs e)
{
if (_tapped) return;
_tapped = true;
Task.Delay(100).ContinueWith(_ => _tapped = false);
// Command 실행
}
이 방식으로 중복 탭을 100ms 안에 차단할 수 있다.
✔ 해결 전략 4: Command 중복 실행 방지용 “Busy 플래그 패턴”
ViewModel:
public ICommand MyCommand => new Command(async () =>
{
if (_isBusy) return;
_isBusy = true;
try
{
await DoWork();
}
finally
{
_isBusy = false;
}
});
이 패턴은 MAUI에서 매우 널리 사용되는 정석이다.
✔ 해결 전략 5: Navigation 중복 Push 방지
return;
await Shell.Current.GoToAsync(nameof(DetailPage));
Navigation 중복 발생을 완벽히 방지한다.
5. 문제 해결 후의 아키텍처 설계 원칙
Command 중복 실행을 막기 위해서는 다음 구조적 설계가 필요하다.
- Button 내부에는 GestureRecognizer를 사용하지 않는다
- CollectionView는 SelectionChanged 중심 구조로 재설계한다
- GestureRecognizer는 레이아웃 수준에서만 사용한다
- Busy 플래그로 Command 재진입을 방지한다
- Navigation 흐름에서 중복 Push를 차단한다
이 규칙만 지켜도 중복 호출 문제의 90% 이상은 해결된다.
마무리 — 이벤트 흐름을 이해하면 Command 구조가 완전히 안정된다
MAUI에서 Command가 두 번 실행되는 문제는
단순 이벤트 버그가 아니라:
- Native Touch 이벤트
- GestureRecognizer 처리 방식
- 이벤트 버블링
- SelectionChanged와 Tap 충돌
- Navigation 중복 처리
이 복합적으로 얽혀 있는 구조적인 문제다.
이 글에서 소개한 해결 전략을 적용하면
중복 Command 실행 문제를 근본적으로 해결할 수 있고
UI 안정성이 크게 향상된다.
'MAUI CollectionView 문제 해결 > Korean Version' 카테고리의 다른 글
| MAUI Entry TextChanged 딜레이 문제 해결, 입력 지연의 내부 구조 분석과 최적화 전략 (0) | 2025.12.12 |
|---|---|
| MAUI CollectionView 스크롤 초기화 문제 해결, Virtualization과 데이터 갱신 구조 분석 (0) | 2025.12.11 |
| MAUI CollectionView에서 체크박스 선택 상태가 반영되지 않을 때 반드시 확인해야 하는 구조적 문제와 해결 전략 (0) | 2025.12.11 |
| MAUI Dependency Injection 적용 실패 문제 해결, IHostBuilder 구조 분석과 실전 대응 전략 (0) | 2025.12.11 |
| MAUI CommandParameter 전달 실패 문제 해결, 구조적 원인 분석과 실전 대응 전략 (0) | 2025.12.10 |