Siverlight에 있는 InvokeCommandAction은 이벤트의 파라메터를 CommandParameter로 전달해 주지 않는다.
어제 찾아보다가 발견한 것으로 이런 문제를 깔끔하게 해결해주는 포스트이다.

InvokeDelegateCommandAction이란 Behavior는 EventArgs를 CommandParameter로 전달해주는 매우 유용한 Behavior이다.

Silverlight Commands Hacks: Passing EventArgs as CommandParameter to DelegateCommand triggered by EventTrigger

http://weblogs.asp.net/alexeyzakharov/silverlight-commands-hacks-passing-eventargs-as-commandparameter-to-delegatecommand-triggered-by-eventtrigger

'Silverlight > ETC' 카테고리의 다른 글

Passing EventArgs as CommandParameter to DelegateCommand triggered by EventTrigger  (0) 2014.10.24
Rx Links & Querys  (0) 2012.06.26
Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
블로그 이미지

kaki104

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

Reactive Extensions for .NET (Rx) - Forums
http://social.msdn.microsoft.com/Forums/pl-pl/rx/threads

 

Introducing Pushqa-Queryable Push Messages over OData
http://blog.petegoo.com/index.php/tag/signalr/

 

Home > C#, Programming, Rx, WPF > Building an Auto Complete control with Reactive Extensions (Rx)
http://blog.petegoo.com/index.php/2011/11/22/building-an-auto-complete-control-with-reactive-extensions-rx/

Rx: Curing Your Asynchronous Programming Blues
http://www.slideshare.net/jibyjohnc/rx-curing-your-asynchronous-programming-blues-qcon-london

 

Rx Workshop

http://www.slideshare.net/panesofglass/rx-workshop

 

Reactive Extensions v2.0 Release Candidate available now!

http://blogs.msdn.com/b/rxteam/archive/2012/06/20/reactive-extensions-v2-0-release-candidate-available-now.aspx

 

관찰자 디자인 패턴(Observer Design Pattern)

http://msdn.microsoft.com/ko-kr/library/ee850490.aspx

 

1) windows  Form    Rx mouse event operation.....

var up = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseUp")
         select evt.EventArgs.Location;

var move = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
         select evt.EventArgs.Location;


var down = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseDown")
       select evt.EventArgs.Location;

up.Subscribe(x => heleleText.Text=x.X.ToString());
down.Subscribe(x => heveleText.Text = x.Y.ToString());
move.Subscribe(x => hevoleText.Text = x.Y.ToString()+":"+x.Y.ToString());

2) WPF(XAML) mouse event operation..........

  [XAML]
  <Grid>
        <StackPanel>
            <TextBlock x:Name="heleleText" Text="helele and hevele"/>
            <TextBox x:Name="heveleText"/>

            <StackPanel Orientation="Horizontal">
                <ListBox x:Name="heleleList"/>
                <ListBox x:Name="heveleList"/>
            </StackPanel>

        </StackPanel>
    </Grid>

   [CS]
    var move = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
               select evt.EventArgs.GetPosition(this);
   
    var up = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseUp")
             select evt.EventArgs.GetPosition(this);
   
    var down = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseDown")
               select evt.EventArgs.GetPosition(this);
   
    var q = from start in down
            from pos in move.StartWith(start).TakeUntil(up)
            select pos;

    // q.ObserveOnDispatcher().Subscribe(s => this.Title = s.ToString());
   
    q.Subscribe(s => this.Title = s.ToString());
   
    var helele = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(-1);
   
    helele.ObserveOnDispatcher()
               .Subscribe(s => this.Title = s.ToString());
    // helele.Subscribe(s => this.Title = s.ToString());

    var changed = Observable.FromEventPattern<TextChangedEventArgs>(heveleText, "TextChanged");
   
    var input = (from e2 in changed
                 let text = ((TextBox)e2.Sender).Text
                 where text.Length >= 3
                 select text)
                .DistinctUntilChanged()
                .Throttle(TimeSpan.FromSeconds(1));
   
    input.ObserveOnDispatcher().Subscribe(
      x =>
      {
          heleleList.Items.Add(x);
      }
    );

    var input2 = Observable.FromEventPattern(heveleText, "TextChanged")
                          .Select(evt => ((TextBox)evt.Sender).Text)
                          .Timestamp()
                          .Do((Timestamped<string> evt) => heveleList.Items.Add(evt))
                          .Select(evt => evt.Value)
                          .Where(evt => evt.Length > 4)
                          .Do(evt => heveleList.Items.Add( evt) );
   
    input2.ObserveOnDispatcher().Subscribe(_ => { });


