Tag-Archive for ◊ PRISM ◊

Wednesday, February 16th, 2011

Regions in Prism have been extended to support a more general notion of navigation, based on URIs and an extensible navigation mechanism.

Navigation within a region means that a new view is to be displayed within that region. The view to be displayed is identified via a URI, which, by default, refers to the name of the view to be created. You can programmatically initiate navigation using the RequestNavigate method defined by the INavigateAsync interface.

RegionManager in prism have a RequestNavigate method which allows you to specify the name of the region to be navigated. This convenient method obtains a reference to the specified region and then calls the RequestNavigate method, as shown in the code.

private void OnViewNavigationRequested()

{

_regionManager.RequestNavigate(“MainRegion”

, new Uri(“EmployeeView1″, UriKind.Relative)

, (navigationResult) =>

{

if (navigationResult.Result == true) MessageBox.Show(“Success”);

else MessageBox.Show(“Failed”);

});

}

The views need to be registered with the region for navigation to work.

[Import]

public EmployeeView1 View1 { get; set; }

[Import]

public EmployeeView2 View2 { get; set; }

public void Initialize()

{

CreateNavigationTabAndRegisterModule();

RegisterViewsWithRegion();

}

private void RegisterViewsWithRegion()

{

_regionManager.RegisterViewWithRegion(“MainRegion”, () => View1);

_regionManager.RegisterViewWithRegion(“MainRegion”, () => View2);

}

View and View Model Participation in Navigation

The INavigationAware interface is implemented by the View and ViewModel to participate in the navigation process. The interface defines the methods

public interface INavigationAware

{

bool IsNavigationTarget(NavigationContext navigationContext);

void OnNavigatedFrom(NavigationContext navigationContext);

void OnNavigatedTo(NavigationContext navigationContext);

}

The OnNavigatedFrom method can be implemented to save the state of the currently active view or viewmodel before navigation. Similarly OnNavigatedTo method can be used to find details of the view or viewmodel navigated to.

If you want to confirm the navigation from the view, the IConfirmNavigationRequest interface can be implemented on the View or ViewModel to confirm the navigation request. The navigation can be canceled or confirmed based on the logic implemented in the ConfirmNavigationRequest method.

public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)

{

if (MessageBox.Show(“Confirm navigation from this view?”, “Confirm navigation”, MessageBoxButton.OKCancel) == MessageBoxResult.OK)

continuationCallback(true);

else

continuationCallback(false);

}

Category: .Net, Silverlight | Tags: , ,  | One Comment
Sunday, February 13th, 2011

In Prism, loosely coupled components in the application communicate with each other using a event aggregation service that the library provides. The event aggregator service uses a publish/subscribe mechanism for communication. The EventAggregator provides multicast publish/subscribe functionality. This means there can be multiple publishers that raise the same event and there can be multiple subscribers listening to the same event as given below.

EventAggregator_Image

In prism communication between publishers and subscribers is done by the CompositePresentationEvent class. This class maintains the list of subscribers and handles event dispatching to the subscribers.

The CompositePresentationEvent class is a generic class that requires the payload type to be defined as the generic type. This helps enforce, at compile time, that publishers and subscribers provide the correct methods for successful event connection.

Event creation is done by creating a class that inherits the CompositPresentationEvent class.

public class EmployeeAddedEvent : CompositePresentationEvent<Model.Employee> { }

Publishers raise an event by retrieving the event from the EventAggregator and calling the Publish method. To access the EventAggregator, you can use dependency injection by adding a parameter of type IEventAggregator to the class constructor. For e.g.

private void OnAddNewClicked()

{

AddNewEmployeeAndPassToEmployeeView();

}

private void AddNewEmployeeAndPassToEmployeeView()

{

Model.Employee employee = new Model.Employee

{

Id = Guid.NewGuid(),

FirstName = “New Employee”,

LastName = “Last Name”,

ChangedDate = DateTime.Now,

CreatedDate = DateTime.Now,

DateOfJoining = DateTime.Now

};

_eventAggregator.GetEvent<EmployeeAddedEvent>().Publish(employee);

}

