'Silverlight/Prism MEF Cont.'에 해당되는 글 2건

MainMenuModule의 MainMenuView.xaml 화면에 MVVM Pattern을 적용해서 사용하는 방법을 간단하게 알아 보도록 하겠다.

1. 폴더 추가
Models, ViewModels

2. Models 폴더 추가

MenuModel.cs

using System;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.ComponentModel;

namespace MainMenuModule.Model
{
    /// <summary>
    /// 메뉴 모델 익스포트
    /// </summary>
    [Export]
    public class MenuModel : IMenuModel, INotifyPropertyChanged
    {
        #region PropertyChange
        public event PropertyChangedEventHandler PropertyChanged;

        public virtual void FirePropertyChange(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
        #endregion

        ObservableCollection<string> menuCollection;
        /// <summary>
        /// 메뉴 컬렉션
        /// </summary>
        public ObservableCollection<string> MenuCollection
        {
            get { return menuCollection; }
            set
            {
                menuCollection = value;
                FirePropertyChange("MenuCollection");
            }
        }

        /// <summary>
        /// 생성자 - ImportingConstructor가 없으면 기본 생성자로 생성함
        /// </summary>
        public MenuModel()
        {
            MenuCollection = new ObservableCollection<string>();
            MenuCollection.Add("MD");
            MenuCollection.Add("SYS");
            MenuCollection.Add("SALE");
            MenuCollection.Add("WH");
        }

        #region IMenuModel Members

        /// <summary>
        /// 추가
        /// </summary>
        /// <param name="addData"></param>
        public void Adding(object addData)
        {
            if (addData != null && addData is string)
            {
                MenuCollection.Add(addData as string);
            }
        }

        /// <summary>
        /// 취소
        /// </summary>
        public void Canceling()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 조회
        /// </summary>
        /// <param name="Condition"></param>
        public void Getting(string Condition)
        {
            if (Condition.Length == 0)
            {

            }
            else
            {
            }
        }

        string messageData;
        /// <summary>
        /// 메시지
        /// </summary>
        public string MessageData
        {
            get
            {
                return messageData;
            }
            set
            {
                messageData = value;
                FirePropertyChange("MessageData");
            }
        }

        /// <summary>
        /// 삭제
        /// </summary>
        /// <param name="removeData"></param>
        public void Removing(object removeData)
        {
            if (removeData != null && removeData is string)
            {
                MenuCollection.Remove(removeData as string);
            }
        }

        /// <summary>
        /// 저장
        /// </summary>
        public void Saving()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

3. ViewModels 추가

MainMenuViewModel.cs

using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;
using MainMenuModule.Model;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;

namespace PrismMEF1.MainMenuModule.ViewModels
{
    /// <summary>
    /// 뷰 모델 익스포트
    /// </summary>
    [Export]
    public class MainMenuViewModel : NotificationObject
    {
        string messageData;
        /// <summary>
        /// 메시지 데이터
        /// </summary>
        public string MessageData
        {
            get
            {
                return messageData;
            }
            set
            {
                if (messageData != value)
                {
                    messageData = value;
                    //프리즘에서 제공하는 프로퍼티 체인지 이벤트
                    RaisePropertyChanged(() => this.MessageData);
                }
            }
        }

        ObservableCollection<string> messageCollection;
        /// <summary>
        /// 메시지 컬렉션
        /// </summary>
        public ObservableCollection<string> MessageCollection
        {
            get
            {
                return messageCollection;
            }
            set
            {
                if (messageCollection != value)
                {
                    messageCollection = value;
                    RaisePropertyChanged(() => this.MessageCollection);
                }
            }
        }

        private MenuModel mainMenu;
        /// <summary>
        /// 메뉴 모델
        /// </summary>
        public MenuModel MainMenu
        {
            get
            {
                return mainMenu;
            }
            set
            {
                mainMenu = value;
                RaisePropertyChanged(() => this.MainMenu);
            }
        }

        /// <summary>
        /// 임포트 컨트스럭처 - 익스포트/임포트시에 실행되는 생성자
        /// </summary>
        /// <param name="menuModel"></param>
        [ImportingConstructor]
        public MainMenuViewModel(MenuModel menuModel)
        {
            MessageCollection = new ObservableCollection<string>();
            //임포트 받은 메뉴 모델을 프로퍼티에 연결
            this.MainMenu = menuModel;
        }

        /// <summary>
        /// 디자인 타임 생성자
        /// </summary>
        public MainMenuViewModel()
        {
            this.MainMenu = new MenuModel();
        }

        DelegateCommand<object> menuSelect;
        /// <summary>
        /// 메뉴 선택 커맨드
        /// </summary>
        public DelegateCommand<object> MenuSelect
        {
            get
            {
                if (menuSelect == null)
                {
                    menuSelect = new DelegateCommand<object>(obj =>
                    {
                        ListBox lb = obj as ListBox;
                        if (lb != null && lb.SelectedItem != null)
                        {
                            var item = lb.SelectedItem as string;
                            MessageBox.Show(item);
                        }
                    }
                    );
                }

                return menuSelect;
            }
        }

        DelegateCommand<object> menuAdd;
        /// <summary>
        /// 메뉴 추가 커맨드
        /// </summary>
        public DelegateCommand<object> MenuAdd
        {
            get
            {
                if (menuAdd == null)
                {
                    menuAdd = new DelegateCommand<object>(obj =>
                    {
                        var cnt = MainMenu.MenuCollection.Count;
                        var menu = "NewMenu" + cnt.ToString();
                        MainMenu.Adding(menu);
                    }
                    );
                }

                return menuAdd;
            }
        }

        DelegateCommand<object> menuRemove;
        /// <summary>
        /// 메뉴 삭제 커맨드
        /// </summary>
        public DelegateCommand<object> MenuRemove
        {
            get
            {
                if (menuRemove == null)
                {
                    menuRemove = new DelegateCommand<object>(obj =>
                    {
                        ListBox lb = obj as ListBox;
                        if (lb != null && lb.SelectedItem != null)
                        {
                            var menu = lb.SelectedItem as string;
                            MainMenu.Removing(menu);
                        }
                    }
                    );
                }

                return menuRemove;
            }
        }
    }
}

4. MainMenuView.xaml.cs

using System.ComponentModel.Composition;
using System.Windows.Controls;
using PrismMEF1.MainMenuModule.ViewModels;

namespace PrismMEF1.MainMenuModule.Views
{
    [Export(typeof(MainMenuView))]
    public partial class MainMenuView : UserControl
    {
        /// <summary>
        /// 뷰 모델 임포트 - 비동기 동작
        /// </summary>
        [Import]
        public MainMenuViewModel ViewModel
        {
            get { return this.DataContext as MainMenuViewModel; }
            set
            {
                this.DataContext = value;
            }
        }

        /// <summary>
        /// 생성자
        /// </summary>
        public MainMenuView()
        {
            InitializeComponent();
        }
    }
}

5. MainMenuView.xaml

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:PrismMEF1_MainMenuModule_ViewModels="clr-namespace:PrismMEF1.MainMenuModule.ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    x:Class="PrismMEF1.MainMenuModule.Views.MainMenuView"
    FontSize="18"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
   
    <!--디자인 타임에 뷰 모델을 사용하기 위해서 입력-->
 <d:DataContext>
  <PrismMEF1_MainMenuModule_ViewModels:MainMenuViewModel/>
 </d:DataContext>

   
    <StackPanel x:Name="LayoutRoot" Background="Blue">
     <Button Content="Main Menu Add" Foreground="#FF1F257E" >
      <i:Interaction.Triggers>
       <i:EventTrigger EventName="Click">
        <i:InvokeCommandAction Command="{Binding MenuAdd, Mode=OneWay}"/>
       </i:EventTrigger>
      </i:Interaction.Triggers>
     </Button>
     <Button Content="Main Menu Remove" Foreground="#FF1F257E">
      <i:Interaction.Triggers>
       <i:EventTrigger EventName="Click">
        <i:InvokeCommandAction Command="{Binding MenuRemove, Mode=OneWay}" CommandParameter="{Binding ElementName=listBox}"/>
       </i:EventTrigger>
      </i:Interaction.Triggers>
     </Button>
        <ListBox x:Name="listBox" ItemsSource="{Binding MainMenu.MenuCollection}">
         <i:Interaction.Triggers>
          <i:EventTrigger EventName="SelectionChanged">
           <i:InvokeCommandAction Command="{Binding MenuSelect, Mode=OneWay}" CommandParameter="{Binding ElementName=listBox}"/>
          </i:EventTrigger>
         </i:Interaction.Triggers>
        </ListBox>
    </StackPanel>
</UserControl>

6. 실행

1) 시작

2) Main Menu Add 버튼 클릭으로 메뉴 추가


3) Main Menu Remove 버튼 클릭으로 메뉴 삭제

