Skip to main content

Create a Custom Service

  • 4 minutes to read

This topic describes how to create a custom service if predefined services do not suit your requirements.

Note

If you need to implement the logic that should access a UI element in the View Model code, you can use the UIObjectService instead.

Follow the steps below to create a custom service, attach it to a control, and access this service in the View Model:

  1. Create a service interface with methods that should be called from the View Model:

    public interface IGridUpdateService {
        void BeginUpdate();
        void EndUpdate();
    }
    
  2. Create a ServiceBase class descendant that implements your interface:

    using DevExpress.Mvvm.UI;
    // ...
    public class GridUpdateService : ServiceBase, IGridUpdateService {
        public void BeginUpdate() {
            // ...
        }
        public void EndUpdate() {
            // ...
        }
    }
    
  3. Use the AssociatedObject property to access the associated control:

    using DevExpress.Xpf.Grid;
    // ...
    public class GridUpdateService : ServiceBase, IGridUpdateService {
        GridControl GridControl => AssociatedObject as GridControl;
    
        public void BeginUpdate() {
            Dispatcher.Invoke(new Action(() => {
                if (GridControl != null) {
                    GridControl.BeginDataUpdate();
                }
            }));
        }
    
        public void EndUpdate() {
            Dispatcher.Invoke(new Action(() => {
                if (GridControl != null) {
                    GridControl.EndDataUpdate();
                }
            }));
        }
    }
    

    In this example, the Dispatcher object is used to call methods of the associated control in the UI thread.

  4. Add your service to the Behaviors collection to attach it to a control:

    <Window ...
            xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
            xmlns:local="clr-namespace:DXGridThreads"
            xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm">
        <Window.DataContext>
            <local:ViewModel />
        </Window.DataContext>
        <dxg:GridControl AutoGenerateColumns="AddNew" 
                         ItemsSource="{Binding Source}">
            <dxmvvm:Interaction.Behaviors>
                <local:GridUpdateService/>
            </dxmvvm:Interaction.Behaviors>
        </dxg:GridControl>
    </Window>
    
  5. Access your service in the View Model:

    using DevExpress.Mvvm;
    // ...
    public class ViewModel : ViewModelBase {
        public IGridUpdateService GridUpdateService { get { return GetService<IGridUpdateService>(); } }
    
        void TimerCallback(object state) {
            lock(SyncRoot) {
                if(GridUpdateService != null) {
                    GridUpdateService.BeginUpdate();
                    foreach(DataItem item in Source) {
                        item.Value = random.Next(100);
                    }
                    GridUpdateService.EndUpdate();
                }
            }
        }
    }
    
  6. (Optional) Add a DependencyProperty to your service. This property is set at the View level and you can use its value within the service:

    public class GridUpdateService : ServiceBase, IGridUpdateService {
        public static readonly DependencyProperty UpdatedTextProperty =
            DependencyProperty.Register("UpdatedText", typeof(string), typeof(GridUpdateService), new PropertyMetadata("Updated"));
    
        public string UpdatedText {
            get { return (string)GetValue(UpdatedTextProperty); }
            set { SetValue(UpdatedTextProperty, value); }
        }
        // ...
    }
    
    <dxmvvm:Interaction.Behaviors>
        <local:GridUpdateService UpdatedText="Modified"/>
    </dxmvvm:Interaction.Behaviors>
    
  7. (Optional) Override OnAttached and OnDetaching methods to subscribe and unsubscribe from associated control events:

    public class GridUpdateService : ServiceBase, IGridUpdateService {
        GridControl GridControl => AssociatedObject as GridControl;
    
        protected override void OnAttached() {
            base.OnAttached();
            GridControl.CustomColumnDisplayText += GridControl_CustomColumnDisplayText;
        }
    
        private void GridControl_CustomColumnDisplayText(object sender, CustomColumnDisplayTextEventArgs e) {
            // ...
        }
    
        protected override void OnDetaching() {
            GridControl.CustomColumnDisplayText -= GridControl_CustomColumnDisplayText;
            base.OnDetaching();
        }
    }
    

The complete sample project is available in the following GitHub repository:

View Example: Data Grid for WPF - How to Update Data in a Separate Thread

See Also