Subscribers can enlist with an event using one of the Subscribe method overloads available on the CompositePresentationEvent class. In our sample, you can use the event subscription as

private void SubcribeToEmployeeAddedEvent(IEventAggregator eventAggregator)

{

EmployeeAddedEvent employeeAddedEvent = eventAggregator.GetEvent<EmployeeAddedEvent>();

if (_subscriptionToken != null)

employeeAddedEvent.Unsubscribe(_subscriptionToken);

_subscriptionToken = employeeAddedEvent.Subscribe(OnEmployeeAddedEvent, ThreadOption.UIThread, false);

}

public void OnEmployeeAddedEvent(Model.Employee employee)

{

Employees.Add(employee);

}

If your subscriber no longer wants to receive events, you can unsubscribe by using your subscriber’s handler or you can unsubscribe by using a subscription token.

The following code example shows how to directly unsubscribe to the handler.

employeeAddedEvent.Unsubscribe(OnEmployeeAddedEvent);

Wednesday, February 02nd, 2011

Authentication in Silverlight applications that use WCF RIA services can make use of the WCF RIA services authentication framework. WCF RIA Services builds upon the ASP.NET Membership framework by exposing the Membership framework to rich Internet clients through the authentication domain service. After adding an authentication domain service, you can enable the following functions:

  • Authentication – to verify a user’s credentials and mark the user as logged in or logged out.
  • Roles – to group users by responsibilities and grant resource permissions to authenticated members of a group.
  • Profiles – to retain properties for authenticated users and retrieve those properties in your application.

This post demonstrates how to enable user authentication in your prism application using RIA services.

RIA Services provides the authentication domain service template to facilitate authentication on the presentation tier. The authentication domain service derives the AuthenticationBase class which contains the profile properties for the authenticated user. This service is accessed via the WebContext class which is automatically generated by the RIA services. You can also create your custom implementation for the membership provider and configure the service to use this instead of the default provider.

For e.g.:

public class BlogsPrajeeshMembershipProvider : MembershipProvider

{

public override string ApplicationName

{

get

{

return “BlogsPrajeesh.PrismSamples”;

}

set { }

}

//Other methods…

public override bool ValidateUser(string username, string password)

{

if (username == “Prajeesh” && password == “Password”) return true;

return false;

}

}

Configuring the membership provider in the Web.config file.

<system.web>

<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>

<authentication mode=”Forms” />

<membership defaultProvider=”BlogsPrajeeshMembershipProvider”>

<providers>

<add name=”BlogsPrajeeshMembershipProvider” type=”BlogsPrajeesh.PrismSamples.Web.BlogsPrajeeshMembershipProvider, BlogsPrajeesh.PrismSamples.Web”/>

</providers>

</membership>

</system.web>

To use this authentication service in the Silverlight client, configure the WebContext in App.xaml.cs file as

public App()

{

this.Startup += this.Application_Startup;

this.Exit += this.Application_Exit;

this.UnhandledException += this.Application_UnhandledException;

InitializeComponent();

WebContext context = new WebContext();

context.Authentication = new FormsAuthentication();

ApplicationLifetimeObjects.Add(context);

}

Later in the Shell

public Shell()

{

InitializeComponent();

this.Loaded += new RoutedEventHandler((x, y) =>

{

if (WebContext.Current.Authentication.User != null && !WebContext.Current.Authentication.User.Identity.IsAuthenticated)

{

RegionManager.Regions["LoginRegion"].Add(LoginView, “LoginView”);

RegionManager.Regions["LoginRegion"].Activate(LoginView);

}

});

}

The LoginViewModel code that authenticates the user

[Export(typeof(LoginViewModel))]

[PartCreationPolicy(CreationPolicy.NonShared)]

public class LoginViewModel : NotificationObject

