【发布时间】:2017-03-24 20:53:58
【问题描述】:
我的目标是在 UWP 应用程序中显示一个简单的Graph。该图包含顶点和边的列表。 Vertex 有一个绝对位置,应该相应地显示在视图中。 Edge 包含两个顶点,应表示为一个顶点与另一个顶点之间的简单线。此外,如果这些 GraphItem(顶点和边)在视图中是可选的,那也很好。
到目前为止,我已经尝试使用 ListBox 并将其 ItemsPanel 设置为 Canvas,以便可以选择项目。我创建了自己的GraphDataTemplateSelector,它继承自DataTemplateSelector,用于选择是绘制顶点还是绘制边。我的 ViewModel 将图形作为对象的 ObservableCollection 返回,该对象用作 ListBox 的 ItemsSource。我尝试使用ItemContainerStyle 定位元素并绑定Canvas.Left 和Canvas.Top 属性。但是根据这个post,UWP 不支持Setter.Value 的绑定,所以我使用了同一篇文章中描述的RenderTransform 的解决方法。
这种方法的问题是元素的选择矩形总是停留在画布的左上角。据我了解,如果我选择 Canvas 作为视图的 ItemsPanel,它的子项将显示在 ContentPresenter 中。我的猜测是,这是因为 RenderTransform 仅应用于 DataTemplate 而不是 ContentPresenter 本身。
我现在的问题是如何解决这个问题,以便选择矩形与元素一起移动?也许这不是实现这一目标的最佳方式,并且有更好的解决方案?感谢您的时间和帮助!
我的 XAML 代码:
<Page.Resources>
<DataTemplate x:DataType="models:VertexModel" x:Key="VertexTemplate">
<StackPanel>
<StackPanel.RenderTransform>
<TranslateTransform X="{x:Bind Position.X}" Y="{x:Bind Position.Y}"/>
</StackPanel.RenderTransform>
<Ellipse Fill="Red" Height="40" Width="40" StrokeThickness="2" Stroke="Black"/>
<TextBlock Text="{x:Bind Name}" HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="models:EdgeModel" x:Key="EdgeTemplate">
<Line X1="{x:Bind StartVertex.Position.X}"
Y1="{x:Bind StartVertex.Position.Y}"
X2="{x:Bind EndVertex.Position.X}"
Y2="{x:Bind EndVertex.Position.Y}"
Stroke="DarkGreen" StrokeThickness="2"/>
</DataTemplate>
<templateSelector:GraphDataTemplateSelector x:Key="GraphDataTemplateSelector"
VertexTemplate="{StaticResource VertexTemplate}"
EdgeTemplate="{StaticResource EdgeTemplate}"/>
</Page.Resources>
<ListBox ItemsSource="{Binding Graph}"
ItemTemplateSelector="{StaticResource GraphDataTemplateSelector}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
我的 GraphDataTemplateSelector:
public class GraphDataTemplateSelector : DataTemplateSelector
{
public DataTemplate VertexTemplate { get; set; }
public DataTemplate EdgeTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is VertexModel)
return VertexTemplate;
if (item is EdgeModel)
return EdgeTemplate;
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
【问题讨论】: