How to: Show Various Notifications to Multiple Users
- 5 minutes to read
When you implement notifications in your application, XAF creates a instance of the notification class and displays it to each user. If one user interacts with this notification (for example, invokes Snooze or Dismiss Actions), XAF propagates modifications for all users. This topic explains how to create different notifications for multiple users to allow them to use Actions without collisions.
Assume that you have an application with the Security System enabled. The
MyNotification
class implements the ISupportNotifications interface and exposes theAssignedTo
andMyTask
properties.using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using DevExpress.Persistent.Base.General; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; using DevExpress.Persistent.BaseImpl.EF; namespace MySolution.Module.BusinessObjects; public class MyNotification : BaseObject, ISupportNotifications { public virtual MyTask MyTask { get; set; } public virtual ApplicationUser AssignedTo { get; set; } private DateTime? alarmTime; public virtual DateTime? AlarmTime { get { return alarmTime; } set { alarmTime = value; if (value == null) { IsPostponed = false; } } } [Browsable(false), NotMapped] public object UniqueId { get { return ID; } } [Browsable(false)] public virtual bool IsPostponed { get; set; } [Browsable(false)] public virtual string NotificationMessage { get { return MyTask.Subject; } } } // Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
The
MyTask
property is an object of the customMyTask
type. TheMyTask
class has theMyNotifications
aggregated collection of notifications that is a part of the one-to-many relationship.using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.EF; using System.Collections.Generic; using System.ComponentModel; using System.Collections.ObjectModel; namespace MySolution.Module.BusinessObjects; [DefaultClassOptions] public class MyTask : BaseObject { public virtual string Subject { get; set; } [DevExpress.ExpressApp.DC.Aggregated] public virtual IList<MyNotification> MyNotifications { get; set; } = new ObservableCollection<MyNotification>(); }
Note
You may use the
Event
class from the Business Class Library with the Scheduler Module instead of the custom ISupportNotifications object. If you do so, Scheduler capabilities will not work (for example, the RecurringReminder functionality). To avoid this, you should create a separateEvent
instance for each user.Navigate to the YourApplicationName.Module\YourApplicationNameModule.cs file. In the overridden ModuleBase.Setup method, subscribe to the XafApplication.LoggedOn event. Get the NotificationsModule instance and subscribe to the DefaultNotificationsProvider.CustomizeNotificationCollectionCriteria event.
using DevExpress.Data.Filtering; using DevExpress.ExpressApp.Notifications; using DevExpress.Persistent.Base.General; // ... public override void Setup(XafApplication application) { base.Setup(application); application.LoggedOn += application_LoggedOn; } void application_LoggedOn(object sender, LogonEventArgs e) { NotificationsModule notificationsModule = Application.Modules.FindModule<NotificationsModule>(); DefaultNotificationsProvider notificationsProvider = notificationsModule.DefaultNotificationsProvider; notificationsProvider.CustomizeNotificationCollectionCriteria += notificationsProvider_CustomizeNotificationCollectionCriteria; } void notificationsProvider_CustomizeNotificationCollectionCriteria( object sender, CustomizeCollectionCriteriaEventArgs e) { if (e.Type == typeof(MyNotification)) { e.Criteria = CriteriaOperator.FromLambda(x => x.AssignedTo == null || x.AssignedTo.ID == (Guid)CurrentUserIdOperator.CurrentUserId()); } }
As a result, XAF filters notifications based on the assigned user if you specify the AssignedTo
property or displays the same notifications for all users if the AssignedTo
value is empty.
If you want to open the corresponding MyTask
Detail View with a double click on a notification in the notification window, create a Controller that inherits from WinNotificationsMessageListViewController
in a WinForms application or WebNotificationsMessageListViewController
in an ASP.NET Web Forms application.
Note
This functionality is not available in XAF ASP.NET Core Blazor applications.
The following code snippet demonstrates the Controller implementation for a Windows Forms application:
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Notifications.Win;
using YourApplicationName.Module.BusinessObjects;
namespace YourApplicationName.Win.Controllers;
public class MyWinNotificationsMessageListViewController : WinNotificationsMessageListViewController {
protected override DevExpress.ExpressApp.View CreateDetailView() {
Object obj = ViewCurrentObject.NotificationSource;
if (ViewCurrentObject.NotificationSource is MyNotification) {
obj = ((MyNotification)ViewCurrentObject.NotificationSource).MyTask;
}
IObjectSpace objectSpace = Application.CreateObjectSpace(obj.GetType());
Object objectInTargetObjectSpace = objectSpace.GetObject(obj);
DevExpress.ExpressApp.View view = Application.CreateDetailView(objectSpace, objectInTargetObjectSpace);
ProcessDetailView(view);
return view;
}
}
If you need to delete a notification when a user dismisses it, create a new ObjectViewController<ViewType, ObjectType>:
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Notifications;
using DevExpress.Persistent.Base.General;
//...
public class DeleteOnDismissController : ObjectViewController<DetailView, NotificationsObject> {
private NotificationsService service;
protected override void OnActivated() {
base.OnActivated();
service = Application.Modules.FindModule<NotificationsModule>().NotificationsService;
NotificationsDialogViewController notificationsDialogViewController =
Frame.GetController<NotificationsDialogViewController>();
if (service != null && notificationsDialogViewController != null) {
notificationsDialogViewController.Dismiss.Executing += Dismiss_Executing;
notificationsDialogViewController.Dismiss.Executed += Dismiss_Executed;
}
}
protected override void OnDeactivated() {
NotificationsDialogViewController notificationsDialogViewController =
Frame.GetController<NotificationsDialogViewController>();
if(notificationsDialogViewController != null) {
notificationsDialogViewController.Dismiss.Executing -= Dismiss_Executing;
notificationsDialogViewController.Dismiss.Executed -= Dismiss_Executed;
}
base.OnDeactivated();
}
private void Dismiss_Executing(object sender, System.ComponentModel.CancelEventArgs e) {
service.ItemsProcessed += Service_ItemsProcessed;
}
private void Service_ItemsProcessed(object sender,
DevExpress.Persistent.Base.General.NotificationItemsEventArgs e) {
IObjectSpace space = Application.CreateObjectSpace(typeof(MyNotification));
foreach(INotificationItem item in e.NotificationItems) {
if(item.NotificationSource is MyNotification) {
space.Delete(space.GetObject(item.NotificationSource));
}
}
space.CommitChanges();
}
private void Dismiss_Executed(object sender,
DevExpress.ExpressApp.Actions.ActionBaseEventArgs e) {
service.ItemsProcessed -= Service_ItemsProcessed;
}
}