{

[ImportingConstructor]

public LoginViewModel(IRegionManager regionManager)

{

_regionManager = regionManager;

LoginCommand = new DelegateCommand(() => PerformLogin());

this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler((x, y) => RaiseCommandChanged());

}

private void RaiseCommandChanged()

{

LoginCommand.RaiseCanExecuteChanged();

}

private void PerformLogin()

{

var webContext = WebContext.Current;

webContext.Authentication.Login(“Prajeesh”, “Password”);

webContext.Authentication.LoggedIn += new EventHandler<System.ServiceModel.DomainServices.Client.ApplicationServices.AuthenticationEventArgs>((x, y) =>

{

var loginView = _regionManager.Regions["LoginRegion"].GetView(“LoginView”);

_regionManager.Regions["LoginRegion"].Remove(loginView);

});

}

//Other methods…

}

Wednesday, January 19th, 2011

In my previous post Silverlight, PRISM, MVVM, MEF – Part 3, I explained how to add validation metadata to entities and perform data validation on views in the prism application. The standard validation attributes that ship in the System.ComponentModel.DataAnnotations assembly can cover many common validation scenarios. But if you want to do perform custom validations on the business logic, you need to use the CustomValidationAttribute to implement the validation logic. Like the standard validation attributes, it also allows you to specify an ErrorMessage and the properties that failed the validation.

Custom validations can be implemented in a separate class which has static methods that perform the validation. For e.g

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]

public partial class Customer

{

[CustomValidation(typeof(CustomerRules), "ValidateCustomer")]

internal sealed class CustomerMetadata

{

private CustomerMetadata()

{

}

[CustomValidation(typeof(CustomerRules), "IsValidJoiningDate")]

public DateTime? DateOfJoining { get; set; }

}

}

The above sample code has custom validations implemented on entity and property level. The validation rules are implemented in the CustomerRules class which is shared between the server and the client.

public class CustomerRules

{

public static ValidationResult ValidateCustomer(Customer customer, ValidationContext context)

{

if (string.Compare(customer.FirstName, customer.LastName, StringComparison.OrdinalIgnoreCase) == 0)

return new ValidationResult(“First name and last name cannot be same”, new string[] { “FirstName”, “LastName” });

return ValidationResult.Success;

}

public static ValidationResult IsValidJoiningDate(DateTime? joiningDate, ValidationContext context)

{

if (joiningDate.HasValue)

{

if(joiningDate.Value.Year < 1990 || joiningDate.Value.Year > 2011)

return new ValidationResult(“Joining date should be between 01-01-1990 && 31-12-2011″, new string[] { “DateOfJoining”});

}

return ValidationResult.Success;

}

}

In the client code XAML, you just need to set the NotifyOnValidationError property to True to notify the user on validation errors

<TextBox Text=”{Binding CurrentCustomer.FirstName, Mode=TwoWay, NotifyOnValidationError=True}” Grid.Column=”1″ Grid.Row=”2″ Width=”250″ Height=”25″ HorizontalAlignment=”Left” />

<TextBox Text=”{Binding CurrentCustomer.LastName, Mode=TwoWay, NotifyOnValidationError=True}” Grid.Column=”3″ Width=”250″ Height=”25″ HorizontalAlignment=”Left” Grid.Row=”3″ />

<Button Grid.Row=”4″ Content=”Add” prism:Click.Command=”{Binding AddCustomerCommand}” Width=”120″ HorizontalAlignment=”Right” />

<telerik:RadGridView HorizontalAlignment=”Left” Grid.ColumnSpan=”2″ Name=”radGridView1″ VerticalAlignment=”Top” ItemsSource=”{Binding Customers}” SelectedItem=”{Binding CurrentCustomer, Mode=TwoWay}” AutoGenerateColumns=”False”>

<telerik:RadGridView.Columns>

<telerik:GridViewDataColumn DataMemberBinding=”{Binding Id, NotifyOnValidationError=True, Mode=TwoWay}” IsReadOnly=”True” Header=”Customer ID” Width=”100″ />

<telerik:GridViewDataColumn DataMemberBinding=”{Binding FirstName, NotifyOnValidationError=True, Mode=TwoWay}” Header=”First Name” Width=”200″ />

<telerik:GridViewDataColumn DataMemberBinding=”{Binding LastName, NotifyOnValidationError=True, Mode=TwoWay}” Header=”Last Name” Width=”200″ />

