티스토리 뷰

UWP & Windows App

ReactiveUI part1

kaki104 2014. 9. 29. 23:39
반응형

ReactiveUI part1

 

Reactive Extension에 대해서는 총 5개의 포스트를 통해서 많은 내용을 전달한 것 같다. 하지만, Rx만으로 앱을 개발하기에는 아직 몇가지 산이 있는데, 그런 산을 단숨에 뛰어 넘을 수 있도록 도와주는 ReactiveUI(nuget package)에 대해서 몇 번의 포스트를 통해서 이야기 하려고 한다.

 

ReactiveUI 란?

MVVM pattern과 Reactive Extension(RX)와의 콤비라고 할 수 있겠다. MVVM pattern을 이용해서 decouple한 object를 만들고 Rx를 이용해 object간 복잡한 interactions을 선언적으로 등록해서 사용함으로, 기존 event 방식 프로그램의 단점을 극복할 수 있도록 지원하는 라이브러리로, Microsoft에서 정식으로 만든 것은 아니지만, 활용할 가치가 충분한 것으로 판단된다.

 

 

0. 기본 사항

Visual Studio 2013

Reactive Extension part1~5 읽고 Rx에 대한 기본 지식 필요

MVVM 패턴에 대한 기본 지식 필요

 

ReactiveUI

Reactive Programming for WPF, Silverlight, WinRT, and Windows Phone 7

http://www.reactiveui.net/

 

상단에 DOCS (PDF) 메뉴를 클릭해서, rxuiblog.pdf 파일을 받는다.

 

reactiveui/ReactiveUI.Samples

https://github.com/reactiveui/ReactiveUI.Samples

 

오른쪽 하단에 Download ZIP 버튼을 클릭해서 소스를 다운로드 받는다.

 

ReactiveUI/Doc

https://github.com/reactiveui/ReactiveUI/tree/docs/docs

 

ReactiveUI에서 제공하는 기능들을 하나하나 살펴 보도록하고, 이후에 유니버셜앱을 만들어 보자.

 

 

1. Basics

 

Basic Property Binding

 

맨 위에 있는 것이 Binding이라, 무슨 내용인지 확인을 해봤는데, 코드로 바인딩을 지원하는 것이다. 그런데, 이 기능은 아마도, iOS나 Android를 지원하기 위한 기능인 것 같다. xaml에서닌 기본 바인딩을 사용하는 것이 좋을 것 같다.

다른 플랫폼에서 사용하기를 원하는 개발자는 참고하면 되겠다.

 

 

Dependency Resolution

 

뷰모델안에서 new 키워드로 객체를 인스턴스 시키는 경우 해당 객체가 뷰모델에 종속이 된다고 표현하며, 그 종속된 객체는 별도로 dispose를 하지 않으면, 뷰모델과 동일한 lifetime을 가지게 되거나, 혹은 뷰모델이 dispose되지 못하도록 막을 수도 있다. 특히 팝업을 출력하는 경우 그 팝업 객체를 여러번 생성을 하게 되는데, 팝업이 닫히고 dispose를 하지 않는 경우 메모리에 계속 남아있어서, memory leak이 발생한다.

 

종속성 해결은 객체와 객체사이의 연결관계를 제거하여, memory leak을 줄이는 방법을 이야기하며, 여러가지 DI(Dependency Injection) 솔루션들이 존재하는데, ReactiveUI에서는 IDependencyResolver와 IMutableDependencyResolver 두개의 인터페이스를 이용해서 이 문제를 해결한다.

 

https://github.com/reactiveui/ReactiveUI/blob/docs/docs/basics/dependency-resolution.md

 

위의 페이지를 보면 종속성 해결하는 방법이 나오는데, ReactiveUI 6.x 버전에서는 아래의 방법으로 작업해야 한다.

 

    //인터페이스

    public interface IDependencyResolver : IDisposable
    {
        object GetService(Type serviceType, string contract = null);
        IEnumerable<object> GetServices(Type serviceType, string contract = null);
    }

    public interface IMutableDependencyResolver : IDependencyResolver, IDisposable
    {
        void Register(Func<object> factory, Type serviceType, string contract = null);
        IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action<IDisposable> callback);
    }

 

