Пул управления
ControlsPoolControl<T>
IControlsPool<T>
- T - тип многоразового контроля.
- IControlsPool - используется для хранения
многоразовые экземпляры управления ключом
объект (некоторое свойство viewmodel)
- ControlsPoolControl - Контейнер,
которые восстанавливают внутренний контроль
IControlsPool с помощью связанного ключа.
Осуществление
ControlsPoolControl
public class ControlsPoolControl<T> : UserControl where T : UIElement
{
private readonly Panel _mainPanel;
private T _innerControl;
public ControlsPoolControl()
{
_mainPanel = new Grid();
Content = _mainPanel;
}
#region Properties
#region DependencyProperty
public static readonly DependencyProperty KeyObjectProperty = DependencyProperty.Register("KeyObject", typeof(object), typeof(ControlsPoolControl<T>), new PropertyMetadata(null, KeyObjectChanged));
public static readonly DependencyProperty PoolProperty = DependencyProperty.Register("Pool", typeof(IControlsPool<T>), typeof(ControlsPoolControl<T>), new PropertyMetadata(null, PoolChanged));
#endregion
public object KeyObject
{
get { return GetValue(KeyObjectProperty); }
set { SetValue(KeyObjectProperty, value); }
}
public IControlsPool<T> Pool
{
get { return (IControlsPool<T>)GetValue(PoolProperty); }
set { SetValue(PoolProperty, value); }
}
protected T InnerControl
{
get { return _innerControl; }
set
{
if (_innerControl == value)
return;
_innerControl = value;
OnControlChanged();
}
}
#endregion
#region Private API
void Clear()
{
_mainPanel.Children.Clear();
}
void OnKeyObjectChanged()
{
UpdateControl();
}
void OnControlChanged()
{
VerifyAccess();
Clear();
var ctrl = InnerControl;
if (ctrl != null)
_mainPanel.Children.Add(ctrl);
}
private void UpdateControl()
{
if (KeyObject == null || Pool == null)
InnerControl = null;
else
InnerControl = Pool.Get(KeyObject);
}
private static void KeyObjectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ControlsPoolControl<T>)d).OnKeyObjectChanged();
}
private static void PoolChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ControlsPoolControl<T>)d).UpdateControl();
}
#endregion
}
ControlsPool
public interface IControlsPool<T> where T : UIElement
{
void Add(object key, T control);
T Get(object key);
}
public class ControlsPool<T> : IControlsPool<T> where T : UIElement
{
readonly IDictionary<object, T> _controls = new Dictionary<object, T>();
public void Add(object key, T control)
{
if (key == null) throw new ArgumentNullException("key");
if (_controls.ContainsKey(key)) return;
_controls.Add(key, control);
}
public T Get(object key)
{
if (key == null) throw new ArgumentNullException("key");
T control = null;
if (!_controls.TryGetValue(key, out control))
{
control = CreateInstance(key);
_controls.Add(key, control);
}
return control;
}
protected virtual T CreateInstance(object key)
{
return Activator.CreateInstance<T>();
}
}
Использование
Codebehind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ContentControlType = typeof(MyButton);
Layout1 = (DataTemplate)FindResource("_layout1");
Layout2 = (DataTemplate)FindResource("_layout2");
DataContext = new ViewModel { Content1 = "Content1", Content2 = "Content2" };
}
public Type ContentControlType { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
_view.ContentTemplate = _view.ContentTemplate == Layout1 ? Layout2 : Layout1;
}
DataTemplate Layout1;
DataTemplate Layout2;
}
public class ViewModel
{
public string Content1 { get; set; }
public string Content2 { get; set; }
}
public class ButtonsPool : ControlsPool<MyButton> { }
public class ButtonPoolControl : ControlsPoolControl<MyButton>
{
}
public class MyButton : Button
{
static int _counter = 0;
public MyButton()
{
_counter++;
}
}
XAML
Чтобы инициализировать повторно используемый элемент управления, вы должны использовать стиль.
<Window Name="_mainForm" x:Class="WpfVideo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:WpfVideo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<model:ButtonsPool x:Key="_buttonsPool"/>
<DataTemplate x:Key="_layout1" DataType="{x:Type model:ViewModel}">
<StackPanel>
<model:ButtonPoolControl KeyObject="{Binding Content1}" Pool="{StaticResource _buttonsPool}">
<model:ButtonPoolControl.Resources>
<Style TargetType="model:MyButton">
<Setter Property="Content" Value="{Binding Content1}"/>
</Style>
</model:ButtonPoolControl.Resources>
</model:ButtonPoolControl>
<model:ButtonPoolControl KeyObject="{Binding Content2}" Pool="{StaticResource _buttonsPool}">
<model:ButtonPoolControl.Resources>
<Style TargetType="model:MyButton">
<Setter Property="Content" Value="{Binding Content2}"/>
</Style>
</model:ButtonPoolControl.Resources>
</model:ButtonPoolControl>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="_layout2" DataType="{x:Type model:ViewModel}">
<StackPanel Orientation="Horizontal">
<model:ButtonPoolControl Pool="{StaticResource _buttonsPool}" KeyObject="{Binding Content1}">
<model:ButtonPoolControl.Resources>
<Style TargetType="model:MyButton">
<Setter Property="Content" Value="{Binding Content1}"/>
</Style>
</model:ButtonPoolControl.Resources>
</model:ButtonPoolControl>
<model:ButtonPoolControl Pool="{StaticResource _buttonsPool}" KeyObject="{Binding Content2}">
<model:ButtonPoolControl.Resources>
<Style TargetType="model:MyButton">
<Setter Property="Content" Value="{Binding Content2}"/>
</Style>
</model:ButtonPoolControl.Resources>
</model:ButtonPoolControl>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Change</Button>
<ContentPresenter Name="_view" Content="{Binding}" ContentTemplate="{StaticResource _layout1}"/>
</StackPanel>