<telerik:GridViewDataColumn DataMemberBinding=”{Binding DateOfJoining, NotifyOnValidationError=True, Mode=TwoWay}” Header=”Joined On” Width=”200″ />

</telerik:RadGridView.Columns>

</telerik:RadGridView>

Output

CustomValidation-PrismRIAMVVM

Category: .Net, Silverlight | Tags: , , ,  | 2 Comments
Saturday, January 15th, 2011

Your view model or model will often be required to perform data validation and to signal any data validation errors to the view so that the user can act to correct them.

Silverlight and WPF provide support for managing data validation errors that occur when changing individual properties that are bound to controls in the view. For single properties that are data-bound to a control, the view model or model can signal a data validation error within the property setter by rejecting an incoming bad value and throwing an exception. If the ValidatesOnExceptions property on the data binding is true, the data binding engine in WPF and Silverlight will handle the exception and display a visual cue to the user that there is a data validation error.

However, throwing exceptions with properties in this way should be avoided where possible. An alternative approach is to implement the IDataErrorInfo or INotifyDataErrorInfo interfaces on your view model or model classes. These interfaces allow your view model or model to perform data validation for one or more property values and to return an error message to the view so that the user can be notified of the error.

If you are using WCF RIA services for your silverlight application, the rich built-in support for the validation attributes in the System.ComponentModel.DataAnnotation namespace can be used to implement the validation rules via attributes. Just by having that attribute on the server entity or its metadata class, it shows up on the code generated client entity. Additionally, the WCF RIA Services Entity base class that is added to the client entity has an implementation of INotifyDataErrorInfo that uses the data annotation attributes to perform validation when data bound in the UI. So just by adding these attributes with appropriate error messages, you get validation indications for the user in the UI.

The validation attributes in the System.ComponentModel.DataAnnotation namespace include the ability to specify simple forms of validation on entity properties by adding an attribute to an entity property. For e.g.  The below sample shows data validations applied on the Customer entity.

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]

public partial class Customer

{

internal sealed class CustomerMetadata

{

private CustomerMetadata()

{

}

[Required(ErrorMessage="FirstName should be provided")]

[StringLength(100, ErrorMessage="FirstName max length is 100")]

public string FirstName { get; set; }

[Key]

[Required]

public int Id { get; set; }

[Required(ErrorMessage = "LastName should be provided")]

[StringLength(100, ErrorMessage = "LastName max length is 100")]

public string LastName { get; set; }

[Range(typeof(DateTime), "01/01/1990", "01/01/2011", ErrorMessage="Date of joining should be in the range 01-01-1990 - 01-01-2011")]

public Nullable<DateTime> DateOfJoining { get; set; }

public EntityCollection<Order> Orders { get; set; }

}

}

The XAML code looks like.

<StackPanel Orientation=”Vertical”>

<telerik:RadGridView AutoGenerateColumns=”False” ItemsSource=”{Binding Customers}” SelectedItem=”{Binding CurrentCustomer, Mode=TwoWay}”  HorizontalAlignment=”Left” Margin=”0 20 0 0″>

<telerik:RadGridView.Columns>

<telerik:GridViewDataColumn DataMemberBinding=”{Binding FirstName}” Header=”First Name” Width=”200″ />

<telerik:GridViewDataColumn DataMemberBinding=”{Binding LastName}” Header=”Last Name” Width=”200″/>

<gridViewColumns:DateTimePickerColumn DataMemberBinding=”{Binding DateOfJoining}” Header=”DOJ” Width=”150″ />

</telerik:RadGridView.Columns>

</telerik:RadGridView>

<Grid x:Name=”LayoutRoot” Background=”White”>

<Grid.Resources>

<Style x:Key=”TextBlockStyle” TargetType=”TextBlock” >

<Setter Property=”HorizontalAlignment” Value=”Right” />

<Setter Property=”VerticalAlignment” Value=”Center” />

<Setter Property=”Height” Value=”25″ />

<Setter Property=”Margin” Value=”0 0 10 0″ />

<Setter Property=”FontSize” Value=”14″ />

</Style>

</Grid.Resources>