3) App(WinRT)  mouse event operation..........<PointerEventArgs>(this, "PointerMoved")

    <Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
        <StackPanel>
            <TextBlock x:Name="heleleText" Text="helele and hevele"/>
            <TextBox x:Name="heveleText"/>
            <TextBox x:Name="hevoleText"/>
            <StackPanel Orientation="Horizontal">
                <ListBox x:Name="heleleList"/>
                <ListBox x:Name="heveleList"/>
            </StackPanel>
        </StackPanel>
    </Grid>


  protected override void OnNavigatedTo(NavigationEventArgs e)
        {
                   
            var move = from evt in Observable.FromEventPattern<PointerEventArgs>(this, "PointerMoved")
                       select evt.EventArgs.GetCurrentPoint(this);

            var up = from evt in Observable.FromEventPattern<PointerEventArgs>(this, "PointerReleased")
                     select evt.EventArgs.GetCurrentPoint(this);

            var down = from evt in Observable.FromEventPattern<PointerEventArgs>(this, "PointerPressed")
                       select evt.EventArgs.GetCurrentPoint(this);

            var q = from start in down
                    from pos in move.StartWith(start).TakeUntil(up)
                    select pos;

            q.Subscribe(s => heleleText.Text = s.Position.ToString()); //위와 동일, 잘됨

            var helele = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(-1);

            helele.ObserveOnDispatcher()
                       .Subscribe(s => heveleText.Text = s.ToString());
            //helele.Subscribe(s => heveleText.Text = s.ToString()); //Thread Error

            var changed = Observable.FromEventPattern<TextChangedEventArgs>(hevoleText, "TextChanged");

            var input = (from e2 in changed
                         let text = ((TextBox)e2.Sender).Text
                         where text.Length >= 3
                         select text)
                                .DistinctUntilChanged()
                                .Throttle(TimeSpan.FromSeconds(1));

            input.ObserveOnDispatcher().Subscribe(x =>
            {
                heleleList.Items.Add(x);
            }
            );

            var input2 = Observable.FromEventPattern(hevoleText, "TextChanged")
                                  .Select(evt => ((TextBox)evt.Sender).Text)
                                  .Timestamp()
                                  .Do((Timestamped<string> evt) => heveleList.Items.Add(evt))
                                  .Select(evt => evt.Value)
                                  .Where(evt => evt.Length > 4)
                                  .Do(evt => heveleList.Items.Add(evt));

            input2.ObserveOnDispatcher().Subscribe(_ => { });
        }

 

 

'Silverlight > ETC' 카테고리의 다른 글

Passing EventArgs as CommandParameter to DelegateCommand triggered by EventTrigger  (0) 2014.10.24
Rx Links & Querys  (0) 2012.06.26
Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
블로그 이미지

kaki104

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

Prism 4.0 Tips

Silverlight/ETC 2012.06.13 16:33

01. MVVM에서 DelegateCommand를 사용한 버튼의 사용가능 상태를 그리드뷰에 아이템 선택이 될때마다 확인하기

 

View

 

<Grid>
 <Grid.RowDefinitions>
  <RowDefinition Height="0.145*"/>
  <RowDefinition Height="0.855*"/>
 </Grid.RowDefinitions>


 <!--버튼들-->
 <StackPanel Orientation="Horizontal" Margin="0" HorizontalAlignment="Right" d:LayoutOverrides="HorizontalAlignment">
        <telerik:RadButton Content="취소" Command="{Binding CancelCommand}" Margin="5,0,0,0"/>
        <telerik:RadButton Content="삭제" Command="{Binding DeleteCommand}" Margin="5,0,0,0" />
        <telerik:RadButton Content="복구" Command="{Binding RecoverCommand}" Margin="5,0,0,0" />
 </StackPanel>
 
 <!--그리드뷰-->
 <telerik:RadGridView x:Name="rgvTask"
  AutoGenerateColumns="False"  RowIndicatorVisibility="Collapsed" ShowGroupPanel="False"
  ItemsSource="{Binding Tasks}"  IsReadOnly="True" Grid.Row="1" SelectionMode="Multiple" >
  <i:Interaction.Triggers>
   <i:EventTrigger EventName="SelectionChanged">
    <i:InvokeCommandAction Command="{Binding SelectionChangedTaskCommand}" CommandParameter="{Binding SelectedItems, ElementName=rgvTask}"/>
   </i:EventTrigger>
  </i:Interaction.Triggers>

  <telerik:RadGridView.Columns>
     <telerik:GridViewSelectColumn />
   <telerik:GridViewDataColumn Header="행번호" DataMemberBinding="{Binding No}" />
   <telerik:GridViewDataColumn Header="생성일시" DataMemberBinding="{Binding CreatedOn}" />
   <telerik:GridViewDataColumn Header="종료일시" DataMemberBinding="{Binding EndedTime}" />
   <telerik:GridViewDataColumn Header="설명" DataMemberBinding="{Binding Description}" />
  </telerik:RadGridView.Columns>
 </telerik:RadGridView>
</Grid>


ViewModel

 

//Prism MEF Container 프로젝트
//RaisePropertyChanged는 프리즘에서 제공

private ICommand cancelCommand;
/// <summary>
/// 취소 커맨드
/// </summary>
public ICommand CancelCommand
{
    get
    {
        if (cancelCommand == null)
        {
            cancelCommand = new DelegateCommand(
                () =>
                {
                  //취소 작업
                },
                () => HasSelectedTask);
        }
        return cancelCommand;
    }
}

private ICommand deleteCommand;
/// <summary>
/// 삭제 커맨드
/// </summary>
public ICommand DeleteCommand
{
    get
    {
        if (deleteCommand == null)
        {
            deleteCommand = new DelegateCommand(
                () =>
                {
                  //삭제작업
                },
                () => HasSelectedTask);
        }
        return deleteCommand;
    }
}

