wpf-113943-mvvm-framework-services-predefined-set-viewinjectionservice-implementing-custom-strategy.md
Below is a list of controls supported by the ViewInjectionService out of the box.
For each control from this list, the ViewInjectionService provides a separate View Injection Strategy. The Strategy implements the view injection mechanism for the specified control (and its descendants). You can create your own strategy or adapt an existing one. To customize the existing strategy, implement a wrapper for your specified control. Wrapper provides the base API for the interaction with your control.
Here is the default wrapper for the ItemsControl.
public interface IItemsControlWrapper<T> : ITargetWrapper<T> where T : DependencyObject {
object ItemsSource { get; set; }
DataTemplate ItemTemplate { get; set; }
DataTemplateSelector ItemTemplateSelector { get; set; }
}
...
public class ItemsControlWrapper : IItemsControlWrapper<ItemsControl> {
public ItemsControl Target { get; set; }
public object ItemsSource {
get { return Target.ItemsSource; }
set { Target.ItemsSource = (IEnumerable)value; }
}
public virtual DataTemplate ItemTemplate {
get { return Target.ItemTemplate; }
set { Target.ItemTemplate = value; }
}
public virtual DataTemplateSelector ItemTemplateSelector {
get { return Target.ItemTemplateSelector; }
set { Target.ItemTemplateSelector = value; }
}
}
Public Interface IItemsControlWrapper(Of T As DependencyObject)
Inherits ITargetWrapper(Of T)
Property ItemsSource() As Object
Property ItemTemplate() As DataTemplate
Property ItemTemplateSelector() As DataTemplateSelector
End Interface
...
Public Class ItemsControlWrapper
Implements IItemsControlWrapper(Of ItemsControl)
Public Property Target() As ItemsControl
Get
Return m_Target
End Get
Set
m_Target = Value
End Set
End Property
Private m_Target As ItemsControl
Public Property ItemsSource() As Object Implements IItemsControlWrapper(Of ItemsControl).ItemsSource
Get
Return Target.ItemsSource
End Get
Set
Target.ItemsSource = DirectCast(value, IEnumerable)
End Set
End Property
Public Overridable Property ItemTemplate() As DataTemplate Implements IItemsControlWrapper(Of ItemsControl).ItemTemplate
Get
Return Target.ItemTemplate
End Get
Set
Target.ItemTemplate = value
End Set
End Property
Public Overridable Property ItemTemplateSelector() As DataTemplateSelector Implements IItemsControlWrapper(Of ItemsControl).ItemTemplateSelector
Get
Return Target.ItemTemplateSelector
End Get
Set
Target.ItemTemplateSelector = value
End Set
End Property
End Class
Below is an illustration that implements a custom strategy by using an example of injecting an element (command buttons) in the RibbonControl.
To adapt the ViewInjectionService for RibbonControl so the service injects BarButtonItems into the specified RibbonControl’s Group (taking into account the Categories and Pages), create a custom descendant of the IItemsControlWrapper interface.
public class RibbonControlWrapper : IItemsControlWrapper<RibbonControl> {
...
}
Public Class RibbonControlWrapper
Implements IItemsControlWrapper(Of RibbonControl)
Handle the changes of the ItemsSource that is the collection of command-button ViewModels ( RibbonItemViewModel instances). To subscribe the CollectionChanged event, use the ItemsSource property’s setter.
public class RibbonControlWrapper : IItemsControlWrapper<RibbonControl> {
public RibbonControl Target { get; set; }
private object _ItemsSource;
public object ItemsSource {
get {
return _ItemsSource;
}
set {
if (_ItemsSource != value) {
if (_ItemsSource != null)
((INotifyCollectionChanged)_ItemsSource).CollectionChanged -= RibbonControlWrapper_CollectionChanged;
_ItemsSource = value;
((INotifyCollectionChanged)_ItemsSource).CollectionChanged += RibbonControlWrapper_CollectionChanged;
}
}
}
void RibbonControlWrapper_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
...
}
}
Public Class RibbonControlWrapper
Implements IItemsControlWrapper(Of RibbonControl)
Private _Target As RibbonControl
Public WriteOnly Property Target() As RibbonControl Implements DevExpress.Mvvm.UI.ViewInjection.ITargetWrapper(Of RibbonControl).Target
Set
_Target = value
End Set
End Property
Private _ItemsSource As Object
Public Property ItemsSource() As Object Implements IItemsControlWrapper(Of RibbonControl).ItemsSource
Get
Return _ItemsSource
End Get
Set(ByVal value As Object)
If _ItemsSource IsNot value Then
If _ItemsSource IsNot Nothing Then
RemoveHandler DirectCast(_ItemsSource, INotifyCollectionChanged).CollectionChanged, AddressOf RibbonControlWrapper_CollectionChanged
End If
_ItemsSource = value
AddHandler DirectCast(_ItemsSource, INotifyCollectionChanged).CollectionChanged, AddressOf RibbonControlWrapper_CollectionChanged
End If
End Set
End Property
Private Sub RibbonControlWrapper_CollectionChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
...
End Sub
Implement a logic for adding BarButtonItems in the RibbonControlWrapper_CollectionChanged event hander. For instance:
void RibbonControlWrapper_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
if (e.Action == NotifyCollectionChangedAction.Add) {
foreach (RibbonItemViewModel vm in e.NewItems) {
var category = Target.Categories.FirstOrDefault(c => String.Equals(c.Name, vm.Category) || String.Equals(c.Caption, vm.Category));
if (category == null) {
category = new RibbonPageCategory() { Name = vm.Category.Replace(" ", ""), Caption = vm.Category };
Target.Categories.Add(category);
}
var page = category.Pages.FirstOrDefault(p => String.Equals(p.Name, vm.Page) || String.Equals(p.Caption, vm.Page));
if (page == null) {
page = new RibbonPage() { Name = vm.Page.Replace(" ", ""), Caption = vm.Page };
category.Pages.Add(page);
}
var group = page.Groups.FirstOrDefault(g => String.Equals(g.Name, vm.Group) || String.Equals(g.Caption, vm.Group));
if (group == null) {
group = new RibbonPageGroup() { Name = vm.Group.Replace(" ", ""), Caption = vm.Group };
page.Groups.Add(group);
}
group.Items.Add(new BarButtonItem() { Content = vm.Content, Glyph = vm.Glyph });
}
}
}
Private Sub RibbonControlWrapper_CollectionChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
If e.Action = NotifyCollectionChangedAction.Add Then
For Each vm As RibbonItemViewModel In e.NewItems
Dim category = _Target.Categories.FirstOrDefault(Function(c) String.Equals(c.Name, vm.Category) OrElse String.Equals(c.Caption, vm.Category))
If category Is Nothing Then
category = New RibbonPageCategory() With {.Name = vm.Category.Replace(" ", ""), .Caption = vm.Category}
_Target.Categories.Add(category)
End If
Dim page = category.Pages.FirstOrDefault(Function(p) String.Equals(p.Name, vm.Page) OrElse String.Equals(p.Caption, vm.Page))
If page Is Nothing Then
page = New RibbonPage() With {.Name = vm.Page.Replace(" ", ""), .Caption = vm.Page}
category.Pages.Add(page)
End If
Dim group = page.Groups.FirstOrDefault(Function(g) String.Equals(g.Name, vm.Group) OrElse String.Equals(g.Caption, vm.Group))
If group Is Nothing Then
group = New RibbonPageGroup() With {.Name = vm.Group.Replace(" ", ""), .Caption = vm.Group}
page.Groups.Add(group)
End If
group.Items.Add(New BarButtonItem() With {.Content = vm.Content, .Glyph = vm.Glyph})
Next vm
End If
End Sub
The RibbonItemViewModel is a class that represents the command-button ViewModel.
public class RibbonItemViewModel {
public virtual string Category { get; protected set; }
public virtual string Page { get; protected set; }
public virtual string Group { get; protected set; }
public virtual string Content { get; protected set; }
public virtual ImageSource Glyph { get; protected set; }
...
}
Public Class RibbonItemViewModel
Private privateCategory As String
Public Overridable Property Category() As String
Get
Return privateCategory
End Get
Protected Set(ByVal value As String)
privateCategory = value
End Set
End Property
Private privatePage As String
Public Overridable Property Page() As String
Get
Return privatePage
End Get
Protected Set(ByVal value As String)
privatePage = value
End Set
End Property
Private privateGroup As String
Public Overridable Property Group() As String
Get
Return privateGroup
End Get
Protected Set(ByVal value As String)
privateGroup = value
End Set
End Property
Private privateContent As String
Public Overridable Property Content() As String
Get
Return privateContent
End Get
Protected Set(ByVal value As String)
privateContent = value
End Set
End Property
Private privateGlyph As ImageSource
Public Overridable Property Glyph() As ImageSource
Get
Return privateGlyph
End Get
Protected Set(ByVal value As ImageSource)
privateGlyph = value
End Set
End Property
Protected Sub New()
End Sub
...
End Class
To register the newly implemented strategy, use the StrategyManager and its StrategyManager.RegisterStrategy<TTarget, TStrategy> method. Since this manager is similar to the ViewInjectionManager , you can also access it from any section of your code: for instance, from the StartUp event handler as shown in the code snippet below.
public partial class App : Application {
private void Application_Startup(object sender, StartupEventArgs e) {
StrategyManager.Default.RegisterStrategy<RibbonControl, ItemsControlStrategy<RibbonControl, RibbonControlWrapper>>();
...
}
...
}
Partial Public Class App
Inherits Application
Private Sub Application_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
StrategyManager.Default.RegisterStrategy(Of RibbonControl, ItemsControlStrategy(Of RibbonControl, RibbonControlWrapper))()
...
End Sub
...
End Class
Use the Inject method to integrate the RibbonItemViewModel.
<dxr:RibbonControl>
<dxr:RibbonDefaultPageCategory Caption="Default PageCategory" Name="defaultPageCategory">
<dxr:RibbonPage Caption="Default Page" Name="defaultPage">
<dxr:RibbonPageGroup Caption="Default PageGroup" Name="defaultPageGroup"/>
</dxr:RibbonPage>
</dxr:RibbonDefaultPageCategory>
<dxmvvm:Interaction.Behaviors>
<dxmvvm:ViewInjectionService RegionName="{x:Static c:Regions.Main}"/>
</dxmvvm:Interaction.Behaviors>
</dxr:RibbonControl>
ViewInjectionManager.Default.Inject(
Regions.Main,
null,
() => RibbonItemViewModel.Create(
"Default PageCategory",
"Default Page",
"Default PageGroup",
"New BarButtonItem #1",
new BitmapImage(new Uri("pack://application:,,,/DevExpress.Images.v14.2;component/Images/Actions/New_16x16.png"))
),
String.Empty
);
ViewInjectionManager.Default.Inject(
Regions.Main,
Nothing,
Function() RibbonItemViewModel.Create(
"Default PageCategory",
"Default Page",
"Default PageGroup",
"New BarButtonItem #1",
New BitmapImage(New Uri("pack://application:,,,/DevExpress.Images.v14.2;component/Images/Actions/New_16x16.png"))
),
String.Empty
)
See Also