<Grid.RowDefinitions>

<RowDefinition Height=”35″ />

<RowDefinition Height=”35″ />

<RowDefinition Height=”35″ />

<RowDefinition Height=”35″ />

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width=”250″ />

<ColumnDefinition Width=”*” />

</Grid.ColumnDefinitions>

<TextBlock Text=”First Name” Style=”{StaticResource TextBlockStyle}” />

<TextBlock Text=”Last Name” Style=”{StaticResource TextBlockStyle}” Grid.Row=”1″ />

<TextBlock Text=”Date Of Joining” Style=”{StaticResource TextBlockStyle}” Grid.Row=”2″ />

<TextBox Text=”{Binding CurrentCustomer.FirstName, Mode=TwoWay, NotifyOnValidationError=True}” Grid.Column=”1″ Width=”250″ HorizontalAlignment=”Left” VerticalAlignment=”Center” Height=”25″ />

<TextBox Text=”{Binding CurrentCustomer.LastName, Mode=TwoWay, NotifyOnValidationError=True}” Grid.Column=”1″ Grid.Row=”1″ Width=”250″ HorizontalAlignment=”Left” VerticalAlignment=”Center” Height=”25″ />

<TextBox Text=”{Binding CurrentCustomer.LastName, Mode=TwoWay, NotifyOnValidationError=True}” Grid.Column=”1″ Grid.Row=”1″ Width=”250″ HorizontalAlignment=”Left” VerticalAlignment=”Center” Height=”25″ />

<Button Content=”Update” Width=”100″ Height=”25″ Grid.Row=”3″ HorizontalAlignment=”Right” prism:Click.Command=”{Binding UpdateCustomerCommand}” />

<telerik:RadDatePicker Grid.Column=”1″ Grid.Row=”2″ HorizontalAlignment=”Left” VerticalAlignment=”Center” SelectedValue=”{Binding CurrentCustomer.DateOfJoining, Mode=TwoWay, NotifyOnValidationError=True}” />

</Grid>

</StackPanel>

ViewModel implementation

[Export(typeof(CustomerViewModel))]

[PartCreationPolicy(CreationPolicy.NonShared)]

public class CustomerViewModel : NotificationObject

{

public ObservableCollection<Customer> Customers { get; set; }

public Customer CurrentCustomer

{

get { return _customer; }

set

{

_customer = value;

RaisePropertyChanged(“CurrentCustomer”);

}

}

[ImportingConstructor]

public CustomerViewModel(ICustomerRepository repository)

{

_customerRepository = repository;

Customers = new ObservableCollection<Customer>();

WireEvents();

LoadCustomers();

}

private void WireEvents()

{

_customerRepository.OnCustomersLoaded += new EventHandler<EventArgs<IEnumerable<Customer>>>((x, y) =>

{

foreach (var customer in y.Data) Customers.Add(customer);

});

}

private void LoadCustomers()

{

_customerRepository.GetAll();

}

}

When invalid data is entered in the view, you can see the validation errors on the properties as in the figure below.

Prism3_sample

Category: .Net, Silverlight | Tags: , ,  | One Comment
Friday, January 07th, 2011

Actions or operations that can be performed in the view model are implemented as commands.  Commands provide a convenient way to represent actions or operations that can be easily bound to controls in the UI. They encapsulate the actual code that implements the action or operation and help to keep it decoupled from its actual visual representation in the view.

Commands are implemented in the ViewModel either as CommandMethods or ICommand implementations.  The ICommand objects defines an Execute and CanExecute method which encapsulate the action logic. Prism has a DelegateCommand implementation which implements the ICommand interface. The DelegateCommand’s constructor allows you to define the delegates for the Execute and CanExecute actions.  For e.g the XAML given below shows a button that is bound to a DelegateCommand.

<StackPanel Orientation=”Horizontal” Grid.Row=”1″ HorizontalAlignment=”Right” Margin=”0 15 0 0″>

<TextBlock Text=”Search text: ” VerticalAlignment=”Center” />

<TextBox Width=”240″ Text=”{Binding SearchText, Mode=TwoWay}” />

