wpf 공부 중에 쓰레드나 비동기 메소드등이 mvvm패턴 어디에 위치 해야 합당한 것일지 궁금합니다

윈폼에서 wpf 넘어오는 과정으로 열심히 스터디 하고 있습니다.
유투브 등을 통하여 따라하고 분석해보는 중에 UI 쓰레드와 따로 생성하는 쓰레드나 비동기 메소드, 타이머 등 mvvm 중 어디에 위치하는것이 합당 한 가에 대해 궁금해서 몇일 검색을 통해 알아보고자 했지만 언급한 곳이 없었습니다.
모델-모델뷰 두 곳 중 한곳에서 그러한 로직을 처리 하는 것이 맞는 것 같은데 어떠한 기준이 있는지요?

2개의 좋아요

일반적으로 ViewModel에서 합니다.

1개의 좋아요

어떤 속성의 데이터냐에 따라 다른 것 같다고 생각합니다.

단순하게 비동기 메서드나 스레드로 구분하진 않는 것 같습니다.

뷰에 의존한 처리는 코드비하인드에서 처리하고 분리된 데이터라면 모델이나 연계된 뷰모델에서 처리하는게 맞을 것입니다.

코드비하인드에서도, 뷰모델에서도 스레드는 사용해도 전혀 문제가 되지 않다고 생각합니다.

mvvm도 사람마다 기준이 많이 다르기도하고, wpf가 원조 mvvm이긴 하지만 오히려 mvvm이 연구가 많이 된 다른 기술들도 함께보시면 기준자체는 명확하게 잡히지 않을까 합니다.


저의 경우엔 뷰모델에서 되도록 ui에 의존한 네임스페이스를 참조하지 않으려 부단히 노력합니다.

그게 코드의 수와 복잡도, 많은 파일 수를 만들어내지만 오히려 그렇게 되는 것이 개발할땐 복잡하게 하는 것 같다가도 추후에 봤을때 코드가 모듈화가 되어있다보니 편했던 것 같습니다.

ui에 의존해도 되는 사용자 정의 클래스, ui에 의존하지 않아도 되는 사용자 정의 클래스를 구분하는 편이었고

보통은 behavior, attachedproperty, converter가 ui에 의존해도 되는 사용자 정의 클래스였던 것 같고 나머진 아니었던거 같네요.

뷰모델과 뷰가 강하게 커플링이 되면 뷰모델에서 디스페처 관련 오류가 발생하겠으나, 그렇게 되지 않도록 연구된 많은 코드패턴들이 그렇게 안되도록 만들 수 있습니다.

디자인패턴이나 어떤 코딩 철학은 코딩을 하는 때에 중요한 것이지 런타임에서 중요한 건 아니기 때문이죠. 어차피 런타임에선 다 짬뽕되니까요.

mvvm에서 사용되는 여러 용어들이나 방법들을 검토해보시면 스스로 만의 기준이 서실 것 같습니다.

5개의 좋아요

얽… view model 에서 DependencyObject 상속이라니…

5개의 좋아요

일반적으로 mvvm 패턴을 적용했을 때 특정 기능이 어떤 계층에 위치해야 하는지는 어떻게 동작하는지가 아니라, 어떤 동작을 하는지에 따라 결정되게 됩니다.

예를 들어 http 통신을 이용해 지도 api에 접근해 특정 지역의 식당 정보를 수집해 리스트로 제공하고, 상세정보 보기 클릭 시 WebView2를 이용해 인근 지도를 표시하는 기능을 개발한다고 가정해 봅시다.

이 경우, 개발해야 할 파트를 크게 다음과 같이 나눌 수 있을 것입니다.

  1. 지도 api를 활용해 식당 정보를 수집하는 기능
  2. 수집한 식당 리스트를 UI로 표시하는 기능
  3. GPS 정보를 이용해 지도의 url을 가져오는 기능
  4. WebView2에 지도를 표시하는 기능