private ICommand recoverCommand;
/// <summary>
/// 복구 커맨드
/// </summary>
public ICommand RecoverCommand
{
    get
    {
        if (recoverCommand == null)
        {
            recoverCommand = new DelegateCommand(() => {//복구작업}, () => this.HasSelectedTask);
        }
        return recoverCommand;
    }
}

/// <summary>
/// 선택된 작업존재 여부를 확인 Linq 사용
/// </summary>
public bool HasSelectedTask
{
    get
    {
        var result = this.SelectedTasks.Any();
        return result;
    }
}

private ObservableCollection<Comm.Task> _tasks = new ObservableCollection<Comm.Task>();
/// <summary>
/// 작업 목록
/// </summary>
public ObservableCollection<Comm.Task> Tasks
{
    get { return _tasks; }
    set
    {
        _tasks = value;
        RaisePropertyChanged(() => this.Tasks);
    }
}

private ObservableCollection<Comm.Task> selectedTasks = new ObservableCollection<Comm.Task>();
/// <summary>
/// 선택된 작업들
/// </summary>
public ObservableCollection<Comm.Task> SelectedTasks
{
    get { return selectedTasks; }
    set
    {
        selectedTasks = value;
        RaisePropertyChanged(() => this.SelectedTasks);
    }
}

private ICommand selectionChangedTaskCommand;
/// <summary>
/// 선택 변경 커맨드
/// </summary>
public ICommand SelectionChangedTaskCommand
{
    get
    {
        if (selectionChangedTaskCommand == null)
        {
            selectionChangedTaskCommand = new DelegateCommand<object>(
                obj =>
                {
                    var items = obj as ObservableCollection<object>;
                    if(items == null)
                    {
                        items = new ObservableCollection<object>();
                    }
                    SelectedTasks = new ObservableCollection<Comm.Task>(items.Cast<Comm.Task>());
                    //커맨드의 상태변경 -> 버튼 활성화/비활성화
                    CancelCommand.RaiseCanExecuteChanged();
                    DeleteCommand.RaiseCanExecuteChanged();
                    RecoverCommand.RaiseCanExecuteChanged();
                });
        }
        return selectionChangedTaskCommand;
    }
}

'Silverlight > ETC' 카테고리의 다른 글

Passing EventArgs as CommandParameter to DelegateCommand triggered by EventTrigger  (0) 2014.10.24
Rx Links & Querys  (0) 2012.06.26
Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
블로그 이미지

kaki104

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

1. 프린트 출력시 한글이 깨지는 현상

pdf파일로 변경하여 출력을 할 때 한글이 깨지는 현상은 font관련 문제로 맑은 고딕(Malgun Gothic)을 이용해서 디자인 작업을 해서 출력하면 한글이 깨지지 않음

 

'Silverlight > ETC' 카테고리의 다른 글

Rx Links & Querys  (0) 2012.06.26
Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
Twitter Client Lecture(강좌 목록) by Silverlight 5  (0) 2012.01.05
블로그 이미지

kaki104

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

1. EntityQuery를 이용해서 클라이언트에서 조건을 추가해서 조회하기


//Server side

[Query]
public IQueryable<VisitReservation> GetVisitReservations(int siteid)
{
        var results = from kkk in this.ObjectContext.VisitReservations
                                    .Include("Visitors")

                                    .Include("Visitors.Cards")
                                    .Include("VisitorUsers")
                                    .Include("VisitorPermissions")
                      where kkk.SiteId == siteid
                      orderby kkk.ReservedOn
                      select kkk;

 

        return results;
}

 

//Client side

using System.ServiceModel.DomainServices.Client;

 

DateTime start = new DateTime(this.StartDate.Year, this.StartDate.Month, this.StartDate.Day, 0, 0, 0);
DateTime end = new DateTime(this.EndDate.Year, this.EndDate.Month, this.EndDate.Day, 23, 59, 59);

var query = from kkk in DomainContext.GetVisitReservationsQuery(this.SiteId)
            where kkk.ReservedOn >= start 
                && kkk.ReservedOn <= end
                && (kkk.UserId == User.Id || kkk.ApproverId == User.Id)
            select kkk;

 

this.DomainContext.Load(query, LoadBehavior.RefreshCurrent,
    lo =>
    {
        if (lo.HasError == true)
        {
            lo.MarkErrorAsHandled();
            MessageBox.Show(string.Format(StringTable.FailedToLoadData, lo.Error.Message));
            return;
        }

        this.VisitReservations = new ObservableCollection<VisitReservation>(lo.Entities);
        this.SearchResult = string.Format("[{0} {1}]", StringTable.SearchResults, this.VisitReservations.Count);
    }, null);

 

 

블로그 이미지

kaki104

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

Rx, Linq Tips

Silverlight/ETC 2012.05.04 15:00

Rx 사용한 소스 정리 중 사용한 버전은 Rx SDK 1.1.11011

 

//기본 Linq 쿼리

var cards = from kkk in op.Entities
            where kkk.Cards != null && kkk.Cards.Any() == true
            let c = kkk.Cards
            from jjj in c
            select new UserCard(this.CommonDomainContext, kkk, jjj);

var cards2 = from kkk in op.Entities
             where kkk.Cards == null || kkk.Cards.Any() == false
             select new UserCard(this.CommonDomainContext, kkk, null);

var tcards = cards.Concat(cards2).OrderBy(p => p.User.Name);

 

//옵저버블로 만들고, 스레드 풀을 사용하고, 디스패처쓰고, 서브스크레블

tcards.ToObservable()
    .ObserveOn(Scheduler.ThreadPool)
    .ObserveOnDispatcher()
    .SubscribeOnDispatcher()
    .Subscribe(
    p =>
    {

        //next
        this.UserCards.Add(p);
    },
    c =>
    {

        //complete
    });

//레이지로 만들어서 사용해 보기도 했는데..원하는 방향이 아니였음

Lazy<ObservableCollection<UserCard>> lu = new Lazy<ObservableCollection<UserCard>>(
    () =>
    {
        ObservableCollection<UserCard> collection = new ObservableCollection<UserCard>(tcards);
        return collection;
    });

this.AllUserCards = lu.Value;

//스케줄러만 사용해서 스레드풀로 처리를 해볼려고 했는데..실행은 가능하나, 원하는 결론이 아님

Scheduler
    .Schedule(Scheduler.ThreadPool,
    sc =>
    {
        foreach (var user in op.Entities)
        {
            if (user.Cards != null && user.Cards.Any() == true)
            {
                var cards = from kkk in user.Cards
                            select new UserCard(this.CommonDomainContext, user, kkk);

                cards.ToList().ForEach(p =>
                {
                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        this.UserCards.Add(p);
                    });
                });
            }
        }
    });

//Linq subquery 사용 - Include

var orgMembers = this.ObjectContext.USERs_Proc(organizationId).ToList();
var results = from id in orgMembers
              join member in
                   (
                    from user in this.ObjectContext.Users.Include("Cards")
                    let cs = user.Cards
                    where user is Member
                          && (userName == "" || (user as Member).Name.Contains(userName))
                          && (cardId == "" || cs.Count(c => c.Id.Contains(cardId)) > 0)
                    select user
                   )
              on id equals member.Id
              select member;

//Rx 타이머

var timer = Observable.Interval(new TimeSpan(0, 0, 1))
                        .ObserveOnDispatcher();
timerDisp = timer.SubscribeOnDispatcher()
                .Subscribe(time =>
                {
                    if (this.Progress + 60 >= this.Total)
                    {
                        this.Progress = this.Total;
                        timerDisp.Dispose();
                    }
                    else
                        this.Progress += 60;
                });

 

//2개의 컬렉션을 가지고 새로운 컬렉션 생성하고, DataContext에 넣고, SubmitChange() 실행, Submitting 중 Cancel 가능

//모든 작업을 쓰레드풀에서 실행

Scheduler
      .Schedule(Scheduler.ThreadPool, () =>
  {
      var results = from kkk in cards
                    from jjj in permissionGroups
                    let d = (jjj is DoorPermissionGroup ? new CardDoorPermissionGroupRelation() { CardId = kkk.Id, GroupId = (jjj as DoorPermissionGroup).GroupId, LastState = 1 } : null)
                    let f = (jjj is FloorPermissionGroup ? new CardFloorPermissionGroupRelation() { CardId = kkk.Id, GroupId = (jjj as FloorPermissionGroup).GroupId, LastState = 1 } : null)
                    let p = (jjj is PartitionPermissionGroup ? new CardPartitionPermissionGroupRelation() { CardId = kkk.Id, GroupId = (jjj as PartitionPermissionGroup).GroupId, LastState = 1 } : null)
                    select new { door = d, floor = f, partition = p };

 

var doors = from kkk in
                (from kkkk in results
                 where kkkk.door != null
                 select kkkk.door)
            join jjj in this.Context.CardDoorPermissionGroupRelations
            on new { kkk.GroupId, kkk.CardId } equals new { jjj.GroupId, jjj.CardId } into outer
            from o in outer.DefaultIfEmpty()
            where o == null
            select kkk;
var floor = from kkk in
                (from kkkk in results
                 where kkkk.floor != null
                 select kkkk.floor)
            join jjj in this.Context.CardFloorPermissionGroupRelations
            on new { kkk.GroupId, kkk.CardId } equals new { jjj.GroupId, jjj.CardId } into outer
            from o in outer.DefaultIfEmpty()
            where o == null
            select kkk;
var partition = from kkk in
                    (from kkkk in results
                     where kkkk.partition != null
                     select kkkk.partition)
                join jjj in this.Context.CardPartitionPermissionGroupRelations
                on new { kkk.GroupId, kkk.CardId } equals new { jjj.GroupId, jjj.CardId } into outer
                from o in outer.DefaultIfEmpty()
                where o == null
                select kkk;

 

//이렇게 작업하면 스케줄 취소를 했을때 오류가 발생하지 않음

doors.Cast<CardDoorPermissionGroupRelation>().ToList().ForEach(
    p => this.Context.CardDoorPermissionGroupRelations.Add(p));
floor.Cast<CardFloorPermissionGroupRelation>().ToList().ForEach(
    p => this.Context.CardFloorPermissionGroupRelations.Add(p));
partition.Cast<CardPartitionPermissionGroupRelation>().ToList().ForEach(
    p => this.Context.CardPartitionPermissionGroupRelations.Add(p));

 

      submitOp = this.Context.SubmitChanges(
                  p =>
                  {
                      //공통
                      timerDisp.Dispose();

                      if (p.HasError == false)
                      {
                          if (p.IsCanceled == false)
                          {
                              //끝까지 완료
                              this.IsCompleted = true;
                              if (this.Completed != null)
                              {
                                  this.Completed(this, EventArgs.Empty);
                              }
                          }
                          else
                          {
                              //중간에 취소
                              this.IsCanceled = true;
                              this.Context.RejectChanges();
                          }
                      }
                      else
                      {
                          p.MarkErrorAsHandled();
                          this.Context.RejectChanges();
                      }
                  }, null);
  });
 
public void Cancel()
{
    if (submitOp.CanCancel == true)
    {
        submitOp.Cancel();

    }
}

 

 

///스케줄러와 Linq를 이용해서 대량 데이터 수정

addOpDisp = Scheduler
    .Schedule(Scheduler.ThreadPool, () =>
    {
        var results = from kkk in cards
                      let ds = (from door in kkk.CardDoorPermissionGroupRelations
                                select door.LastState = 1)
                      let fs = (from floor in kkk.CardFloorPermissionGroupRelations
                                select floor.LastState = 1)
                      let ps = (from part in kkk.CardPartitionPermissionGroupRelations
                                select part.LastState = 1)
                      let state = kkk.DownState = 1
                      let sum = ds.Count() + fs.Count() + ps.Count()
                      select sum;

 

        foreach (var r in results)
        {
        }
       
        submitOp = this.Context.SubmitChanges(
                        p =>
                        {
                            if (p.HasError == false)
                            {
                                if (p.IsCanceled == false)
                                {
                                    //끝까지 완료
                                    this.IsCompleted = true;
                                    if (this.Completed != null)
                                    {
                                        this.Completed(this, EventArgs.Empty);
                                    }
                                }
                                else
                                {
                                    //중간에 취소
                                    this.IsCanceled = true;
                                    this.Context.RejectChanges();
                                }
                            }
                            else
                            {
                                p.MarkErrorAsHandled();
                                this.Context.RejectChanges();
                            }

                            //공통
                            if (addOpDisp != null)
                                addOpDisp.Dispose();
                        }, null);

    });

'Silverlight > ETC' 카테고리의 다른 글

Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
Twitter Client Lecture(강좌 목록) by Silverlight 5  (0) 2012.01.05
[Arg_COMException] error solution: perhaps  (4) 2012.01.04
블로그 이미지

kaki104

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

01. 풀스크린일 때 LostFocus가 되어도 전체화면을 유지 옵션
Application.Current.Host.Content.FullScreenOptions = System.Windows.Interop.FullScreenOptions.StaysFullScreenWhenUnfocused;

 

02. OOB 상태에서 업데이트 확인

if (App.Current.IsRunningOutOfBrowser)
{
    App.Current.CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(OnCheckAndDownloadUpdateCompleted);
    App.Current.CheckAndDownloadUpdateAsync();
}

void OnCheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
{
    if (e.Error == null && e.UpdateAvailable)
    {
        MessageBox.Show("Application updated, please restart to apply changes.");
    }
}

 

03. Thread Cross Error 발생시            

Deployment.Current.Dispatcher.BeginInvoke(() => {});

 

04. DispatcherTimer

System.Windows.Threading.DispatcherTimer myDispatcherTimer = new System.Windows.Threading.DispatcherTimer();
myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 000); // 100 Milliseconds
myDispatcherTimer.Tick += (ss, ee) =>
{
    if (this.Progress + 60 >= this.Total)
    {
        this.Progress = this.Total;
        myDispatcherTimer.Stop();
    }
    else
        this.Progress += 60;
};
myDispatcherTimer.Start();


 

05. 명시적 바인딩, Explicit
var binding = picker.GetBindingExpression(DateTimePicker.SelectedDateTimeProperty);
binding.UpdateSource();

 

 

06. Behavior, Trigger 만들기

Silverlight and WPF Behaviours and Triggers - Understanding, Exploring And Developing Interactivity using C#, Visual Studio and Blend

http://www.codeproject.com/Articles/57664/Silverlight-and-WPF-Behaviours-and-Triggers-Unders

 

 

07. 정규식 - 이메일

if (this.EmailId.Contains('@') == true)
{
    string emailPattern = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
    System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(emailPattern);

    System.Text.RegularExpressions.Match m = regex.Match(this.EmailId);

    if (m.Success == false)
    {
        //이메일 주소 오류
        return;
    }
}

 

8. 실버라이트5에서 async, await, Task 사용하기

Nuget으로 설치

Async Targeting Pack for Visual Studio 2012

http://www.microsoft.com/en-us/download/details.aspx?id=29576

 

'Silverlight > ETC' 카테고리의 다른 글

Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
Twitter Client Lecture(강좌 목록) by Silverlight 5  (0) 2012.01.05
[Arg_COMException] error solution: perhaps  (4) 2012.01.04
블로그 이미지

kaki104

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

Silverlight가 시작할 때 Parameter를 사용하는 방법에 대해 살펴보자.

 

1. Parameter

실버라이트를 호출하는 페이지에 Get이나 Post를 이용해서 Parameter를 전송하면, 그 것에 따라서 다른 처리를 할 수 있게 되는데,

 

일단 기본 호출 방법은 아래와 같다.

 

http://localhost:57178/Default.aspx

 

여기에 Parameter를 이용해서 호출해 보면 아래와 같다.

 

http://localhost:57178/Default.aspx?para1=123&para2=456

 

2. Parameter를 Web page의 CodeBehind에서 처리하고 initParams로 넘겨서 사용하기