7. 자세한 사항은 소스를 참고 하기 바란다.


 

'Silverlight > Prism MEF Cont.' 카테고리의 다른 글

Prism 4.0 MEF Container 2 - MVVM Pattern apply  (2) 2012.02.29
Prism 4.0 MEF Container 1  (2) 2012.02.13
블로그 이미지

kaki104

/// Microsoft MVP - Windows Development 2014 ~ 2019 5ring /// twitter : @kaki104, facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

Silverlight, WPF 프로젝트를 개발 할 때 Prism을 사용해서 개발하게 된다. 그런데, 대부분은 Unity Container만 사용하고 MEF Container를 사용하는 프로젝트는 잘 없는 것 같다. 간단하게 MEF Container를 이용하는 방법을 적어 보고자 한다. (Windows Phone 7도 Prism을 이용 할 수 있는데 Unity Container만을 지원한다.)

참고 포스트
Prism for Silverlight/MEF in Easy Samples. Part 1 - Prism Modules
http://www.codeproject.com/Articles/155835/Prism-for-Silverlight-MEF-in-Easy-Samples-Part-1-P

1. Prism 4.0

Developer's Guide to Microsoft Prism
http://msdn.microsoft.com/en-us/library/gg406140.aspx

프리즘은 WPF, Silverlight 등의 프로그램 개발 할 때 쉽게 설계하고, 개발하고, 유연성을 가지도록 개발을 하는 패턴을 제공해주는 툴이라고 생각하면 되겠다. Enterprise Library가 프리즘을 기반으로 만들어진 것 중 하나이다.

