Layered Silverlight Application - Presentation Layer

Oct 23, 2011 at 2:18 PM

hi,

  I am using Assorted Layered applciation and it includes Silverlight also. I created Silverlight Library project for Silverlight UI process. Here i added service reference and code for getting data asnycronosly. But how can i pass the data geting here to the grid in UI. I added UI Process project in the UI. But data getting asynchonously so how can call method in UI. Can any help among this or sample?

Coordinator
Oct 25, 2011 at 1:26 AM

Hi,

You can create EventHandlers in your UI Process Components (Controller) classes and raise events to signal the UI when the asynchronous calls to the back-end completes. From the UI, subscribe to the Event and populate the UI controls as needed.

Hugs,
Serena 

Oct 31, 2011 at 6:00 AM
Edited Oct 31, 2011 at 6:08 AM

thanks. So i created binding methods in the UI application and asyncronous methodds in the UI process application and in the UI application raise the event in UI process. sorry i didnt get. I got one article which uses AutoResetEvent and signal the UI thread for wait. But when i tried that which blocks entire UI and so that asyncronous method is not called. Can you give some more ideas about your idea

Coordinator
Nov 1, 2011 at 12:59 AM

Hi,

You do not need to use AutoResetEvent. The solution can be implemented quite straight-forward with .NET events.

In your Controller class in UI.Process, create:

a) EventHandlers (and EventArgs)

b) Create OnXXX methods to raise the events with the EventArgs

 

In your Silverlight UI:

a) Register to those events (which you will be assigning an event handling method).

b) Bind the data to your controls in the event handling method.

 

I apologize I am unable to provide you with a code sample right now due to work commitments.

 

Hugs,
Serena

Nov 1, 2011 at 8:18 AM

thanks i will try and tell you

Nov 2, 2011 at 7:35 AM

hi,

 As per your response i created 1 method in my Silverlight User Process class and call asyncronous method here.

Next in silverlight application, mainpage.xaml.cs i register page load event to those event(created in user process) like below



    public partial class MainPage : UserControl
    {
        public UserProcess _uProcess;
        public MainPage()
        {
            InitializeComponent();
            _uProcess = new UserProcess();
             LayoutRoot.DataContext = _uProcess;
           this.Loaded+=new RoutedEventHandler(_uProcess.details);

        }
    }

I can run the project successfully but i have confusion in my datagrid bindings. I have datagrid1 in the mainpage how can i bind the result to this grid. I set data context to my UserController class instance and in my UserProcess class i wrote the code like below;

    public class UserProcess
    {
        UserControl d = null;
    

        public void details(object sender, RoutedEventArgs e)
        {
               d = (UserControl) sender;
                
                UserServiceClient c = new UserServiceClient();
                c.SelectUserDetailsCompleted += new EventHandler<SelectUserDetailsCompletedEventArgs>(c_SelectUserDetailsCompleted);

                c.SelectUserDetailsAsync();
        }

        void c_SelectUserDetailsCompleted(object sender, SelectUserDetailsCompletedEventArgs e)
        {
                if (e.Result != null)
                {
                    d.DataContext = e.Result;
                }
        }
    }

Is this right? or what i did wrongly?

 

Coordinator
Nov 5, 2011 at 4:39 AM

Hi,

Nope, that was not what I had in mind :) Anyway, here is the sample code I managed to whip up during the weekend :)

Step 1. Create an EventArgs class in your UI.Process project.

    public class DataPopulatedEventArgs<T> : EventArgs
    {
        public T Result { get; set; }
    }

In your Controller class in UI.Process project:

Step 2. Create an Event using the .NET EventHandler

        public event EventHandler<EventArgs> DataPopulated;

Step 3. Create a OnDataPopulated method to raise the event.

        protected void OnDataPopulated(EventArgs args)
        {
            if (DataPopulated != null)
                DataPopulated(this, args);
        }

Step 4. Raise the Event in the method which you are calling the WCF service.

        public void ListEmployeeExpenses(long employeeID)
        {
            // Create proxy to WCF service.
            ExpenseServiceClient proxy = new ExpenseServiceClient();

            proxy.ListEmployeeExpensesCompleted += delegate(object sender, ListEmployeeExpensesCompletedEventArgs e)
            {
                // Store the results from the call.
                var args = new DataPopulatedEventArgs<ObservableCollection<Expense>>();
                args.Result = e.Result;

                // Raise the event.
                OnDataPopulated(args);

                // Close the proxy.
                proxy.CloseAsync();

            };

            // Call the WCF method.
            proxy.ListEmployeeExpensesAsync(employeeID);
        }

In your Silverlight page:

Step 5. Register to the event and then bind the result to the controls after the call

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            // Create an instance of the controller.
            ExpenseController upc = new ExpenseController();

            // Register to the data populated event.
            upc.DataPopulated += delegate(object s, EventArgs args)
            {
                // Get the event argument.
                var dataArgs = args as DataPopulatedEventArgs<ObservableCollection<Expense>>;

                // Bind results to UI control.
                dataGrid1.ItemsSource = dataArgs.Result;
            };

            // Call the controller method.
            upc.ListEmployeeExpenses(6);
        }

I have tested it and it works nicely. 

Hope it helps :)

Hugs,
Serena 

Nov 7, 2011 at 1:45 AM
Edited Nov 7, 2011 at 6:40 AM

very thanks friend. I will try

Hi,

   I worked this way and got the result. Thanks for your time. But i have one problem in using business enity

I have Business enity called User. In the UI Process i got the User entity when i add servicereference. Now In the silverlight application i need User entity. We can't refer business applicationto the Silverlight application. So in the silverlight application also i use namespace UI.RIA.Process.ServiceReference1.

I have 2 namespace imported in my xaml code behind


MyApp.UI.RIA.Process;
MyApp.UI.RIA.Process.ServiceReference1;

Is this right?

If so, here i need to get result based on status. For status i have private field StatusID in User enity and return using public filed Status based on enum StatusType. (same as EXpenseType in the sample applcication) - Active 1 and InActive 0

 I have service method SelectUsersByStatus which includes User Enity as paramater.For this i added code like below in the Mainpage.xaml.cs.

User user = new User();
user.Status = StatusType.Active;

//my delegate method

ListUsersByStatus(user);

Here my problem is when i set Status in User object, it couldn't update in StatusID (always 0). So i alway return Inactive users. I can update private filed StatusID = 1 so that reult is correct.

Why i can see and use private field here?
Why statusID not update through Status field? so how i use this?(In my web application it run correctly)

Nov 22, 2011 at 9:48 AM
Edited Nov 22, 2011 at 10:25 AM

hi,,

 I didn't get any answer regarding my business entities using in RIS user process. (just explained above post). So can i convert the business entities project to silverlight library project and add reference to the UI of RIA application? Is this affect any other type of UI application?  

Can you guid how i ingrate this silverlight application with exsting layered project? Based on this only i can continue the process

Coordinator
Nov 23, 2011 at 12:18 AM
Edited Nov 23, 2011 at 2:23 AM

I missed the email notification on your post on Nov 7. So sorry about that.

Things to note:

  • The Silverlight CLR is different from the .NET CLR. Therefore, you can't reuse the same Entity assembly for both projects.
  • When you "Add Service Reference" to your WCF, a set of entities are "code-generated" by Visual Studio for you. You can actually see the code in a Reference.cs file.
  • Therefore, the entities that you accessed on your Silverlight are not the same as the one on your back-end.
  • You can make use of the entities generated by the "Add Service Reference" in Silverlight and if you have somehow conflicting entities in 2 services, you can use the "using" statement to distinguish them.
  • To serialize your own properties in WCF, make sure you have the [DataMember] attribute decorated on your properties and also [Serializable] on your enums.

Reusing .NET CLR classes in Silverlight is a known Silverlight problem. If you port your Entity classes to the UI, you will then need to make sure both sets are insync. I would try to avoid that if possible.

[Updated] I found a very interesting tool. Project Linker http://visualstudiogallery.msdn.microsoft.com/5e730577-d11c-4f2e-8e2b-cbb87f76c044/ This allows you to share code between projects that target different runtime.

Hope it helps!

Hugs,
Serena

Nov 23, 2011 at 4:16 AM
Edited Nov 23, 2011 at 9:06 AM

thanks serena. I have added only one service to the RIA process and the enums are serializable only (not datacontract and datamember). All my entities are declared as [DATAMEMBER].

So using the entity from service is not good. am i right?

I also searched and found that silverlight and .net CLR are different so we can't use non silverlight assemblies can't use in silverlight. But i got articles for work around this

http://msmvps.com/blogs/kevinmcneish/archive/2010/05/28/silverlight-4-101-using-silverlight-assemblies-in-your-non-silverlight-projects.aspx

Also i got easy tool for this to avoid manual reference (portable library tools)

http://visualstudiogallery.msdn.microsoft.com/b0e0b5e9-e138-410b-ad10-00cb3caf4981

So i will check first with project linker and find out way

 

[updated] i tried with project linker. When i added the business entities to the RIA UI project message is shown as project is linked successfully but how i use the entity in the application. Project is linked but i cannt add reference to the business entioty project or cant call the enioty object in the target project (RIA UI)

 

[update]

hi

   i tried with Portable Library Tools. By using this i got the following work arounds

1. I can add business entities reference to RIA UI projects as well as other UIs types.

But have the following problems

1. Serializable attribute is not included in the portable library so i cannt add serializable attribute to the enum or entity classes (if i change status id as public field project run successfully)

2. ObservationCollection is also not included so that i need to use Generic List

Now can you guid me is this good way? if so serialization is must or not? Is any problem if i use Generic List?

IF servicereference enity is good way what i did wrongly?

[update]

hi

 I also tried with Project Linker. so when i add enities class that also linked in the silverlight projects (RIA UI application & RIA UI Process application). The answer return as Entities in the service reference so i just convert to the enity in the servicereference like below

args.Result = e.Result as List<MyApp.Business.Enities.User>;

Also the service method expect User class in the service reference

Its ok. But when i run tha application i got the error in User class  exists in the silverlight application because of serializable attribute.

Now what to do?

 

 

regards

Akhil

 

 

 

Nov 26, 2011 at 3:20 AM
Edited Nov 26, 2011 at 3:20 AM

hi,

 I am confused with entities in silverlight side. If i use portable librry i cant use serializable attribute and so that entities cannt use in silverlight? Any help regarding this?

Regards

Akhil

Coordinator
Nov 26, 2011 at 5:28 AM

Hi,