<Button Content=”Search” prism:Click.Command=”{Binding SearchCommand}” />

</StackPanel>

Namespace implementations

xmlns:prism=”http://www.codeplex.com/prism”

You can also pass command parameters using the CommandParameter property.

In the view model the SearchCommand implementation is defined as

[Export]

[PartCreationPolicy(CreationPolicy.NonShared)]

public class EmployeeViewModel : NotificationObject

{

[ImportingConstructor]

public EmployeeViewModel(IEmployeeRepository employeeRepository)

{

_employeeRepository = employeeRepository;

GetEmployees();

SetCommands();

PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler((x, y) => RaiseCommandChangedEvent());

}

private void RaiseCommandChangedEvent()

{

SearchCommand.RaiseCanExecuteChanged();

}

private void SetCommands()

{

SearchCommand = new DelegateCommand(() => FilterEmployees(), () => !string.IsNullOrEmpty(SearchText));

}

public DelegateCommand SearchCommand { get; private set; }

private void FilterEmployees()

{

//Filter employees here…

}

//Rest of the code…

}

Tuesday, January 04th, 2011

The Model-View-ViewModel (MVVM) pattern helps you to cleanly separate the business and presentation logic of your application from its user interface (UI). The MVVM pattern helps you separate the presentation and business logic to be put into 3 main classes, VIEW, VIEW MODEL and MODEL.

In this post we’ll see the implementation of MVVM in prism using MEF for View and ViewModel discovery.  The class interactions used in this sample is as given below.

MVVM

The model class in the sample contains data for the Employee object

public class Employee : BaseEntity

{

public string FirstName { get; set; }

public string LastName { get; set; }

public DateTime DateOfJoining { get; set; }

public string Designation { get; set; }

}
The EmployeeRepository class is used to query data about employees.

[Export(typeof(IEmployeeRepository))]

public class EmployeeRepository : Repository<Employee>, IEmployeeRepository

{

public override System.Collections.Generic.IEnumerable<Employee> All()

{

return _context.Employees;

}

public override void Save(Employee entity)

{

//Save method

}

public override void Remove(Employee entity)

{

//Remove logic

}

}

The repository instance will be resolved in the ViewModel class via the Import attribute.

[ImportingConstructor]

public EmployeeViewModel(IEmployeeRepository employeeRepository)

{

_employeeRepository = employeeRepository;

GetEmployees();

}

Implementing the View and ViewModel classes

[Export]

[PartCreationPolicy(CreationPolicy.NonShared)]

public class EmployeeViewModel : NotificationObject

{

[ImportingConstructor]

public EmployeeViewModel(IEmployeeRepository employeeRepository)

{

_employeeRepository = employeeRepository;

GetEmployees();

}

private void GetEmployees()

{

Employees = new ObservableCollection<Model.Employee>(_employeeRepository.All());

}

public ObservableCollection<Model.Employee> Employees { get; set; }

IEmployeeRepository _employeeRepository;

}

The ViewModel instance is resolved in the view the same way.

[Export]

[PartCreationPolicy(CreationPolicy.NonShared)]

public partial class EmployeeView : UserControl

{

[Import]

public EmployeeViewModel ViewModel

{

set { DataContext = value; }

}

public EmployeeView()

{

InitializeComponent();

}

}

The NonShared enumeration makes sure that singleton instance of view is not created. Now in the module controller class you can resolve this view instance and show it in the respective region when required. My code sample looks like.

[Import]

public EmployeeView EmployeeView { get; set; }

[ImportingConstructor]

public EmployeeModule(IRegionManager regionManager)

{

_regionManager = regionManager;

}

private void OnSearchAndViewClicked()

{

_regionManager.AddToRegion(“MainRegion”, EmployeeView);

_regionManager.Regions["MainRegion"].Activate(EmployeeView);

}

Final output

PrismMVVM_1

Next we’ll see how to implement commands and interactions between View and ViewModel via ICommand implementation.

Category: .Net, Silverlight | Tags: , ,  | One Comment
Thursday, December 23rd, 2010

