# Create a Custom Service | WPF Controls | DevExpress Documentation

This topic describes how to create a custom service if [predefined services](/WPF/113931/mvvm-framework/services/predefined-set) 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](/WPF/404099/mvvm-framework/services/predefined-set/ui-object-service) 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:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">public interface IGridUpdateService {
    void BeginUpdate();
    void EndUpdate();
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Interface IGridUpdateService
    Sub BeginUpdate()
    Sub EndUpdate()
End Interface
</code></pre></section>
2. Create a [ServiceBase](/WPF/DevExpress.Mvvm.UI.ServiceBase) class descendant that implements your interface:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF-1_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;/ (DevExpress.Mvvm.UI)(?:;|$)/&quot;:&quot;/WPF/DevExpress.Mvvm.UI&quot;}" class="lang-csharp">using DevExpress.Mvvm.UI;
// ...
public class GridUpdateService : ServiceBase, IGridUpdateService {
    public void BeginUpdate() {
        // ...
    }
    public void EndUpdate() {
        // ...
    }
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF-1_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;/ (DevExpress.Mvvm.UI)(?:;|$)/&quot;:&quot;/WPF/DevExpress.Mvvm.UI&quot;}" class="lang-vb">Imports DevExpress.Mvvm.UI
&#39; ...
Public Class GridUpdateService
    Inherits ServiceBase
    Implements IGridUpdateService

    Public Sub BeginUpdate() Implements IGridUpdateService.BeginUpdate
        &#39; ...
    End Sub

    Public Sub EndUpdate() Implements IGridUpdateService.EndUpdate
        &#39; ...
    End Sub
End Class
</code></pre></section>
3. Use the `AssociatedObject` property to access the associated control:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF-2_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;/ (DevExpress.Xpf.Grid)(?:;|$)/&quot;:&quot;/WPF/DevExpress.Xpf.Grid&quot;}" class="lang-csharp">using DevExpress.Xpf.Grid;
// ...
public class GridUpdateService : ServiceBase, IGridUpdateService {
    GridControl GridControl =&gt; AssociatedObject as GridControl;

    public void BeginUpdate() {
        Dispatcher.Invoke(new Action(() =&gt; {
            if (GridControl != null) {
                GridControl.BeginDataUpdate();
            }
        }));
    }

    public void EndUpdate() {
        Dispatcher.Invoke(new Action(() =&gt; {
            if (GridControl != null) {
                GridControl.EndDataUpdate();
            }
        }));
    }
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF-2_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;/ (DevExpress.Xpf.Grid)(?:;|$)/&quot;:&quot;/WPF/DevExpress.Xpf.Grid&quot;}" class="lang-vb">Imports DevExpress.Xpf.Grid
&#39; ...
Public Class GridUpdateService
    Inherits ServiceBase
    Implements IGridUpdateService

    Private ReadOnly Property GridControl As GridControl
        Get
            Return TryCast(AssociatedObject, GridControl)
        End Get
    End Property

    Public Sub BeginUpdate() Implements IGridUpdateService.BeginUpdate
        Dispatcher.Invoke(New Action(Sub()
            If GridControl IsNot Nothing Then
                GridControl.BeginDataUpdate()
            End If
        End Sub))
    End Sub

    Public Sub EndUpdate() Implements IGridUpdateService.EndUpdate
        Dispatcher.Invoke(New Action(Sub()
            If GridControl IsNot Nothing Then
                GridControl.EndDataUpdate()
            End If
        End Sub))
    End Sub
End Class
</code></pre></section>

     In this example, the [Dispatcher](https://learn.microsoft.com/dotnet/api/system.windows.threading.dispatcher) object is used to call methods of the associated control in the UI thread.
4. Add your service to the [Behaviors](/WPF/DevExpress.Mvvm.UI.Interactivity.Interaction.Behaviors) collection to attach it to a control:

- XAML

<section id="tabpanel_HX8b4IXohF-3_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code data-highlight-lines="[[10,12]]" class="lang-xaml">&lt;Window ...
        xmlns:dxg=&quot;http://schemas.devexpress.com/winfx/2008/xaml/grid&quot;
        xmlns:local=&quot;clr-namespace:DXGridThreads&quot;
        xmlns:dxmvvm=&quot;http://schemas.devexpress.com/winfx/2008/xaml/mvvm&quot;&gt;
    &lt;Window.DataContext&gt;
        &lt;local:ViewModel /&gt;
    &lt;/Window.DataContext&gt;
    &lt;dxg:GridControl AutoGenerateColumns=&quot;AddNew&quot; 
                     ItemsSource=&quot;{Binding Source}&quot;&gt;
        &lt;dxmvvm:Interaction.Behaviors&gt;
            &lt;local:GridUpdateService/&gt;
        &lt;/dxmvvm:Interaction.Behaviors&gt;
    &lt;/dxg:GridControl&gt;
&lt;/Window&gt;
</code></pre></section>
5. Access your service in the View Model:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF-4_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;}" class="lang-csharp">using DevExpress.Mvvm;
// ...
public class ViewModel : ViewModelBase {
    public IGridUpdateService GridUpdateService { get { return GetService&lt;IGridUpdateService&gt;(); } }