If you are sharing code between .NET CLR and Silverlight, you need to of course make sure only the compatible feature/options are used for both.

  • It is true that Serializable is not available in Silverlight, therefore you will need to remove it from the entities. With that remove, you can only rely on DataContract Serializer :(
  • ObservableCollection is available in Silverlight. It is in the  System.Collections.ObjectModel namespace.

If you use Project Linker, you need to have another project with the same name at your presentation layer using Siliverlight Class library project. All references in the presentation layer must use Silverlight projects only.

If you use Service Reference, you should not encounter any problems if your entities are just pure data transfer objects that does not contain any logic. I have tried creating an entity with Enumeration type property and I have no problems serializing that across to Silverlight. You will only encounter Entity collision when you have two service references that create same sets of entities. In that scenario, you just need to use the "using" statement to differentiate them i.e.

using WFSvc = MyNamespace.UI.Process.MyWorkflowService;
using WCFSvc = MyNamespace.UI.Process.MyWCFService;

Then you can declare like:

WCFSvc.MyEntity entity = new WCFSvc.MyEntity();

Hugs,
Serena

 

Nov 26, 2011 at 9:10 AM

hi, 

  • It is true that Serializable is not available in Silverlight, therefore you will need to remove it from the entities. With that remove, you can only rely on DataContract Serializer :(

    Ok. i will try with this (This problem araise when i use portable library

  • ObservableCollection is available in Silverlight. It is in the  System.Collections.ObjectModel namespace.

     Yes that is available but when i create entities as portable library project then only the problem araise

    About Enitities

    I have no logic in the entity project. I added only one service reference in my RIA User Interface Component project. As  you gave, io can create instance of the enity llike the below

    User user = new User;

    But when i assign the status for retriveing users list by status i have the problem.

    user.Status = StatusType.Active

    Here i set the status as Active. But it did'nt set private enity member StatusID. So always pass 0 to the DAL. This is my problem. (Here didn't used project linker etc)

    Below is my enity class

    namespace MyApp.Business.Entities
    {
        [DataContract]
        [Serializable]
        public class User : Base
        {
            [DataMember]
            public string UserName { get; set; }
    
            [DataMember]
            public string Password { get; set; }
    
            [DataMember]
            public string NewPassword { get; set; }
    
            [DataMember]
            public string FirstName { get; set; }
    
            [DataMember]
            public string LastName { get; set; }
    
            [DataMember]
            public String FullName { get; set; }
    
            [DataMember]
            public DateTime DOB { get; set; }
    
            [DataMember]
            public int Age { get; set; }
    
            [DataMember]
            public string Email { get; set; }
            
            [DataMember]
            private int StatusID { get; set; }
    
            [DataMember]
            public StatusType Status
            {
                get
                {
                    return (StatusType)this.StatusID;
                }
                set
                {
                    this.StatusID = (int)value;
                }
            }
    
        }
    }
    

    My Status type Enum

    namespace MyApp.Business.Entities
    {
        [Serializable]
        public enum StatusType
        {
            Active = 1,
            InActive = 0,
    
        }
    }
    

    I think you got my problem clearly

     

     

  • Coordinator
    Nov 26, 2011 at 3:51 PM
    Edited Nov 26, 2011 at 4:00 PM

    Hi,

    I am sorry that I am not familiar with the behavior of Portable Library. I am using Project Linker which I think is simpler. I believe theoretically it should be the same.

    • You need to make sure both your Entity and Enum are shared between your Silverlight and .NET CLR projects.
    • You need to Add Reference of the Silverlight Class Library version of your Entities to your Silverlight Projects.
    • You can remove the Serializable attribute and replace it with DataContract.
    • When you Add Service Reference, make sure the 'Reuse types in reference assemblies' option is checked and 'Reuse types in all reference assemblies' is selected. Make sure your entity project is listed in the list box. If it doesn't, that means you did not reference it.

    The reason you are getting 0 for your StatusID is because you are using the Serialized version of the Entity from "Add Service Reference". When you "Add Service Reference", a copy of your entity is created by VS. This replica creates independent private fields for each StatusID and Status. Therefore, assigning value to one will not affect the other. Please ensure you are using your own entity class and not the serialized replica.

    If you have not done it, do remember to "Update Service Reference" after you make your changes.

    Finally, are you using ADO.NET EF? If you are not, you can just do

    [DataMember]
    public StatusType StatusID { get; set; }

    If you are, I am not sure if the latest version of EF i.e. 4.1 allows you to do that as well. Do check it out.

    Hope this helps.

    Nov 27, 2011 at 3:36 AM
    Edited Nov 27, 2011 at 5:50 AM

    hi,

     Thanks. As you told i used serializable attribute in the enum I will try with DataContract.

    I am not using any ADO.NET EF. I am not familiar with this. So Just start with ado.net core. All DAL code using Stored procedure and the enity created by us only

    [update]

    I got your point for nonupdating statusid. Actually retrivng users based on status, i tried with wrong way ie instead of passing StatusType field as paramater i used User type. So only created this much confusion. Now i tried with StatusType as paramater instead of User type i got the result as expected. For this i used the same entoty i got from service reference (Not linked or refrenced my enitity project)

    But because of this i got some more ideas and now thinking in that way. If i need to modify user's details (including status type) i need to pass User type as paramater. So now i need to try this alo. In your way you telling that

    Step 1 : I create seperate silverlight class library project for enitites (same like RIA.Process) and referece to the silverlight applciation. So silverlight enitite are unique project and nonsilverlight enity project is another one.

    Step 2 : Declare enum as [DataContract] instead of serializable and use the same way as ather enity classes

    Am i right? (so not using project linker or something like that)

     

     

    Regards

    Akhil

    Coordinator
    Nov 27, 2011 at 2:24 PM
    Edited Nov 27, 2011 at 2:26 PM

    Akhil,

    If you are not using EF, then your StatusID property can be simplified to just

    [DataMember]
    public StatusType StatusID { get; set; }

    You do not need 2 properties to hold values for ID and enum. Just remember to cast it to the right type in your DAC before doing any CRUD.

    To answer your question, ideally all methods that require to manipulate multiple properties of an Entity should be accepting the entity as parameter. In your case, you should be passing around the User object. The method should be able to manipulate any properties of the entity.

    Whether using Project Linker or hand-coding yourself, the concept of the workaround for Silverlight is the same. If you have a MyProject.Business.Entities project in .NET CLR (back-end), you will need to have a Silverlight class library (whether hand-coded or project linked) name MyProject.Business.Entities.

    All Silverlight projects will reference the Silverlight version.

    When you "Add Service Reference" and instruct VS to 'Reuse types in reference assemblies', no replica of the entities will be generated for you. Therefore, there is only 1 version of entities being used on your Silverlight front-end. 

    When you call your WCF back-end, the entity will be serialized (using DataContractSerializer) and reconstructed on the back-end as objects matching your back-end MyProject.Business.Entities.

    Your problem (and confusion) are caused by the behavior of the svcutil.exe (Add Service Reference) and the differences of runtime between Silverlight and .NET CLR. If you understand what actually happens when you Add Service Reference, then you will be able to understand what is going on (or wrong).

    Are you clear about what I said about replica entities generated by "Add Service Reference" ?

    // Serena


    Nov 28, 2011 at 2:20 AM

    hi,

     Yes i got it. I also try to learn more about this add service reference.

    Actually i thought that even StatsuID is int field, my presentation users can easily fix the status using meaningful name. So i put enum for that. If i use public StatusID field only all users need to know the status number i am going to use in the backend

    Thanks for your help and time

    Regards

    Akhil

     

    Coordinator
    Nov 28, 2011 at 2:28 AM

    Yeah! You got a point there. :)

    // Serena

    Nov 30, 2011 at 2:30 AM

    hi,

    Thanks. Anyway whenever got time try to add one silvrelight sample to Expense Sample. This may also help more people

    Regards

    Akhil