//인스턴스를 Type에 등록

Locator.CurrentMutable.Register(() => new MainPageViewModel(), typeof(MainPageViewModel));

 

//Type에 연결된 인스턴스 사용

this.DataContext = Locator.CurrentMutable.GetService(typeof(MainPageViewModel));

 

인스턴스를 Type에 등록할 때 contract을 지정하게되면, Type만으로는 사용할 수 없으니, 사용시에 유의하기 바란다.

 

 

MessageBus

 

다른 MVVM pattern 프레임웩에서 많이 사용되는 message bus pattern이 포함되어 있는데, message bus pattern이란 서로 다른 뷰, 뷰모델, 프로젝트간에 특정 message를 보내고, 받는 용도로 사용되는 것을 말하며, Publish–subscribe pattern(http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)이라고도 한다.

 

message bus pattern이 Event-driven programming(http://en.wikipedia.org/wiki/Event-driven_programming)과 큰 차이점은 서로 직접적인 연결 관계가 없다는 것이다. 하지만, 언제 어디서든 원하는 메시지를 주고, 받을 수 있으며, 특히, ReactiveUI에서 구현된 MessageBus는 worker thread에서 보낸 메시지가 main thread에서 도착하기 때문에, cross-thread error를 발생시키지 않는다.

 

    //인터페이스

    public interface IMessageBus : IEnableLogger
    {
        bool IsRegistered(Type type, string contract = null);
        IObservable<T> Listen<T>(string contract = null);
        IObservable<T> ListenIncludeLatest<T>(string contract = null);
        IDisposable RegisterMessageSource<T>(IObservable<T> source, string contract = null);
        void RegisterScheduler<T>(IScheduler scheduler, string contract = null);
        void SendMessage<T>(T message, string contract = null);
    }

 

        //메시지 송신

        //IObservable sequence를 message source로 등록

        var click = Observable.FromEventPattern<RoutedEventArgs>(ClickMessageButton, "Click")
                    .Do(x => _count++)
                    .Do(x => ((Button)x.Sender).Content = "Click Message " + _count);
        ReactiveUI.MessageBus.Current.RegisterMessageSource(click);

 

        //object를 send message로 전송

        private void SendMessageButton_Click(object sender, RoutedEventArgs e)
        {
            var person = new PersonModel()
            {
                Name = "kaki104",
                Age = _count,
                Sex = _count % 2 == 0
            };
            ReactiveUI.MessageBus.Current.SendMessage(person);
        }

 

        //메시지 수신

        //IObservable EventPattern 수신

        ReactiveUI.MessageBus.Current.Listen<EventPattern<RoutedEventArgs>>()
                .Subscribe(evtPattern => {
                    Listener1.Items.Add(((Button)evtPattern.Sender).Content);
            });

 

        //object 수신

        ReactiveUI.MessageBus.Current.Listen<PersonModel>()
                .Subscribe(person => {
                    Listener2.Items.Add(person);
            });

 

 

 

 

2. End

오랫동안 테스트 및 문서를 찾으면서 포스트를 작성하다보니 내용은 얼마 없는데, 시간이 벌써 일주일 정도 소요된 것 같다. 이번에는 간단하게 여기서 마무리하고, 다음에 ReactiveCommand라는 엄청난 놈에 대해 설명하도록 하겠다.

 

다음에도 아래의 소스에서 계속 이어서 진행한다.

 

 

3. Source

ReactiveUI.Sample.zip
다운로드

 

 

"난 출현 안하는 거냐?"

 

"바쁘다"

 

"바쁜 녀석이 어제는 낮에는 잠자고, TV보고, 저녁에는 미드보고 자냐?"

 

"내일을 위한 에너지 충전이다"

 

"후후 그 충전 제대로 해주지!!!!!!!!"

 

지지지이징지잊이이징징지~~~~~~~파파파팟~~퍽퍽~~~푸더덕~

 

 

반응형

'UWP & Windows App' 카테고리의 다른 글

Nuget Package error 해결법  (0) 2014.11.18
ReactiveUI part2  (0) 2014.09.30
Reactive Extension part5  (2) 2014.09.19
Reactive Extension part4  (0) 2014.09.14
Reactive Extension part 3  (2) 2014.09.13
댓글