2. MEF Container

MEF(Managed Extensibility Framework)는 대규모 어플리케이션의 유연성, 유지보수 및 테스트를 하기 쉽게하는 기능을 제공하는 것으로, Prism에 포함되어 Unity Container와 함께 하나의 큰 축을 이루고 있다.

3. MEF Container를 구성하는데 제일 중요한 사항

Shell.xaml이 있는 메인 프로젝트에는 References에 Prism관련 DLL들이 Copy Local : True  되어 있어야 하고, 그 외의 다른 프로젝트에서는 모두 Copy Local : False가 되어 있어야 한다. 이 부분만 확실하게 해주면 프로젝트를 구성하는데 어려움이 없을 것이다.

4. 메인 모듈(PrismMEF1)
찾아서 보아야 하는 부분을 순서대로 보도록 하겠다.

App.xaml.cs

  private void Application_Startup(object sender, StartupEventArgs e)
  {
      //부트 스트리퍼로 시작
      (new Bootstrapper()).Run();
  }


Bootstrapper.cs

using System.Windows;
using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Modularity;
using System.ComponentModel.Composition.Hosting;
using PrismMEF1.Infrastructure;

namespace PrismMEF1
{
    /// <summary>
    /// 부트스트리퍼
    /// </summary>
    public class Bootstrapper : MefBootstrapper
    {
        /// <summary>
        /// 쉘 초기화
        /// </summary>
        protected override void InitializeShell()
        {
            base.InitializeShell();
            Application.Current.RootVisual = (UIElement)Shell;
        }


        protected override DependencyObject CreateShell()
        {
            //익스포트된 Shell.xaml를 임포트 시켜서 리턴
            return Container.GetExportedValue<Shell>();
        }

        /// <summary>
        /// 모든 MEF 콤포저블 카탈로그들이 들어가 있는 넘
        /// </summary>
        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();

