我对wpf比较新,所以我提前为任何糟糕的编码做法道歉。
我试图创建一个仪表板应用程序,用户可以通过添加不同的控件(表格,图形等)来定制它们并移动它们/调整它们的大小。
我最初使用Canvas来绘制我的控件并进行移动和调整大小的工作。由于需要内容是动态的,我转而使用如下的ItemsControl:
<ItemsControl Name="dashboardCanvas" ItemsSource="{Binding Path=CanvasContents}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type local:MoveThumb}">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="Control">
<Grid>
<local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 -4 0 0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="2" Cursor="SizeWE" Margin="-4 0 0 0" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="2" Cursor="SizeWE" Margin="0 0 -4 0" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 0 0 -4" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="DesignerItemTemplate">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
<Control Template="{StaticResource ResizeDecoratorTemplate}"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
<Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
</Grid>
</ControlTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
<Control Template="{StaticResource ResizeDecoratorTemplate}"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
<Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
<Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
我现在遇到一个问题,即我添加到ItemsControl的任何控件都没有应用模板。
我已经看到了这个问题:Why Does ItemsControl Not Use My ItemTemplate? 但我无法将ItemsControl继承到我的控件中,因为它们已经从ContentControls继承。
这是我的主要控制对象:
class TableControl: DashboardItem
{
public TableControl()
{
Width = 100;
Height = 100;
Content = new Ellipse
{
Fill = new SolidColorBrush(Colors.Green),
IsHitTestVisible = false
};
}
public int X
{
get
{
return 10;
}
}
public int Y
{
get
{
return 200;
}
}
}
DashboardItem目前只是:
class DashboardItem : ContentControl
{
}
在后面的代码中,我有一个DashboardItems的ObservableCollection,ItemsControl绑定了它。
如何强制将ItemsControl模板应用于控件中的所有项目?
答案 0 :(得分:1)
Blinx,
我尝试了你的代码,发现了这个错误。
您的代码中存在奇怪的混合。
您的ObservableCollection
ContentControl
不得为DashboardItems
。
使您的对象ContentControl
,真实业务对象(或viewmodel对象)可能持有X和Y属性,但没有typecast
的继承。
如果您提供GUI对象,似乎WPF不关心您的模板。
如果您需要为Items Control的不同项目提供不同的外观,那么您将能够使用
-a TemplateSelector(用于为给定行选择模板)
- 或DataItemTemplate的DataType属性
答案 1 :(得分:0)
只需添加另一个解决方案。正如公认的答案所指出的,如果直接使用ItemsControl
,则传入的任何GUI对象都将按原样排列在ItemsPanel
上,从而完全绕开DataTemplate
。 (如果不是GUI对象,则首先将其包装在ContentPresenter
中。)
要解决此问题,可以创建ItemsControl
的子类,您必须强制始终为项目创建一个容器。您可以通过将false
返回IsItemItsOwnContainerOverride
来完成此操作。这告诉控件该项目必须先包装在容器中-再次,在ItemsControl
的默认实现中,它是一个简单的ContentPresenter
–因此它将始终应用任何给定的ItemTemplate
。
这是代码...
public class EnsureContainerItemsControl : ItemsControl {
protected override bool IsItemItsOwnContainerOverride(object item) {
return false; // Force the control to always generate a container regardless of what was passed in
}
}