MVVM 관점에서 각 계층에 위치할 데이터 및 기능은 대략적으로 다음과 같이 나눌 수 있습니다.

  • Model: 식당 정보(이름, 위치, 연락처 등)
  • ViewModel: Model 및 ViewDetailCommand(상세 정보 보기), MapUrl 등
  • View: 리스트박스, WebView2 등
  • Service: API 통신 관련 기능

Http 통신은 비동기 방식으로 구현하는 게 일반적이므로 Service는 비동기 방시으로 설계될 것이고, Service를 호출해 Model을 업데이트하는 ViewModel 역시 비동기 메서드를 구현해야 할 것입니다.

반대로 WebView2는 CoreWebView2를 초기화 해줘야 하는데, EnsureCoreWebView2Async를 호출함으로써 명시적으로 초기화 해줘야 하는 경우가 있습니다. WebView2는 UI 계층에 위치하므로, View에도 역시 비동기 메서드가 구현되게 됩니다.

따라서 비동기 메서드는 반드시 어디에 위치해야 하고, 타이머는 반드시 어디에 위치해야 하는 게 아니라,

어떤 기능인지에 따라 해당 기능이 위치해야 할 계층이 정해진다.

가 결론이 됩니다.

7개의 좋아요

MVVM 관점에서 어떻게 기능을 분리해야 할지 감이 잘 잡히지 않는다면, UI 로직을 기타 다른 것과 분리하려는 노력을 먼저 해보시는 것을 권해드립니다. MVVM 외에도 MVC, MVP 등 UI 관련 디자인 패턴의 목적은 UI 로직과 도메인 로직을 서로 분리하는 것이고, 어떻게 잘 분리할까가 핵심 목표가 됩니다.

다른 분들께서 ViewModel에서 되도록 UI 관련 네임스페이스를 참조하지 않거나 극단적으로 어셈블리 자체를 분리하는 것을 말씀하시는 것도 ViewModel에 UI 관련 로직을 추가하지 않으려는 노력의 산물로 볼 수 있습니다.

4개의 좋아요

@루나시아 님 말씀 대로, 비동기 코드를 모델이나 뷰 모델에 구겨 넣기 보다는, 별도의 서비스로 분리하는 원칙이 더 중요하다 할 수 있습니다.

App = [ { M, V, VM, }, Service ]

이는 MVVM에만 적용되는 것이 아니고, 다른 패턴에서도 동일합니다.

App = [ { M, V, C, }, Service ]

이렇게 분리 해놓으면 이 서비스를 (M, V, VM 중) 누가 호출할 것인지에 대한 선택의 문제만 남습니다.

이 선택은 자유로울 수도 있고, 전체 시스템의 설계 방향 또는 성능 문제 때문에 매우 제한적일 수도 있습니다.

이점이 케바케가 되는 이유라 할 수 있습니다.

5개의 좋아요

제가 잘못 알고 있는 건가요…?
일반적으로 VM이 DependencyObject 상속 받는게 아닌가요?

2개의 좋아요

DependencyObject 클래스는 DispatcherObject 클래스를 상속받고 있고, System.Windows 네임스페이스에 속합니다.

보통은 컨트롤 구현시에 사용되는 클래스 입니다.

ViewModel은 직접 View 를 참조해서는 안됩니다.
이는 명백한 MVVM 위배에 해당되는 것 입니다.

ViewModel은 View의 순수한 View 관련 비즈니스 로직만을 정의하고 담당 해야 합니다. 때문에 ViewModel에서는 DependencyObject 를 참조할 필요가 없습니다. (MVVM 위배 입니다.)

5개의 좋아요

아… 제가 착각 했습니다.
DependencyObject를 ObservableObject 로 생각했네요 ㅎㅎ

5개의 좋아요

답변 주셔서 감사합니다.
좀 더 고민해보면서 작성해야 되겠다 싶습니다.

3개의 좋아요