조쉬 스미스의 릴레이 명령 이행에 결함이 있습니까?
모델-뷰-뷰 모델 설계 패턴과 함께 WPF Apps With The Model-View Model Design Pattern(모델-뷰-뷰 모델 설계 패턴과 함께 사용) 참조, 구체적인 예는 다음과 같습니다.RelayCommand
(그림 3). (이 질문에 대한 전체 기사를 읽을 필요는 없습니다.)
일반적으로 이행이 훌륭하다고 생각합니다만, 그 위임에 대해 질문이 있습니다.CanExecuteChanged
의 기부금.CommandManager
의RequerySuggested
이벤트. 상태에 대한 문서:
이 이벤트는 정적이므로 약한 참조로만 처리기를 유지합니다.이 이벤트를 수신하는 개체는 이벤트 처리기에 대한 강력한 참조를 유지하여 가비지 수집을 방지해야 합니다.이 작업은 이 이벤트에 연결하기 전 또는 후에 처리기를 값으로 할당하고 전용 필드를 사용하여 수행할 수 있습니다.
하지만 샘플 구현은 다음과 같습니다.RelayCommand
에서는 구독 처리기에 대한 이러한 작업을 유지 관리하지 않습니다.
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
- 이렇게 하면 약한 기준이 다음으로 누출됩니까?
RelayCommand
의 클라이언트, 사용자에게 요구합니다.RelayCommand
의 구현을 이해합니다.CanExecuteChanged
그리고 그들 자신이 살아있는 참조를 유지합니까? 만약 그렇다면, 예를 들어, 구현을 수정하는 것이 타당합니까?
RelayCommand
잠재적인 조기 GC를 완화하기 위해 다음과 같은 것이 됩니다.CanExecuteChanged
가입자:// This event never actually fires. It's purely lifetime mgm't. private event EventHandler canExecChangedRef; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; this.canExecChangedRef += value; } remove { this.canExecChangedRef -= value; CommandManager.RequerySuggested -= value; } }
Josh의 "Understanding Routed Commands" 기사에서 답을 찾았습니다.
[...] CanExecuteChanged 이벤트에서 WeakEvent 패턴을 사용해야 합니다.이는 시각적 요소가 해당 이벤트를 후크하고 앱이 종료될 때까지 명령 개체가 가비지 수집되지 않을 수 있으므로 메모리 누수의 가능성이 매우 높기 때문입니다. [...]
라는 주장이 나오는 것 같습니다.CanExecuteChanged
구현자는 WPF 이후로 등록된 핸들러에 약하게 고정해야 합니다.Visuals
스스로를 풀기에는 너무 멍청합니다.이것은 가장 쉽게 구현할 수 있습니다.CommandManager
누가 이미 이런 짓을 했습니까?아마도 같은 이유 때문일 것입니다.
저도 이 구현이 결함이 있다고 생각합니다. 왜냐하면 이벤트 처리기에 대한 약한 참조가 확실히 유출되기 때문입니다.이것은 사실 매우 나쁜 것입니다.
MVVM Light 툴킷과RelayCommand
그 안에서 구현되고 그것은 기사에서와 마찬가지로 구현됩니다.
로 다음코드절않호습다니지출을 호출하지 않습니다.OnCanExecuteEditChanged
:
private static void OnCommandEditChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var @this = d as MyViewBase;
if (@this == null)
{
return;
}
var oldCommand = e.OldValue as ICommand;
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= @this.OnCanExecuteEditChanged;
}
var newCommand = e.NewValue as ICommand;
if (newCommand != null)
{
newCommand.CanExecuteChanged += @this.OnCanExecuteEditChanged;
}
}
그러나 이렇게 변경하면 다음과 같이 작동합니다.
private static EventHandler _eventHandler;
private static void OnCommandEditChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var @this = d as MyViewBase;
if (@this == null)
{
return;
}
if (_eventHandler == null)
_eventHandler = new EventHandler(@this.OnCanExecuteEditChanged);
var oldCommand = e.OldValue as ICommand;
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= _eventHandler;
}
var newCommand = e.NewValue as ICommand;
if (newCommand != null)
{
newCommand.CanExecuteChanged += _eventHandler;
}
}
유일한 차이점은? 표에 같이바와의 ,CommandManager.RequerySuggested
필드에 이벤트 처리기를 저장하고 있습니다.
Reflector에서도 RoutedCommand
를 하지 거라고 ;) WPF 팀의 누군가가 실수를 하지 않았다면;)
저는 그것이 결함이 있다고 믿습니다.
이벤트를 Command Manager로 재라우팅하면 다음 동작을 얻을 수 있습니다.
이렇게 하면 WPF 명령 인프라가 모든 RelayCommand 개체에 기본 제공 명령을 요청할 때마다 실행할 수 있는지 여부를 확인할 수 있습니다.
그러나 하나의 명령에 바인딩된 모든 컨트롤에 CanExecute 상태를 재평가하려면 어떻게 됩니까?이 구현에서 명령 관리자로 이동해야 합니다. 즉,
응용 프로그램의 모든 명령 바인딩이 재평가됩니다.
여기에는 전혀 문제가 되지 않는 모든 항목, CanExecute를 평가하는 데 부작용이 있는 항목(예: 데이터베이스 액세스 또는 장시간 실행 작업), 수집 대기 중인 항목 등이 포함됩니다.마치 쇠망치로 못을 박는 것과 같습니다.
당신은 이것을 하는 것의 결과를 진지하게 고려해야 합니다.
여기서 요점을 놓칠 수 있지만 다음은 생성자의 이벤트 처리기에 대한 강력한 참조가 되지 않습니까?
_canExecute = canExecute;
언급URL : https://stackoverflow.com/questions/2281566/is-josh-smiths-implementation-of-the-relaycommand-flawed
'it-source' 카테고리의 다른 글
GROUP BY와 DISTINCT 사이에 차이가 있습니까? (0) | 2023.05.06 |
---|---|
Swift에서 보기의 모든 하위 보기를 제거하는 방법은 무엇입니까? (0) | 2023.05.06 |
오류: 도커의 Alpine에 psycopg2를 설치할 때 pg_config 실행 파일을 찾을 수 없습니다. (0) | 2023.05.06 |
두 로컬 분기 Git 병합 (0) | 2023.05.01 |
Angular에서 템플릿 HTML 블록을 재사용하는 방법은 무엇입니까? (0) | 2023.05.01 |