2009-03-24 4 views
1

WPF의 MVVM 패턴의 ViewModel 부분을 WPF 어셈블리를 참조하지 않고 구현하고 싶습니다. 문제가되는 부분은 명령 라우팅입니다.이 경우 ViewModel은 명령 바인딩이 작동 할 수 있도록 ICommand 유형의 속성을 구현해야합니다..NET 클래스에 속성을 주입 후 컴파일

이제 ICommand을 피하고 단순히 object으로 속성을 선언 할 수 있습니다. 모든 것이 여전히 효과가 있습니다. 그러나 나를 귀찮게하는 것은 입니다. 그들은을 선언해야합니다. 그들은 보일러 플레이트 코드처럼 느껴지기를 바랍니다.

내 ViewModels는 현재 다음과 같이 :

public class HelloWorldViewModel : ViewModel 
{ 
    [BoundProperty] 
    public string Name { get; set; } 

    [CommandHandler("SayHello")] 
    public bool CanSayHello() 
    { 
     return Name != "" && Name != null; 
    } 

    [CommandHandler("SayHello")] 
    public void SayHello() 
    { 
     View.ShowMessage("Hello, {0}!", Name); 
    } 

    public object SayHello { get; private set; } 
} 

CommandHandlerAttribute 명령 핸들러의 런타임 발견 (AN Action 및 선택적 Func<bool>를) 할 수는 BoundPropertyAttribute 정말 재산에 자신을 주입하는 측면동안 세터와 전화 INotifyPropertyChanged. 나는 컴파일러 일리 weaver을 사용하여 이것을 수행한다.

이상적으로, 나는 마지막 줄 (SayHello 속성)도 암시 적으로 만들고 싶습니다. 그것이 WPF의 요구 사항이 아니라면 소스에 포함시킬 필요가 없습니다.

그래서, 당연히, 나는 수업에 필요한 IL을 주입하는 CommandHandlerAttribute 측면을 사용하여 생각하고 본질적으로 속성이을 후 컴파일 생성. 좋은 IL 작성자 (예 : PostSharp)가 더 쉽게 만들 수는 있지만 매우 어렵습니다.

나는이 여행을 시작하기 전에 모든 접근 방식에 대해 어떻게 생각하는지 듣고 싶습니다. 그것은 소리가 나는가? 더 좋은 방법이 있습니까? 어떻게/당신이 그것을합니까?

답변

3

나에게 이것은 너무 영리하게 들린다. 너무 많은 '마술'이 일어나고 있습니다. 특히, 나는 CommandHandlerAttribute의 마술 문자열과 다른 측면을 싫어한다. 즉, 내가이 길로 내려 가려면 EventAggregator와 비슷한 것을 사용하지만 명령은 사용하겠다고했다. IOW, SayHello는 ViewModel에 전혀 존재하지 않습니다. 이제까지 매직이 SayHell()과 CanSayHello()에 대한 명령 바인딩을 생성하는 대신 글로벌 CommandAggregator에서 명령을 찾습니다. Magic String을 사용하는 한, CommandAggregator의 명령은 느리게 생성 될 수 있으므로 사용자가 "보일러 판"을 코딩 할 필요가 없습니다. 남아있는 모든 것은 ICommandSource에 명령을 지정하기위한 XAML 마법 (마크 업 확장)을 만드는 것입니다.

<Button Command="{my:AggregateCommand SayHello}"/> 
0

개인적인 견해로는 이것이 흥미 롭다. 그러나 나는 그것을 일반적으로 피할 것이다.

보일러 플레이트 코드 (또는 보일러 플레이트 코드와 같은 코드)를 피하면 결과가 달라집니다. 당신이 끊임없이 물건을 다시 타이핑하지 않기 때문에 좋은 생각처럼 보일지도 모르지만 장기적으로 볼 때 이해하기 쉽지 않습니다.

개인적으로 나는 보일러 플레이트 코드를 삽입하기 위해 좋은 코드 템플릿을 설치하려고 시도하고 소스 코드에서이를 숨길 수 있도록 영역을 포장합니다. 보일러 플레이트가있는 파일을 채우는 데 30 초가 걸리는데,이 경우 코드를 이해하려고 할 때 2 년 후, 또는 2 주 후 누군가보다 고통 스럽습니다 (나를 위해). 다른 사람이 내 코드를 이해하려고 할 때 2 년 후 ...

1

프리즘을 사용한 후에 어느 정도 시간이 걸렸지 만 MVVM과 비슷한 것으로 보이기 전에는 여전히 생각하고있는 전략을 생각해 냈습니다. 몇 가지 유효성 :

리플렉션을 기반으로 ICommand 인터페이스의 구현을 만들었습니다. 생성자가 대상 객체와 작업 이름을 허용했습니다. 리플렉션을 사용하여 코드는 이름 "Can [operation]"또는 "[Operation] Enabled"로 이름이 "Can [operation] Changed"또는 "[Operation] 조작] 사용 가능 변경됨 ". 첫 번째 메소드 만 필요했지만 반영된 메소드/속성/이벤트는 ICommand 인터페이스의 기본적인 구현으로 연결되었습니다.

그런 다음 IValueConverter의 구현을 만들어 이전 클래스의 인스턴스를 만들고 대상 객체로 변환 할 값을 전달하고 변환기의 매개 변수를 작업 이름으로 전달했습니다.

위의 구성 요소를 사용하면 예를 들어 버튼의 Command 속성을 (변환기 지정과 함께) 작업 소스에 직접 바인딩하고 Button의 CommandParameter 속성을 작업 이름으로 설정할 수있었습니다 . 이 방법으로, 나는 WPF에 대한 육체적 지식을 가진 명령 소스없이 선언적 명령 바인딩을 얻었다.

+0

나는 "마법"메서드 및 속성 이름을 가진 반사를 사용하여 좋아하지 않는다. 나는 과거에 종종 발견했다. 나는 메소드의 이름을 바꾼다. 예기치 않은 UI UI가 컴파일러없이 오류를 일으키지 않고 멈췄다. 그러나 당신의 기본 디자인이 마음에 드는데, 람다 식으로 와이어 업을하는 것은 어떨까요? –

+0

나는 람다에 대한 아이디어를 많이 좋아한다. 인터페이스를 단순화하기 때문에 리플렉션 (적어도 기본적으로)을 통해 "enabled"속성/이벤트를 찾는 것을 선호 할 수 있습니다. –

0

가장 좋은 방법은 프록시 또는 데코레이터 패턴입니다. 런타임 중에 UI/WPF stuff 멤버로 래핑되거나 꾸며진 로우 레벨 엔티티를 사용할 수 있습니다. 이 방법은 시간을 절약하고 프레임 워크, 인젝션 등을 신경 쓰지 않고도 간단하면서도 효율적인 방법입니다.

유일한 방법은 엔티티를 적절한 데코레이터로 포장하도록 설계해야한다는 것입니다.

이를 구현하는 방법을 볼 수 있습니다, 그것은 도움이 될 것입니다
2

내가 조언 :

"종류 매직의" 어려움에서 INotifyPropertyChanged를

[http://visualstudiogallery.msdn.microsoft.com/ d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a 하나 개의 속성에 추가 예로서, [1]

:

[Magic] 
public string Name { get { return _name; } set { _name = value; } } 
string _name; 

모든 클래스 속성에 추가하는 또 다른 예 :

[Magic] 
public class MyViewModel: INotifyPropertyChanged 
{ 
    public string Name { get; set; } 
    public string LastName { get; set; } 
    ..... 
}