    void TimerCallback(object state) {
        lock(SyncRoot) {
            if(GridUpdateService != null) {
                GridUpdateService.BeginUpdate();
                foreach(DataItem item in Source) {
                    item.Value = random.Next(100);
                }
                GridUpdateService.EndUpdate();
            }
        }
    }
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF-4_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;}" class="lang-vb">Imports DevExpress.Mvvm
&#39; ...
Public Class ViewModel
    Inherits ViewModelBase

    Public ReadOnly Property GridUpdateService As IGridUpdateService
        Get
            Return GetService(Of IGridUpdateService)()
        End Get
    End Property

    Private Sub TimerCallback(ByVal state As Object)
        SyncLock SyncRoot
            If GridUpdateService IsNot Nothing Then
                GridUpdateService.BeginUpdate()
                For Each item As DataItem In Source
                    item.Value = random.Next(100)
                Next

                GridUpdateService.EndUpdate()
            End If
        End SyncLock
    End Sub
End Class
</code></pre></section>
6. (Optional) Add a [DependencyProperty](https://learn.microsoft.com/dotnet/api/system.windows.dependencyproperty) to your service. This property is set at the View level and you can use its value within the service:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF-5_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">public class GridUpdateService : ServiceBase, IGridUpdateService {
    public static readonly DependencyProperty UpdatedTextProperty =
        DependencyProperty.Register(&quot;UpdatedText&quot;, typeof(string), typeof(GridUpdateService), new PropertyMetadata(&quot;Updated&quot;));

    public string UpdatedText {
        get { return (string)GetValue(UpdatedTextProperty); }
        set { SetValue(UpdatedTextProperty, value); }
    }
    // ...
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF-5_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Class GridUpdateService
    Inherits ServiceBase
    Implements IGridUpdateService

    Public Shared ReadOnly UpdatedTextProperty As DependencyProperty = 
        DependencyProperty.Register(&quot;UpdatedText&quot;, GetType(String), GetType(GridUpdateService), New PropertyMetadata(&quot;Updated&quot;))

    Public Property UpdatedText As String
        Get
            Return CStr(GetValue(UpdatedTextProperty))
        End Get
        Set(ByVal value As String)
            SetValue(UpdatedTextProperty, value)
        End Set
    End Property
    &#39; ...
End Class
</code></pre></section>

- XAML

<section id="tabpanel_HX8b4IXohF-6_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code class="lang-xaml">&lt;dxmvvm:Interaction.Behaviors&gt;
    &lt;local:GridUpdateService UpdatedText=&quot;Modified&quot;/&gt;
&lt;/dxmvvm:Interaction.Behaviors&gt;
</code></pre></section>
7. (Optional) Override `OnAttached` and `OnDetaching` methods to subscribe and unsubscribe from associated control events:

- C#
    - VB.NET

<section id="tabpanel_HX8b4IXohF-7_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">public class GridUpdateService : ServiceBase, IGridUpdateService {
    GridControl GridControl =&gt; 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();
    }
}
</code></pre></section>
<section id="tabpanel_HX8b4IXohF-7_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Class GridUpdateService
    Inherits ServiceBase
    Implements IGridUpdateService

    Private ReadOnly Property GridControl As GridControl
        Get
            Return TryCast(AssociatedObject, GridControl)
        End Get
    End Property

    Protected Overrides Sub OnAttached()
        MyBase.OnAttached()
        GridControl.CustomColumnDisplayText += AddressOf GridControl_CustomColumnDisplayText
    End Sub

    Private Sub GridControl_CustomColumnDisplayText(ByVal sender As Object, ByVal e As CustomColumnDisplayTextEventArgs)
    &#39; ...
    End Sub

    Protected Overrides Sub OnDetaching()
        GridControl.CustomColumnDisplayText -= AddressOf GridControl_CustomColumnDisplayText
        MyBase.OnDetaching()
    End Sub
End Class
</code></pre></section>

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](https://github.com/DevExpress-Examples/wpf-data-grid-update-data-in-a-separate-thread)

See Also

[Create a Custom Behavior](/WPF/17442/mvvm-framework/behaviors#create-a-custom-behavior)

[Example: Create a Custom Service](https://github.com/DevExpress-Examples/wpf-mvvm-framework-create-a-custom-service)