이렇게 사용하는 경우 Parameter를 웹단에서 가공해서 다른 데이터로 변경해서, Silverlight로 넘겨줘야 하는 경우 유용하다. 예를 들어 암호화가된 문자열을 받아서 해독후에 넘겨주는 경우가 있다면, 사용할 수 있겠다.

위에 1.App.xaml.cs load의 경우 파라메터를 App.xaml.cs에서 읽어서 Resource에 추가를 해주도록해서 모든 화면에서 사용이 가능하도록 만들은 것이고, 2.MainPage.xaml.cs direct load의 경우에는 사용하는 화면에서  Parameter를 사용하는 방법이다.

 

Default.aspx.cs -> CodeBehind페이지를 추가

 

namespace SilverlightApplication1.Web
{
    public partial class _Default : System.Web.UI.Page
    {
        public string para1 = string.Empty;
        public string para2 = string.Empty;

 

        protected void Page_Load(object sender, EventArgs e)
        {
            para1 = Request["para1"];
            para2 = Request["para2"];
        }
    }
}

 

Default.aspx

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SilverlightApplication1.Web._Default" %>

...

 

<body>
    <form id="form1" runat="server" style="height:100%">
        <div id="silverlightControlHost">
            <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
        <param name="source" value="ClientBin/SilverlightApplication1.xap"/>
        <param name="onError" value="onSilverlightError" />
        <param name="background" value="white" />
        <param name="minRuntimeVersion" value="4.0.60310.0" />
        <param name="initParams" value="para1=<%=para1 %>,para2=<%=para2 %>" />
        <param name="autoUpgrade" value="true" />
        <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.60310.0" style="text-decoration:none">
          <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
        </a>
         </object>
            <iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>
        </div>
    </form>
</body>

 

[1.App.xaml.cs load]

 

App.xaml.cs

 

private void Application_Startup(object sender, StartupEventArgs e)
{
    //App.xaml에서 읽어서 리소스로 만들어서 사용하기
    if (e.InitParams.ContainsKey("para1"))
    {
        App.Current.Resources.Add("para1", e.InitParams["para1"] as string);
    }
    if (e.InitParams.ContainsKey("para2"))
    {
        App.Current.Resources.Add("para2", e.InitParams["para2"] as string);
    }

    this.RootVisual = new MainPage();
}

 

MainPage.xaml.cs

 

tbPara1.Text = App.Current.Resources["para1"] as string;
tbPara2.Text = App.Current.Resources["para2"] as string;

 

[2.MainPage.xaml.cs direct load]

 

tbDirPara1.Text = App.Current.Host.InitParams["para1"];
tbDirPara2.Text = App.Current.Host.InitParams["para2"];

 

3. Silverlight에서 HtmlPage에 직접 접근해서 Parameter가져오기

 

제일 간단한 방법으로, 여러개의 parameter를 처리하는 경우에는 foreach를 이용할 수도 있다.


tbHtmlPara1.Text = HtmlPage.Document.QueryString.FirstOrDefault(p => p.Key == "para1").Value;
tbHtmlPara2.Text = HtmlPage.Document.QueryString.FirstOrDefault(p => p.Key == "para2").Value;

 

<param name="enableGpuAcceleration" value="true" />
<param name="enableCacheVisualization" value="false" />
<param name="enableFrameRateCounter" value="true" />

4. 소스

 

SilverlightApplication1.zip


'Silverlight > Samples' 카테고리의 다른 글

using Parameter when start up Silverlight  (0) 2012.04.26
블로그 이미지

kaki104

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

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/

지난번에 만들었던 WP7Host 프로젝트를 업그레이드해서 실버라이트에서 아이디와 비밀번호를 입력 받아서 SQL CE 4.0 sdf파일로 asp.net membership 인증을 하고, 인증이 되었을 때 WCF RIA Service에서 인증 확인을 해서 실행여부를 판단하고, 에러 메시지 처리를 어떻게 하는지 종합적으로 적어 보도록 하겠다.

다루고자하는 내용이 좀 방대한 내용이라, 아주 자세한 설명은 생략 하도록 하겠다. 대신, 참고 포스트들을 잘 참고하면 충분히 만들 수 있을 것이라 생각한다.

0. 연결 포스트
http://kaki104.tistory.com/entry/WCF-RIA-Service-hosting-SOAP-endpoint
http://kaki104.tistory.com/entry/Silverlight-5-WCF-RIA-Service-SQL-CE-40

1. 참고 포스트

1) Authentication in Business Application in Silverlight 4
http://www.c-sharpcorner.com/uploadfile/dpatra/authentication-in-business-application-in-silverlight-4/
비지니스 어플리케이션을 이용해서 인증을 하는 기본적인 방법에 대해서 설명해 놓았다. 한번 해보면 어떤 것인지 이해할 수 있다.

2) ASP.NET Universal Providers 1.0.1
http://nuget.org/packages/System.Web.Providers
ASP.NET 4.0에서 SQL Server 2005부터 SQL Azure까지 모든 공급자를 제공. 즉, SQL CE 4.0 공급자도 포함을 하고 있다. 이 것을 먼저 설치 해야한다. (단, Entity Framework 4.1, Entity Framework 4.2 June CTP 버전을 사용 한다면, 이 공급자 없이도 직접 접근이 가능하나, 만들어서 제공해 주는 것이니 부담 가지지 말고 그냥 설치해서 사용한다.)

