我的视频控件布局很少(不同的DataTemplates)。创建此视频控件的时间非常长。我想在不同的DataTemplates中重用此视频控件的实例。
Codebehind和ViewModel:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Layout1 = (DataTemplate)this.FindResource("_layout1");
Layout2 = (DataTemplate)this.FindResource("_layout2");
DataContext = new ViewModel {Content1 = "Content1", Content2 = "Content2"};
}
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; }
}
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>
<DataTemplate x:Key="_layout1" DataType="{x:Type model:ViewModel}">
<StackPanel>
<Button Content="{Binding Content1}"/>
<Button Content="{Binding Content2}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="_layout2" DataType="{x:Type model:ViewModel}">
<StackPanel Orientation="Horizontal">
<Button Content="{Binding Content1}"/>
<Button Content="{Binding Content2}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Change</Button>
<ContentPresenter Name="_view" Content="{Binding}" ContentTemplate="{StaticResource _layout1}"/>
</StackPanel>
如何重复使用按钮并阻止在每个模板更改时创建新按钮?
已编辑:在Button_click上使用datatemplates _layout1和_layout2之间切换。只有一个模板有效。我不想在两个地方绘制一个控件实例。我希望在激活时禁止在其他模板中创建控件(之前已停用)。 或者我可以使用另一种方法,没有datatemplates?风格,资源,触发器?
答案 0 :(得分:3)
ControlsPoolControl<T>
IControlsPool<T>
<强> 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>();
}
}
<强>代码隐藏强>
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>
答案 1 :(得分:0)
你做不到。 FrameworkElement
和FrameworkContentElement
个实例只能添加到逻辑树的一个点。如果您尝试将此类对象的相同实例添加到两个不同的位置,则会出现例外情况:
Element已经有一个逻辑父级。 它必须脱离旧的 父级在附加到新的之前 之一。