【问题标题】:Display Graph with Vertices and Edges in UWP在 UWP 中显示带有顶点和边的图形
【发布时间】:2017-03-24 20:53:58
【问题描述】:

我的目标是在 UWP 应用程序中显示一个简单的Graph。该图包含顶点和边的列表。 Vertex 有一个绝对位置,应该相应地显示在视图中。 Edge 包含两个顶点,应表示为一个顶点与另一个顶点之间的简单线。此外,如果这些 GraphItem(顶点和边)在视图中是可选的,那也很好。

到目前为止,我已经尝试使用 ListBox 并将其 ItemsPanel 设置为 Canvas,以便可以选择项目。我创建了自己的GraphDataTemplateSelector,它继承自DataTemplateSelector,用于选择是绘制顶点还是绘制边。我的 ViewModel 将图形作为对象的 ObservableCollection 返回,该对象用作 ListBox 的 ItemsSource。我尝试使用ItemContainerStyle 定位元素并绑定Canvas.LeftCanvas.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);
    }
}

【问题讨论】:

    标签: c# xaml uwp


    【解决方案1】:

    我现在的问题是如何解决这个问题,以便选择矩形随着元素一起移动

    选择矩形实际上是BorderBackground 矩形,默认位于ListViewItem control template 内。 您在DateTemplate 中定义的转换仅适用于控件模板的ContentPresenter,不适用于BorderBackground 矩形。因此,您可能需要为ListView 定义一个新的ListViewItem 样式,并使用position 数据为BorderBackground 矩形设置变换。

    如您所知,您可能无法将数据绑定到setter.value,但您应该能够将数据绑定到使用Binding 的控件模板内的元素。代码示例如下,在页面资源中定义新样式:

    <Page.Resources>
    ...
     <Style x:Key="ListViewItemExpanded" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Grid
                            x:Name="ContentBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">                     
                            <Rectangle
                                x:Name="BorderBackground"
                                Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}"
                                Opacity="0"
                                Control.IsTemplateFocusTarget="True"
                                IsHitTestVisible="False">
                                <Rectangle.RenderTransform>
                                    <TranslateTransform X="{Binding Position.X}" Y="{Binding Position.Y}" />
                                </Rectangle.RenderTransform>
                            </Rectangle>
                            <Grid
                                x:Name="ContentPresenterGrid"
                                Margin="0,0,0,0"
                                Background="Transparent">
                                <Grid.RenderTransform>
                                    <TranslateTransform x:Name="ContentPresenterTranslateTransform" />
                                </Grid.RenderTransform>
                                <ContentPresenter
                                    x:Name="ContentPresenter"
                                    Margin="{TemplateBinding Padding}"
                                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                    Content="{TemplateBinding Content}"
                                    ContentTemplate="{TemplateBinding ContentTemplate}"
                                    ContentTransitions="{TemplateBinding ContentTransitions}" />
    
                            </Grid> 
                            <TextBlock
                                x:Name="PlaceholderTextBlock"
                                Margin="{TemplateBinding Padding}"
                                Foreground="{x:Null}"
                                Opacity="0"
                                AutomationProperties.AccessibilityView="Raw"
                                IsHitTestVisible="False"
                                Text="Xg" />
                            <Rectangle
                                x:Name="PlaceholderRect"
                                Fill="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"
                                Visibility="Collapsed" />
                            <Rectangle
                                x:Name="MultiArrangeOverlayBackground"
                                Grid.ColumnSpan="2"
                                Fill="{ThemeResource ListViewItemDragBackgroundThemeBrush}"
                                Opacity="0"
                                IsHitTestVisible="False" />
                            <Border
                                x:Name="MultiSelectSquare"
                                Width="20"
                                Height="20"
                                Margin="12,0,0,0"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Center"
                                BorderBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                                BorderThickness="2"
                                Visibility="Collapsed">
                                <Border.Clip>
                                    <RectangleGeometry Rect="0,0,20,20">
                                        <RectangleGeometry.Transform>
                                            <TranslateTransform x:Name="MultiSelectClipTransform" />
                                        </RectangleGeometry.Transform>
                                    </RectangleGeometry>
                                </Border.Clip>
                                <Border.RenderTransform>
                                    <TranslateTransform x:Name="MultiSelectCheckBoxTransform" />
                                </Border.RenderTransform>
                                <FontIcon
                                    x:Name="MultiSelectCheck"
                                    Foreground="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                                    Opacity="0"
                                    FontFamily="{ThemeResource SymbolThemeFontFamily}"
                                    FontSize="16"
                                    Glyph="&#xE73E;"
                                    Visibility="Collapsed" />
                            </Border>
                            <TextBlock
                                x:Name="MultiArrangeOverlayText"
                                Grid.ColumnSpan="2"
                                Margin="18,9,0,0"
                                Foreground="{ThemeResource ListViewItemDragForegroundThemeBrush}"
                                Opacity="0"
                                FontFamily="{ThemeResource ContentControlThemeFontFamily}"
                                FontSize="26.667"
                                AutomationProperties.AccessibilityView="Raw"
                                IsHitTestVisible="False"
                                Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DragItemsCount}"
                                TextTrimming="WordEllipsis"
                                TextWrapping="Wrap" />
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="BorderBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="BorderBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerDownThemeAnimation TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Selected">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0:0:0"
                                                Storyboard.TargetName="MultiSelectCheck"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="BorderBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentLowBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PointerOverSelected">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0:0:0"
                                                Storyboard.TargetName="MultiSelectCheck"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="BorderBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentMediumBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PressedSelected">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0:0:0"
                                                Storyboard.TargetName="MultiSelectCheck"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="BorderBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerDownThemeAnimation TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DisabledStates">
                                    <VisualState x:Name="Enabled" />
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="ContentBorder"
                                                Storyboard.TargetProperty="Opacity"
                                                To="{ThemeResource ListViewItemDisabledThemeOpacity}" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>                                
                                ...
                                <VisualStateGroup x:Name="DataVirtualizationStates">
                                    <VisualState x:Name="DataAvailable" />
                                    <VisualState x:Name="DataPlaceholder">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderRect" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="ReorderHintStates">
                                    <VisualState x:Name="NoReorderHint" />
                                    <VisualState x:Name="BottomReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation
                                                Direction="Bottom"
                                                ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                                                TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="TopReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation
                                                Direction="Top"
                                                ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                                                TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="RightReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation
                                                Direction="Right"
                                                ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                                                TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="LeftReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation
                                                Direction="Left"
                                                ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                                                TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:0.2" To="NoReorderHint" />
                                    </VisualStateGroup.Transitions>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DragStates">
                                    <VisualState x:Name="NotDragging" />
                                    <VisualState x:Name="Dragging">
                                        <Storyboard>
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="ContentBorder"
                                                Storyboard.TargetProperty="Opacity"
                                                To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                            <DragItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="DraggingTarget">
                                        <Storyboard>
                                            <DropTargetItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MultipleDraggingPrimary">
                                        <Storyboard>                                           
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="MultiArrangeOverlayBackground"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="MultiArrangeOverlayText"
                                                Storyboard.TargetProperty="Opacity"
                                                To="1" />
                                            <DoubleAnimation
                                                Duration="0"
                                                Storyboard.TargetName="ContentBorder"
                                                Storyboard.TargetProperty="Opacity"
                                                To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                            <FadeInThemeAnimation TargetName="MultiArrangeOverlayBackground" />
                                            <FadeInThemeAnimation TargetName="MultiArrangeOverlayText" />
                                            <DragItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MultipleDraggingSecondary">
                                        <Storyboard>
                                            <FadeOutThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="DraggedPlaceholder">
                                        <Storyboard>
                                            <FadeOutThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:0.2" To="NotDragging" />
                                    </VisualStateGroup.Transitions>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>   
    </Page.Resources> 
    

    并将样式设置为ListViewItem

    <ListView
        ItemContainerStyle="{StaticResource ListViewItemExpanded}"
        ItemTemplateSelector="{StaticResource GraphDataTemplateSelector}"
        ItemsSource="{x:Bind Graph1}">
        <ListView.ItemsPanel>
    ...
    </ListView>
    

    结果:

    您应该可以只将变换设置为ContentBorder 元素,在这种情况下,您将不会再次在Datetemplate 中设置变换。

    【讨论】:

    • 感谢您的回答。这个解决方案非常有效,因为我将RenderTransform 应用于基本网格而不是BorderBackground Rectangle。通过此更改,它完全可以完成它需要做的事情。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多