Заставьте вложенные свойства работать внутри DataTemplate
Я получил ItemsControl
который использует Canvas
как ItemsPanel
и его элементы отображаются в различных формах WPF в зависимости от типа привязки, в основном так:
<ItemsControl ItemsSource="{Binding PreviewShapes}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:UiPreviewLineViewModel}">
<Line X1="{Binding Start.X}" Y1="{Binding Start.Y}"
X2="{Binding End.X}" Y2="{Binding End.Y}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Line" ToolTip="{Binding Text}">
</Line>
</DataTemplate>
<DataTemplate DataType="{x:Type local:UiPreviewEllipsisViewModel}">
<Ellipse Canvas.Left="{Binding UpperLeft.X" Canvas.Top="{Binding UpperLeft.Y}"
Width="{Binding Width}" Height="{Binding Height}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Ellipse" ToolTip="{Binding Text}">
</Ellipse>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="SketchCanvas" ClipToBounds="False">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Поэтому я в основном добавляю объекты в PreviewShapes
модели представления и в зависимости от типа они отображаются в WPF Line
с или Ellipse
s. Это в основном работает, но прикрепленные свойства Canvas.Left
а также Canvas.Top
игнорируются даже при использовании статических значений.
Также VS или ReSharper уведомляет меня, что присоединенное свойство не имеет никакого эффекта в текущем контексте.
Как я могу расположить Ellipse
на холсте без использования прикрепленных свойств? Или какое другое решение было бы уместным?
2 ответа
К сожалению, никто не хотел публиковать ответ.
Во-первых, полезны ссылки Клеменса. Предметы будут внутри ContentPresenter
что является причиной, почему установка Canvas.Left/Top
на Ellipsis
не работает.
Решение 1
Добавив стиль в контейнер элементов, можно установить привязки для позиции:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding UpperLeft.X}" />
<Setter Property="Canvas.Top" Value="{Binding UpperLeft.Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
Это работает, но DataTemplate
размещение <Line>
будет выдавать обязательные предупреждения, потому что эта модель представления не имеет свойства UpperLeft
, Тем не менее, это работает для многоточия и линии размещены их X1
, Y1
, X2
а также Y2
ценности.
Решение 2
Если вы хотите использовать более детальный подход к управлению, вы можете установить Canvas
свойства к ContentPresenter
проксируя их с пользовательским поведением / прикрепленным свойством. Давайте назовем его CanvasPointProxyBehavior, вы можете использовать его для Ellipse
как это:
<DataTemplate DataType="{x:Type local:UiPreviewEllipsisViewModel}">
<Ellipse behaviors:CanvasPointProxyBehavior.Point="{Binding UpperLeft}"
Width="{Binding Width}" Height="{Binding Height}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Ellipse" ToolTip="{Binding Text}">
</Ellipse>
</DataTemplate>
Line
не понадобится Код для этого присоединенного свойства может выглядеть следующим образом:
public class CanvasPointProxyBehavior
{
public static readonly DependencyProperty PointProperty = DependencyProperty.RegisterAttached("Point", typeof(Point), typeof(CanvasPointProxyBehavior), new UIPropertyMetadata(null, PointChangedCallback));
public static void SetPoint(DependencyObject depObj, Point point)
{
depObj.SetValue(PointProperty, point);
}
public static Point GetPoint(DependencyObject depObj)
{
return depObj.GetValue(PointProperty) as Point;
}
private static void PointChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
UIElement uiElement = (dependencyObject as UIElement);
if (uiElement == null) return;
UIElement elementToBePositioned = uiElement;
var visualParent = VisualTreeHelper.GetParent(uiElement);
if (visualParent is ContentPresenter)
{
elementToBePositioned = visualParent as ContentPresenter;
}
var point = e.NewValue as Point;
if (point != null)
{
Canvas.SetLeft(elementToBePositioned, point.X);
Canvas.SetTop(elementToBePositioned, point.Y);
}
}
}
Надеясь, кто-то найдет одно или оба решения полезными.
Обратите внимание, что я столкнулся с тем же предупреждением ReSharper, что и ZoolWay, но в моем случае это было в сетке данных, где я хотел, чтобы кнопка справа была выровнена по правому краю, а не по левому краю:
Параметр вложенного свойства "Grid.Column" не действует в текущем контексте и может быть удален.
Вот код, где у меня было предупреждение, на Button Grid.Column="2"
:
<Border VerticalAlignment="Center" Style="{DynamicResource InspectionsCustomDataGridHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Label Name="InspectionsDataGridTitle" Background="White" Content="{Binding InspectionsCollectionView.View.Count, ConverterParameter={x:Static resx:Resources.InspectionsDataGridTitle}, Converter={StaticResource DataGridHeaderCountConverter}}" Style="{DynamicResource InspectionsCustomDataGridHeaderLabel}" MouseDown="InspectionsDataGridTitle_MouseDown" />
<!-- more labels, etc... -->
<Button Grid.Column="2" Width="30" Height="30" Margin="0,0,10,0" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" Command="{Binding CreatePDFCommand,Mode=OneWay}" >
<StackPanel Orientation="Horizontal" Background="Transparent">
<Image Width="30" Height="30" Source="/Inspections;component/Icons/pdf_btn.png" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Border>
Вот как я исправил предупреждение, куда я переместил кнопку под первым StackPanel
:
<Border VerticalAlignment="Center" Style="{DynamicResource InspectionsCustomDataGridHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Label Name="InspectionsDataGridTitle" Background="White" Content="{Binding InspectionsCollectionView.View.Count, ConverterParameter={x:Static resx:Resources.InspectionsDataGridTitle}, Converter={StaticResource DataGridHeaderCountConverter}}" Style="{DynamicResource InspectionsCustomDataGridHeaderLabel}" MouseDown="InspectionsDataGridTitle_MouseDown" />
<!-- more labels, etc... -->
</StackPanel>
<Button Grid.Column="2" Width="30" Height="30" Margin="0,0,10,0" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" Command="{Binding CreatePDFCommand,Mode=OneWay}" >
<StackPanel Orientation="Horizontal" Background="Transparent">
<Image Width="30" Height="30" Source="/Inspections;component/Icons/pdf_btn.png" />
</StackPanel>
</Button>
</Grid>
</Border>
НТН