            //거기다가 이 프로젝트까지 카탈로그에 넣는데...왜 넣는걸까?
            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly));
        }

        /// <summary>
        /// 모듈카탈로그를 만드는데 사용
        /// </summary>
        /// <returns></returns>
        protected override IModuleCatalog CreateModuleCatalog()
        {
            //모듈카탈로그 생성
            ModuleCatalog moduleCatalog = new ModuleCatalog();

            //ModuleName, Moduletype은 클래스 이름
            //즉시 다운로드
            moduleCatalog.AddModule
            (
                new ModuleInfo
                {
                    InitializationMode = InitializationMode.WhenAvailable,
                    Ref = "PrismMEF1.MainMenuModule.xap",
                    ModuleName = ModuleNames.MainMenuModuleImp,
                    ModuleType = "PrismMEF1.MainMenuModule.MainMenuModuleImp, PrismMEF1.MainMenuModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                }
            );
            //다중에 다운로드
            moduleCatalog.AddModule
            (
                new ModuleInfo
                {
                    InitializationMode = InitializationMode.OnDemand,
                    Ref = "PrismMEF1.MDModule.xap",
                    ModuleName = ModuleNames.MDModuleImp,
                    ModuleType = "PrismMEF1.MDModule.MDModuleImp, PrismMEF1.MDModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                }
            );

            //추가한 모듈카탈로그를 반환해야징;;
            return moduleCatalog;
        }
    }
}

Shell.xaml
<!--쉘에서 레전을 지정-->
    <ContentControl Grid.Row="1" Grid.Column="0"
                        prism:RegionManager.RegionName="mainMenuRegion" Grid.RowSpan="2" Margin="10,10,0,0"/>
    <ContentControl Grid.Row="1" Grid.Column="1"
                      prism:RegionManager.RegionName="subMenuRegion" Margin="10,10,10,0"/>
    <ContentControl Grid.Row="2" Grid.Column="1"
          prism:RegionManager.RegionName="contentRegion" Margin="10,10,10,0"/>


5. 메뉴 모듈(PrismMEF1.MainMenuModule)

MainMenuModuleImp.cs

using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using PrismMEF1.Infrastructure;
using PrismMEF1.MainMenuModule.Views;

namespace PrismMEF1.MainMenuModule
{
    [ModuleExport(typeof(MainMenuModuleImp))]
    public class MainMenuModuleImp : IModule
    {
        /// <summary>
        /// 레전 메니저 임포트
        /// </summary>
        [Import]
        public IRegionManager regionManager { private get; set; }

        /// <summary>
        /// 모듈이 로딩이 되자마자 지정된 레전에 들어간다.
        /// </summary>
        public void Initialize()
        {
            regionManager.RegisterViewWithRegion(RegionNames.MainMenuRegion, typeof(MainMenuView));
            regionManager.RegisterViewWithRegion(RegionNames.SubMenuRegion, typeof(SubMenuView));
        }
    }
}

6. 컨텐츠 모듈(PrismMEF1.MDModule)

using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using PrismMEF1.Infrastructure;
using PrismMEF1.MDModule.Views;

namespace PrismMEF1.MDModule
{
    [ModuleExport(typeof(MDModuleImp))]
    public class MDModuleImp : IModule
    {
        /// <summary>
        /// 레전 매니저 임포트
        /// </summary>
        [Import]
        public IRegionManager regionManager { private get; set; }

        public void Initialize()
        {
            //리전메니저를 임포트해서 불러들인 후에 리전중에 컨텐츠리진에 MDMainView를 붙인다.
            regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(MDMainView));
        }

    }
}

7. 화면

접속 가능 주소 : http://kaki105.cafe24.com/PrismMef1/

1) 시작하면 메인메뉴모듈을 로딩해서 바로 표시

2) 컨텐츠모듈 다운로드 버튼을 누르면 컨텐츠 모듈을 다운로드 해서 표시해준다.

8. 이 포스트는 예전에 만들어 놓은 셈플 프로젝트를 빠르게 정리하기 위한 것이다.

'Silverlight > Prism MEF Cont.' 카테고리의 다른 글

Prism 4.0 MEF Container 2 - MVVM Pattern apply  (2) 2012.02.29
Prism 4.0 MEF Container 1  (2) 2012.02.13
블로그 이미지

kaki104

/// Microsoft MVP - Windows Development 2014 ~ 2019 5ring /// twitter : @kaki104, facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

티스토리 툴바