3) How to: Enable Authentication in RIA Services
http://msdn.microsoft.com/en-us/library/ee707353%28VS.91%29.aspx
WCF RIA Service를 이용해서 인증 서비스를 사용하는 방법에 대한 자세한 설명이 나온다.

4) Silverlight and WCF RIA Services (5-Authentication)
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2010/07/02/silverlight-and-wcf-ria-services-5-authentication.aspx
진짜 자세하게 설명해 놓았다. 너무 자세한 설명이라..약간 길지만..내용은 좋다.

5) ASP.NET SQL Server Registration Tool (Aspnet_regsql.exe)
http://msdn.microsoft.com/en-us/library/ms229862(v=vs.80).aspx
membership 데이터 베이스를 생성해주는 툴에 대한 사용법이다.(SQL Server 필요)


2. .Net Framework 4.0에서 SQL CE 4.0 파일 바로 접근하기
Entity Model을 사용한 접근 방법이 아닌 직접 SQL CE 4.0 파일에 접근을 해야하기 때문에, 이 부분을 먼저 해결해야 한다.

3. WP7Host.Web

1) Web.config
설치를 하면 Web.config에 몇가지가 추가된다.(자동으로 추가가 되는 부분도 있지만, 수동으로 추가해 주어야 하는 부분도 있으니 참고하기 바란다)

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <!--configSection-->
  <configSections>
    <sectionGroup name="system.serviceModel">
      <section name="domainServices" type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" allowDefinition="MachineToApplication" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <!--connectionStrings-->
  <connectionStrings>
    <add name="WP7ModelContainer" connectionString="metadata=res://*/WP7Model.csdl|res://*/WP7Model.ssdl|res://*/WP7Model.msl;provider=System.Data.SqlServerCe.4.0;provider connection string=&quot;Data Source=|DataDirectory|\WP7CE40.sdf&quot;" providerName="System.Data.EntityClient" />
    <add name="DefaultConnection"
         connectionString="Data Source=|DataDirectory|\SqlCeAspnetdb.sdf;"
         providerName="System.Data.SqlServerCe.4.0" />

  </connectionStrings>
  <!--system.web-->
  <system.web>
    <!--httpModules-->
    <httpModules>
      <add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpModules>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
    <!--membership-->
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <clear />
        <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>

    <!--rolmanager-->
    <roleManager enabled="true" defaultProvider="DefaultRoleProvider">
      <providers>
        <clear />
        <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </roleManager>
    <!--profile-->
    <profile defaultProvider="DefaultProfileProvider">
      <providers>
        <clear />
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
      <properties>
        <add name="FriendlyName" />
      </properties>
    </profile>
    <!--authentication 인증관련 부분으로 forms name은 직접 수정해 주어야 한다. -->
    <authentication mode="Forms">
      <forms name=".WP7Host_ASPXAUTH" timeout="2880" />
    </authentication>

    <sessionState mode="InProc" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </sessionState>
  </system.web>
  <!--system.webServer-->
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="DomainServiceModule" preCondition="managedHandler" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </modules>
    <validation validateIntegratedModeConfiguration="false" />
  </system.webServer>
  <!--system.serviceModel-->
  <system.serviceModel>
    <domainServices>
      <endpoints>
        <add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
        <add name="Json" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </endpoints>
    </domainServices>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <!--system.data-->
  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SqlServerCe.4.0"/>
      <add name="Microsoft SQL Server Compact Edition Client Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact Edition Client 4.0" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
    </DbProviderFactories>
  </system.data>
</configuration>

2) 인증 관련 추가 사항
여기에서 추가한 파일들은 New Project를 했을 때 BusinessApplication Template 프로젝트를 만들면 생성되는 파일들이다. 단, SqlCeAspnetdb.sdf 파일은 다른 프로젝트에서 사용했던 것을 복사해 왔다.

Services 폴더에
AuthenticationService.cs                          //인증 서비스
UserRegistrationService.cs                      //사용자 등록 서비스

Resources 폴더에
RegisterationDataResources.resx             //사용자 등록시 사용하는 리소스
RegisterationDataResources.Designer.cs 
ValidationErrorResources.Designer.cs      //사용자 등록시 사용하는 데이터 체크 리소스
ValidationErrorResources.resx

Models 폴더에
User.cs                                                //사용자 클래스
RegistrationData.cs                               //등록 데이터 클래스
Shared 폴더에
User.Shared.cs

App_Data 폴더에
SqlCeAspnetdb.sdf                               //인증 db

서버쪽 작업은 이정도면 완료된 것 같다. 각 파일의 내용은 아래 소스를 받은 후 열어서 보기 바란다.

4. WP7Host

1) App.xaml.cs

  public App()
  {
      this.Startup += this.Application_Startup;
      this.Exit += this.Application_Exit;
      this.UnhandledException += this.Application_UnhandledException;

      InitializeComponent();
     
      //웹컨텍스트를 이용해서 인증을 한다.
      WebContext webContext = new WebContext();
      //폼인증 방식 사용
      webContext.Authentication = new FormsAuthentication();
      this.ApplicationLifetimeObjects.Add(webContext);

  }

  private void Application_Startup(object sender, StartupEventArgs e)
  {
      //웹컨텍스트를 리소스로 추가
      this.Resources.Add("WebContext", WebContext.Current);
      //자동으로 로그인 - 이 페이지에 다시 들어왔을 경우 로그인 유저가 있으면 로드함
      WebContext.Current.Authentication.LoadUser(this.Application_UserLoaded, null);

      this.RootVisual = new MainPage();
  }

  private void Application_UserLoaded(LoadUserOperation operation)
  {
      if (operation.HasError == false)
      {}
      else
      {}
  }


