W Prism mamy dostępnych kilka adapterów regionów "od ręki" - pozostałe musimy sami stworzyć.
W jakich sytuacjach może zajść konieczność stworzenia własnego adaptera regionów? Jeżeli chcemy użyć jakiejś kontrolki jako miejsca w które Prism będzie ładował widoki, a obecnie nie ma takiej obsługi w prosty sposób możemy taką obsługę dodać.
Zobaczmy na przykład:
Code:
<Window x:Class="WpfApplication1.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
Title="Shell" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" prism:RegionManager.RegionName="NavigationRegion" />
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</StackPanel>
</Grid>
</Window>
Uruchomienie aplikacji spowoduje następujący błąd:
W wolnym tłumaczeniu wyjątek oznacza iż dana kontrolka nie obsługuje regionów. Tak więc nie pozostaje nam nic innego jak dodać do kontrolki obsługę regionów.
Dodanie obsługi danego regionu składa się z 4 kroków:
- Tworzymy klasę dziedziczącą po RegionAdapterBase<T>
- Implementujemy metodę CreateRegion która zwraca jeden z trzech wyników determinujących zachowania regionu:
- SingleActiveRegion - jeden aktywny region w danym momencie (ContentControl)
- AllActiveRegion - wszystkie regiony aktywne (ItemsControls)
- Region - wiele aktywnych regionów (SelectorControls)
- Implementacja metody Adapt
- Rejestracja stworzonego adaptera w Bootstrapperze
Żeby lepiej zobrazować powyższe kroki przejdziemy je podczas implementowania obsługi regionów w kontrolce StackPanel.
1. Klasa dziedzicząca po klasie RegionAdapterBase<T> :
Code:
public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
{
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
throw new SystemNotImplementedException();
}
protected override IRegion CreateRegion()
{
throw new SystemNotImplementedException();
}
}
2. Metoda CreateRegion
Code:
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (FrameworkElement item in e.NewItems)
{
regionTarget.Children.Add(item);
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (FrameworkElement item in e.NewItems)
{
if (regionTarget.Children.Contains(item))
{
regionTarget.Children.Remove(item);
}
}
}
};
}
Tak więc w metodzie tej nasłuchujemy zdarzenia zmiany kolekcji. Na podstawie typu zdarzenia odpowiednio reagujemy
- w przypadku dodawania nowego elementu - dodajemy go do naszego StackPanel-u za pomocą właściwości Children
- w przypadku usuwania - usuwamy odpowiedni element ze StackPanel-u
3. Metoda CreateRegion:
Code:
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
Zwracamy informację że wszystkie elementy dodane do naszego StackPanel-a będą domyślne aktywne.
4. Dodanie konstruktora do tworzonej klasy StackPanelRegionAdapter
Code:
public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
: base(regionBehaviorFactory)
{
}
Nasza klasa wymaga jeszcze konstruktora - dodajemy go więc.
Całość przedstawia się następująco:
Code:
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Regions;
namespace WpfApplication1
{
public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
{
public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
: base(regionBehaviorFactory)
{
}
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (FrameworkElement item in e.NewItems)
{
regionTarget.Children.Add(item);
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (FrameworkElement item in e.NewItems)
{
if (regionTarget.Children.Contains(item))
{
regionTarget.Children.Remove(item);
}
}
}
};
}
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}
}
Tak więc pierwsza część za nami zostało tylko zarejestrowanie naszego adaptera w Bootstrapperze co przedstawia się następująco:
Code:
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Unity;
namespace WpfApplication1
{
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow = (Shell)Shell;
Application.Current.MainWindow.Show();
}
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
var mappings = new RegionAdapterMappings();
mappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());
return mappings;
}
}
}
Za pomocą metody ConfigureRegionAdapterMappings dodajemy informację o naszym Adapterze StackPanel.
Brak komentarzy:
Prześlij komentarz