The Prism Library provides default control adapters for enabling a control as a region. Extensions around regions may involve providing custom region adapters, custom regions, or replacing the region manager. If you are planning to use a custom Silverlight control or a third party control that does not work with the provided region adapters, you may need to create a custom adapter for the control. In this post I’ll show how to use the RadOutlookBar control as a region manager and create a custom adapter for it in Prism. I have used MEF container instead of unity in this sample.

To create a custom region adapter you need to inherit the RegionAdapterBase class or create an implementation for IRegionAdapter. The sample used in this post inherits the RegionAdapterBase class

public class TelerikOutlookBarRegionAdapter : RegionAdapterBase<RadOutlookBar>

{

public TelerikOutlookBarRegionAdapter(IRegionBehaviorFactory regionBehaviourFactory) : base(regionBehaviourFactory) { }

protected override void Adapt(IRegion region, RadOutlookBar regionTarget)

{

_outlookBar = regionTarget;

_outlookBar.Items.Clear();

region.ActiveViews.CollectionChanged +=

new System.Collections.Specialized.NotifyCollectionChangedEventHandler((x, y) =>

{

switch (y.Action)

{

case NotifyCollectionChangedAction.Add:

foreach (RadOutlookBarItem outlookBarButton in y.NewItems)

_outlookBar.Items.Add(outlookBarButton);

break;

case NotifyCollectionChangedAction.Remove:

foreach (RadOutlookBarItem outlookBarButton in y.NewItems)

_outlookBar.Items.Remove(outlookBarButton);

break;

}

});

region.ActiveViews.ToList().ForEach(x => _outlookBar.Items.Add(x as RadOutlookBarItem));

}

protected override IRegion CreateRegion()

{

return new AllActiveRegion();

}

RadOutlookBar _outlookBar;

}

Next we need to register the region adapter in the Bootstrappers ConfigureRegionAdapterMappings method.

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()

{

var regionAdapterMappings = base.ConfigureRegionAdapterMappings();

var regionBehaviourFactory = Container.GetExportedValue<Microsoft.Practices.Prism.Regions.IRegionBehaviorFactory>();

regionAdapterMappings.RegisterMapping(typeof(Telerik.Windows.Controls.RadOutlookBar), new TelerikOutlookBarRegionAdapter(regionBehaviourFactory));

return regionAdapterMappings;

}

Adding a new Tab from a module can be done like

[ModuleExport("BlogsPrajeesh.PrismSamples.Configuration", typeof(ConfiguraitonModule))]

public class ConfiguraitonModule : IModule

{

[ImportingConstructor]

public ConfiguraitonModule(IRegionManager regionManager)

{

_regionManager = regionManager;

}

public void Initialize()

{

CreateNavigationTabAndRegisterModule();

}

private void CreateNavigationTabAndRegisterModule()

{

RadOutlookBarItem configurationModuleTab = new RadOutlookBarItem();

configurationModuleTab.Header = “Configuration”;

configurationModuleTab.IsSelected = true;

configurationModuleTab.Content = CreateModulePanel();

_regionManager.Regions["NavigationRegion"].Add(configurationModuleTab);

}

StackPanel CreateModulePanel()

{

StackPanel configurationPanel = new StackPanel();

configurationPanel.Orientation = Orientation.Vertical;

configurationPanel.Height = 450;

configurationPanel.Children.Add(CreateModuleLinkItems(“User Profile”, () => OnUserProfileClicked()));

//Add more links

return configurationPanel;

}

HyperlinkButton CreateModuleLinkItems(string content, Action command)

{

HyperlinkButton configurationLinkItem = new HyperlinkButton();

configurationLinkItem.HorizontalAlignment = HorizontalAlignment.Left;

configurationLinkItem.Margin = new Thickness(5D, 5D, 0D, 5D);

configurationLinkItem.Content = content;

configurationLinkItem.Click += new RoutedEventHandler((x, y) => command.Invoke());

return configurationLinkItem;

}

//Other methods…

IRegionManager _regionManager;

}

Output

RadOutlookBarAdapter

Category: .Net, Silverlight | Tags: ,  | 10 Comments