....

  private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
  {
      // If the app is running outside of the debugger then report the exception using
      // the browser's exception mechanism. On IE this will display it a yellow alert
      // icon in the status bar and Firefox will display a script error.
      if (!System.Diagnostics.Debugger.IsAttached)
      {

          // NOTE: This will allow the application to continue running after an exception has been thrown
          // but not handled.
          // For production applications this error handling should be replaced with something that will
          // report the error to the website and stop the application.
          e.Handled = true;
          //예외 처리
          switch (e.ExceptionObject.GetType().ToString())
          {
              case "DomainOperationException":
              case "DomainException":
                  break;
              default:
                  Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
                  break;
          }

      }
  }

2) MainPageViewModel.cs

  //생성자
  public MainPageViewModel()
  {
      Model = new WP7Model();

      if (!DesignerProperties.IsInDesignTool)
      {
          Observable.FromEventPattern<PropertyChangedEventArgs>(Model, "PropertyChanged")
                    .ObserveOn(Scheduler.ThreadPool)
                    .ObserveOnDispatcher()
                    .Subscribe(prop =>
                    {
                        switch (prop.EventArgs.PropertyName)
                        {
                            case "MessageData":
                                this.MessageData = ((WP7Model)prop.Sender).MessageData;
                                break;
                        }
                    });

          WebContext.Current.Authentication.LoggedIn += new EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
          WebContext.Current.Authentication.LoggedOut += new EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);

      }

      IsLogin = false;
  }

  void Authentication_LoggedOut(object sender, System.ServiceModel.DomainServices.Client.ApplicationServices.AuthenticationEventArgs e)
  {
      Display();
  }

  void Authentication_LoggedIn(object sender, System.ServiceModel.DomainServices.Client.ApplicationServices.AuthenticationEventArgs e)
  {
      Display();
  }


  private ICommand loginCommand;
  /// <summary>
  /// 로그인 커맨드
  /// </summary>
  public ICommand LoginCommand
  {
      get
      {
          if (loginCommand == null)
          {
              loginCommand = new ActionCommand(() =>
              {
                  // 파라미터로 넘겨줄 아이디와 패스워드
                  LoginParameters lp = new LoginParameters(UserId, UserPW, false, null);

                  WebContext.Current.Authentication.Login(lp, load =>
                  {
                      if (load.HasError == false && load.LoginSuccess == true)
                      {
                      }
                      else
                      {
                          MessageBox.Show("로그인 실패");
                      }
                  }, null);   
                    
              }
              );
          }
          return loginCommand;
      }
  }

  private ICommand logoutCommand;
  /// <summary>
  /// 로그아웃 커맨드
  /// </summary>
  public ICommand LogoutCommand
  {
      get
      {
          if (logoutCommand == null)
          {
              logoutCommand = new ActionCommand(() =>
              {
                  WebContext.Current.Authentication.Logout(load =>
                  {
                      //Display();
                  }, null);

              }
              );
          }
          return logoutCommand;
      }
  }

  private void Display()
  {
      if (WebContext.Current.User.IsAuthenticated == true)
      {
          IsLogin = true;
          UserName = WebContext.Current.User.DisplayName;
          MessageData = "로그인에 성공 했습니다.";
      }
      else
      {
          IsLogin = false;
          MessageData = "로그인이 필요 합니다.";
      }

  }

5. 실행 결과 확인
1) 로그인 전

2) 로그인 후


6. 인증 데이터로 WCF RIA Service 제한과 에러 메시지 출력

WP7DomainService.cs

  [RequiresAuthentication(ErrorMessage="로그인이 필요한 서비스 입니다.")]
  [RequiresRole("Administrator", ErrorMessage="관리자만 삭제가 가능합니다.")]

  public void DeleteWP7UriList(WP7UriList wP7UriList)
  {
      if ((wP7UriList.EntityState != EntityState.Detached))
      {
          this.ObjectContext.ObjectStateManager.ChangeObjectState(wP7UriList, EntityState.Deleted);
      }
      else
      {
          this.ObjectContext.WP7UriListSet.Attach(wP7UriList);
          this.ObjectContext.WP7UriListSet.DeleteObject(wP7UriList);
      }

      //히스토리 삭제
      this.ObjectContext.WP7HistorySet
              .Where(p => p.WP7UriListId == wP7UriList.Id)
              .ToList().ForEach(p =>
              {
                  this.ObjectContext.WP7HistorySet.Attach(p);
                  this.ObjectContext.WP7HistorySet.DeleteObject(p);
              });
  }

로그인 하지 않은 상태에서 삭제 버튼 클릭

kaki104 (Basic 권한)로 로그인 한 후에 삭제 버튼 클릭

administrator로 로그인 한 후 삭제 버튼 클릭


6. 중요한 내용은 모두 작성한 것 같다. 더 자세한 사항은 소스에 있는 주석을 참고 하기 바란다.


** 소스 크기 제한 때문에 WP7Host Silverlight 프로젝트의 Bin 폴더의 내용은 모두 삭제한 상태임
블로그 이미지

kaki104

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

티스토리 툴바