Dreamine.MVVM.Locators
Dreamine MVVM 프레임워크를 위한 View ↔ ViewModel 매핑 인프라입니다.
이 라이브러리는 규칙 기반 해석, 수동 등록, 역방향 View 해석, Dependency Injection 연동을 지원하는 경량 ViewModel Locator 를 제공합니다.
이 라이브러리는 플랫폼 비종속 매핑 엔진으로 설계되었습니다. 핵심 목적은 View 타입으로부터 적절한 ViewModel 타입을 찾고, ViewModel 타입으로부터 적절한 View 타입을 찾는 것입니다.
DataContext, FrameworkElement, Loaded 이벤트 연결 같은 WPF 전용 처리는 이 라이브러리의 책임이 아닙니다.
주요 기능
- 규칙 기반 View ↔ ViewModel 매핑
- 수동 ViewModel 등록
- 선택적 DI Resolver 연동
- 어셈블리 자동 스캔
- ViewModel 로부터 View 역방향 해석
- 테스트 격리 및 앱 재구성을 위한 Reset/cache clear API
- 루트 네임스페이스 탐색 지원
- 하위 폴더 및 중첩 네임스페이스 탐색 지원
- 다음과 같은 다양한 네임스페이스 구조 지원:
ViewsViewPagesWindowsDialogsGUIGUIsScreensControls
설계 목적
Dreamine.MVVM.Locators 는 WPF 전용 타입에 직접 종속되지 않도록 설계되었습니다.
이 라이브러리의 책임은 다음과 같습니다.
- View 타입으로부터 ViewModel 타입 해석
- ViewModel 타입으로부터 View 타입 해석
- 일관된 규칙 기반 매핑 엔진 제공
- 수동 매핑 및 DI 기반 생성 지원
이 라이브러리의 책임이 아닌 것은 다음과 같습니다.
DataContext설정Loaded이벤트 구독Window,Page,UserControl상속 여부 판별
이런 플랫폼 전용 동작은 별도의 WPF 전용 계층에서 처리해야 합니다.
매핑 동작 방식
Locator 는 다음 순서로 타입을 찾습니다.
View → ViewModel
- 수동 등록 맵 확인
- 규칙 기반 네임스페이스 후보 탐색
- 부모 네임스페이스 확장 탐색
- 루트 네임스페이스 탐색
- 어셈블리 전체에서 타입명 fallback 검색
예를 들어 View 이름이 MainWindow 라면 다음과 같은 후보를 순서대로 찾습니다.
MyApp.ViewModels.MainWindowViewModelMyApp.Views.Admin.MainWindow→MyApp.ViewModels.Admin.MainWindowViewModelMyApp.GUI.Login.MainWindow→MyApp.ViewModels.Login.MainWindowViewModelMyApp.MainWindowViewModel
ViewModel → View
- 규칙 기반 네임스페이스 후보 탐색
- 부모 네임스페이스 확장 탐색
- 루트 네임스페이스 탐색
- 어셈블리 전체에서 타입명 fallback 검색
지원 가능한 구조 예시
루트 네임스페이스
namespace MyApp;
public partial class MainWindow
{
}
public sealed class MainWindowViewModel
{
}
기본 Views / ViewModels 구조
namespace MyApp.Views;
public partial class MainWindow
{
}
namespace MyApp.ViewModels;
public sealed class MainWindowViewModel
{
}
하위 폴더 구조
namespace MyApp.Views.Admin;
public partial class MainWindow
{
}
namespace MyApp.ViewModels.Admin;
public sealed class MainWindowViewModel
{
}
대체 폴더명 구조
namespace MyApp.GUI.Account;
public partial class LoginDialog
{
}
namespace MyApp.ViewModels.Account;
public sealed class LoginDialogViewModel
{
}
Dependency Injection 지원
ViewModel 인스턴스 생성은 등록된 Resolver 를 통해 수행합니다.
resolver.Resolve(vmType)
ViewModel 생성에는 Activator.CreateInstance fallback 이 없습니다. Resolver 가 등록되어 있지 않거나 Resolver 가 null을 반환하면, Resolve(...)는 두 상황을 구분하는 InvalidOperationException을 발생시킵니다.
사용 예시
Resolver 등록
ViewModelLocator.RegisterResolver(new MyResolver());
Locator 상태 초기화
ViewModelLocator.Clear(); // 매핑과 lookup cache 초기화, resolver 유지
ViewModelLocator.ClearResolver(); // resolver 만 제거
ViewModelLocator.Reset(); // 매핑, lookup cache, resolver 모두 초기화
Reset()은 단위테스트 격리에 유용합니다. Clear()는 DI 전략은 유지하면서 매핑만 다시 구성해야 할 때 사용합니다.
수동 매핑 등록
ViewModelLocator.Register(typeof(MainWindow), typeof(MainWindowViewModel));
ViewModel 해석
var vm = ViewModelLocator.Resolve(typeof(MainWindow));
View 해석
var view = ViewModelLocator.ResolveView(typeof(MainWindowViewModel));
자동 등록
ViewModelLocator.RegisterAll(Assembly.GetExecutingAssembly());
권장 규약
이 Locator 는 폭넓은 매칭을 지원하지만, 권장 구조는 여전히 다음과 같습니다.
ViewsViewModels
이 규약을 유지하면 프로젝트 예측 가능성이 높아지고, 동일 타입명이 여러 개 존재할 때 모호성을 줄일 수 있습니다.
참고 사항
- 폭넓은 매칭은 유연성을 높이지만, 동일한 타입명이 여러 개 있을 경우 fallback 매칭이 모호해질 수 있습니다.
- 후보가 여러 개일 가능성이 있으면 수동 등록을 우선하는 것이 안전합니다.
- 이 라이브러리는 매핑과 생성까지를 담당하며, 플랫폼 이벤트 연결은 담당하지 않습니다.
- AppDomain 타입 스캔 결과는 캐시되며, 새 Assembly 가 로드되거나
Clear()/Reset()이 호출되면 무효화됩니다.
라이선스
MIT License
구조 다이어그램
classDiagram
class IViewModelLocator {
<<interface>>
+Locate~T~() T
+Locate(Type) object
}
class ViewModelLocator {
-IServiceProvider _provider
+Locate~T~() T
+Locate(Type) object
}
class ViewModelLocatorBase {
<<abstract>>
+Locate~T~() T
#ResolveViewModel~T~() T
}
class AutoViewModelLocator {
-Dictionary~Type,Type~ _map
+Register~TView, TViewModel~() void
+Locate(Type) object
}
IViewModelLocator <|.. ViewModelLocator
IViewModelLocator <|.. AutoViewModelLocator
ViewModelLocatorBase <|-- ViewModelLocator
ViewModelLocatorBase <|-- AutoViewModelLocatorAPI 문서
타입
\if KO View와 ViewModel 간의 타입 매핑 및 인스턴스 생성을 이름과 네임스페이스 규칙으로 지원합니다. \endif \if EN Supports convention-based type mapping and instance creation between Views and ViewModels. \endif
\if KO View 및 ViewModel 타입 이름을 확인하기 위한 공통 명명 규칙을 제공합니다. \endif \if EN Provides shared naming rules for resolving View and ViewModel type names. \endif
ViewModelLocator
\if KO 어셈블리 로드 시 타입 검색 캐시가 초기화되도록 로케이터를 구성합니다. \endif \if EN Configures the locator to clear type lookup caches when an assembly is loaded. \endif
\if KO 구성된 확인자는 유지하고 등록된 매핑과 타입 검색 캐시를 지웁니다. \endif \if EN Clears registered mappings and type lookup caches while retaining the configured resolver. \endif
\if KO 구성된 ViewModel 확인자를 제거합니다. \endif \if EN Removes the configured ViewModel resolver. \endif
\if KO View 및 ViewModel 타입 검색 캐시를 지웁니다. \endif \if EN Clears the View and ViewModel type lookup caches. \endif
\if KO 구성된 확인자를 사용해 지정한 타입의 인스턴스를 생성합니다. \endif \if EN Creates an instance of the specified type using the configured resolver. \endif
type— \if KO 생성할 타입입니다. \endif \if EN The type to create. \endif반환: \if KO 확인자가 생성한 인스턴스입니다. \endif \if EN The instance created by the resolver. \endif
\if KO 이름 규칙과 선택적 타입 목록을 사용해 View에 대응하는 ViewModel 타입을 찾습니다. \endif \if EN Finds the ViewModel type corresponding to a View using naming conventions and an optional type set. \endif
viewType— \if KO View 타입입니다. \endif \if EN The View type. \endifcachedTypes— \if KO 선택적으로 미리 확보한 검색 타입 목록입니다. \endif \if EN An optional preloaded set of types to search. \endif반환: \if KO 대응하는 ViewModel 타입이며, 찾지 못하면 입니다. \endif \if EN The matching ViewModel type, or when none is found. \endif
\if KO 이름 규칙에 따라 ViewModel 타입에 대응하는 View 타입을 찾습니다. \endif \if EN Finds the View type corresponding to a ViewModel type by naming convention. \endif
viewModelType— \if KO ViewModel 타입입니다. \endif \if EN The ViewModel type. \endif반환: \if KO 대응하는 View 타입이며, 찾지 못하면 입니다. \endif \if EN The matching View type, or when none is found. \endif
\if KO 현재 AppDomain의 모든 비동적 어셈블리에서 로드 가능한 구체 클래스 타입을 가져옵니다. \endif \if EN Gets loadable concrete class types from all non-dynamic assemblies in the current AppDomain. \endif
반환: \if KO 캐시된 로드 가능 타입 배열입니다. \endif \if EN The cached array of loadable types. \endif
\if KO 지정한 어셈블리에서 로드 가능한 타입만 가져옵니다. \endif \if EN Gets only the types that can be loaded from the specified assembly. \endif
assembly— \if KO 검색할 어셈블리입니다. \endif \if EN The assembly to inspect. \endif반환: \if KO 로드 가능한 타입 시퀀스이며, 조회 실패 시 빈 시퀀스입니다. \endif \if EN The loadable type sequence, or an empty sequence when inspection fails. \endif
\if KO View와 ViewModel 타입 매핑을 수동으로 등록합니다. \endif \if EN Manually registers a View-to-ViewModel type mapping. \endif
viewType— \if KO View 타입입니다. \endif \if EN The View type. \endifviewModelType— \if KO ViewModel 타입입니다. \endif \if EN The ViewModel type. \endif\if KO 지정된 어셈블리에서 View와 ViewModel 매핑을 자동으로 등록합니다. \endif \if EN Automatically registers View-to-ViewModel mappings from the specified assembly. \endif
assembly— \if KO 검색할 어셈블리입니다. \endif \if EN The assembly to search. \endif\if KO 외부 ViewModel 확인자를 등록합니다. \endif \if EN Registers an external ViewModel resolver. \endif
resolver— \if KO 등록할 확인자 구현입니다. \endif \if EN The resolver implementation to register. \endif\if KO 등록된 매핑, 타입 검색 캐시 및 확인자를 포함한 모든 로케이터 상태를 초기화합니다. \endif \if EN Clears all locator state, including mappings, type lookup caches, and the configured resolver. \endif
\if KO View 타입에 대응하는 ViewModel 인스턴스를 확인합니다. \endif \if EN Resolves the ViewModel instance corresponding to a View type. \endif
viewType— \if KO View 타입입니다. \endif \if EN The View type. \endif반환: \if KO 확인된 ViewModel 인스턴스이며, 타입을 찾지 못하면 입니다. \endif \if EN The resolved ViewModel instance, or when no matching type is found. \endif
\if KO ViewModel 타입에 대응하는 View 인스턴스를 생성합니다. \endif \if EN Creates the View instance corresponding to a ViewModel type. \endif
viewModelType— \if KO ViewModel 타입입니다. \endif \if EN The ViewModel type. \endif반환: \if KO 생성된 View 인스턴스이며, 타입을 찾지 못하면 입니다. \endif \if EN The created View instance, or when no matching type is found. \endif
\if KO all Loadable Types Cache 값을 보관합니다. \endif \if EN Stores the all loadable types cache value. \endif
\if KO map 값을 보관합니다. \endif \if EN Stores the map value. \endif
\if KO resolver 값을 보관합니다. \endif \if EN Stores the resolver value. \endif
\if KO sync Root 값을 보관합니다. \endif \if EN Stores the sync root value. \endif
\if KO view Model Type Cache 값을 보관합니다. \endif \if EN Stores the view model type cache value. \endif
\if KO view Type Cache 값을 보관합니다. \endif \if EN Stores the view type cache value. \endif
ViewNamingConvention
\if KO 값이 비어 있지 않을 때만 목록에 추가합니다. \endif \if EN Adds a value to the list only when it is not empty or whitespace. \endif
list— \if KO 값을 추가할 목록입니다. \endif \if EN The destination list. \endifvalue— \if KO 조건부로 추가할 값입니다. \endif \if EN The value to add conditionally. \endif\if KO 알려진 View 관련 네임스페이스 토큰을 지정한 토큰으로 바꾼 후보를 열거합니다. \endif \if EN Enumerates candidates formed by replacing known View-related namespace tokens. \endif
sourceNamespace— \if KO 원본 네임스페이스입니다. \endif \if EN The source namespace. \endifreplacement— \if KO 적용할 대체 토큰입니다. \endif \if EN The replacement token. \endif반환: \if KO 바뀐 네임스페이스 후보 시퀀스입니다. \endif \if EN A sequence of replaced namespace candidates. \endif
\if KO ViewModel 네임스페이스에서 View 검색용 네임스페이스 후보를 만듭니다. \endif \if EN Builds namespace candidates for locating a View from a ViewModel namespace. \endif
viewModelNamespace— \if KO 원본 ViewModel 네임스페이스입니다. \endif \if EN The source ViewModel namespace. \endifrootNamespace— \if KO 루트 네임스페이스입니다. \endif \if EN The root namespace. \endif반환: \if KO 중복이 제거된 네임스페이스 후보 배열입니다. \endif \if EN A distinct array of namespace candidates. \endif
\if KO View 네임스페이스에서 ViewModel 검색용 네임스페이스 후보를 만듭니다. \endif \if EN Builds namespace candidates for locating a ViewModel from a View namespace. \endif
viewNamespace— \if KO 원본 View 네임스페이스입니다. \endif \if EN The source View namespace. \endifrootNamespace— \if KO 루트 네임스페이스입니다. \endif \if EN The root namespace. \endif반환: \if KO 중복이 제거된 네임스페이스 후보 배열입니다. \endif \if EN A distinct array of namespace candidates. \endif
\if KO ViewModel 네임스페이스에서 여러 View 네임스페이스 후보를 열거합니다. \endif \if EN Enumerates multiple View namespace candidates from a ViewModel namespace. \endif
sourceNamespace— \if KO 원본 ViewModel 네임스페이스입니다. \endif \if EN The source ViewModel namespace. \endif반환: \if KO View 네임스페이스 후보 시퀀스입니다. \endif \if EN A sequence of View namespace candidates. \endif
\if KO 지정한 네임스페이스의 부모 네임스페이스를 가까운 순서대로 반환합니다. \endif \if EN Returns parent namespaces of the specified namespace from nearest to farthest. \endif
ns— \if KO 확장할 네임스페이스입니다. \endif \if EN The namespace to expand. \endif반환: \if KO 부모 네임스페이스 시퀀스입니다. \endif \if EN The parent namespace sequence. \endif
\if KO 전체 네임스페이스에서 첫 번째 루트 구간을 가져옵니다. \endif \if EN Gets the first root segment from a full namespace. \endif
ns— \if KO 전체 네임스페이스입니다. \endif \if EN The full namespace. \endif반환: \if KO 루트 구간이며 입력이 비어 있으면 빈 문자열입니다. \endif \if EN The root segment, or an empty string when the input is empty. \endif
\if KO 지정한 View 타입에 대응하는 ViewModel 전체 타입 이름 후보를 만듭니다. \endif \if EN Creates full type-name candidates for a ViewModel corresponding to the specified View type. \endif
viewType— \if KO View 타입입니다. \endif \if EN The View type. \endif반환: \if KO 구체적인 순서대로 정렬되고 중복이 제거된 ViewModel 전체 이름 후보입니다. \endif \if EN Distinct ViewModel full-name candidates ordered from most to least specific. \endif
\if KO 지정한 ViewModel 타입에 대응하는 View 전체 타입 이름 후보를 만듭니다. \endif \if EN Creates full type-name candidates for a View corresponding to the specified ViewModel type. \endif
viewModelType— \if KO ViewModel 타입입니다. \endif \if EN The ViewModel type. \endif반환: \if KO 구체적인 순서대로 정렬된 View 전체 이름 후보이며 명명 규칙이 맞지 않으면 빈 배열입니다. \endif \if EN View full-name candidates ordered from most to least specific, or an empty array when the naming rule does not match. \endif
\if KO ViewModel 전체 타입 이름에서 View 전체 타입 이름 후보를 만듭니다. \endif \if EN Creates full type-name candidates for a View from a ViewModel full type name. \endif
viewModelFullName— \if KO ViewModel의 전체 타입 이름입니다. \endif \if EN The full type name of the ViewModel. \endif반환: \if KO 중복과 원래 이름이 제거된 View 전체 이름 후보입니다. \endif \if EN View full-name candidates with duplicates and the original name removed. \endif
\if KO 지정한 타입이 알려진 View 명명 패턴에 해당하는지 판단합니다. \endif \if EN Determines whether the specified type is likely to be a View type. \endif
type— \if KO 검사할 타입입니다. \endif \if EN The type to inspect. \endif반환: \if KO 알려진 View 명명 패턴과 일치하면 입니다. \endif \if EN when the type matches a known View naming pattern. \endif
\if KO 네임스페이스의 중간 또는 마지막 토큰이 일치하면 이를 바꾼 값을 열거합니다. \endif \if EN Enumerates namespace values whose matching middle or final token has been replaced. \endif
sourceNamespace— \if KO 원본 네임스페이스입니다. \endif \if EN The source namespace. \endiffrom— \if KO 찾을 토큰입니다. \endif \if EN The token to find. \endifto— \if KO 대체 토큰입니다. \endif \if EN The replacement token. \endif반환: \if KO 토큰이 바뀐 네임스페이스 시퀀스입니다. \endif \if EN A sequence of namespaces with the token replaced. \endif
\if KO Dot View Model Token 값을 보관합니다. \endif \if EN Stores the dot view model token value. \endif
\if KO Empty Token 값을 보관합니다. \endif \if EN Stores the empty token value. \endif
\if KO Page Models Token 값을 보관합니다. \endif \if EN Stores the page models token value. \endif
\if KO Page Model Token 값을 보관합니다. \endif \if EN Stores the page model token value. \endif
\if KO Pages Token 값을 보관합니다. \endif \if EN Stores the pages token value. \endif
\if KO Page Token 값을 보관합니다. \endif \if EN Stores the page token value. \endif
\if KO View Models Token 값을 보관합니다. \endif \if EN Stores the view models token value. \endif
\if KO View Model Token 값을 보관합니다. \endif \if EN Stores the view model token value. \endif
\if KO Views Token 값을 보관합니다. \endif \if EN Stores the views token value. \endif
\if KO View Token 값을 보관합니다. \endif \if EN Stores the view token value. \endif