代码之家  ›  专栏  ›  技术社区  ›  Mauro Sampietro

谷歌图片,如带有细节面板的列表框

  •  2
  • Mauro Sampietro  · 技术社区  · 6 年前

    你如何设计一个像谷歌图片一样的组件?

    我不知道如何处理选中时每个图像下显示的细节面板。

    细节面板:
    -在两行图像之间显示。
    -保持左右物品就位。

    解决方案:

    多亏了 littlebit 为问题提供了非常好的解决方案。根据他的提示,我创建了下面的通用组件,它负责处理一些在使 littlebit solution production ready时最终会遇到的细节。

    文件:detailedlist.cs

    public class detailedlist:listbox
    {
    #区域详细信息模板
    公共数据模板详细信息模板
    {
    get返回(datatemplate)getvalue(detailstemplateproperty);
    设置setValue(detailTemplateProperty,value);
    }
    
    公共静态只读DependencyProperty DetailsTemplateProperty=
    DependencyProperty.Register(名称为(DetailsTemplate)、类型为(DataTemplate)、类型为(DetailedList));
    γ端区
    
    静态详细列表()
    {
    类型所有者类型=类型(详细列表);
    
    DefaultStyleKeyProperty.OverrideMetadata(所有者类型,
    新框架工作属性元数据(ownerType));
    
    StyleProperty.OverrideMetadata(所有者类型,
    新框架工作属性元数据(空,(depobj,basevalue)=>
    {
    var元素=作为框架元素的depbj;
    如果(元素)!=空&basevalue==空)
    baseValue=element.tryfindResource(ownerType);
    
    返回基值;
    (})
    }
    }
    < /代码> 
    
    

    文件:StretchGrid.cs

    内部类StretchGrid:grid
    {
    专用扩展器;
    
    #区域父面板
    公共面板父面板
    {
    get返回(panel)this.getValue(parentpanelproperty);
    设置this.set value(parentpanelproperty,value);
    }
    
    public static readonly dependencyproperty parentpanelproperty=dependencyproperty.register(
    name of(parentpanel)、typeof(panel)、typeof(strenggrid)、new propertymetadata(空,parentpanelchanged));
    
    private static void parentpanelchanged(dependencyObject d,dependencyPropertiesChangedEventArgs e)
    {
    var StretchGrid=d作为StretchGrid;
    if(StretchGrid==null)返回;
    
    if(e.newValue是面板面板)
    panel.sizeChanged+=拉伸网格.updateMargins;
    }
    γ端区
    
    公共拉伸网格()
    {
    this.loaded+=拉伸网格加载;
    }
    
    加载了专用的void StretchGrid(对象发送器,routedeventargs e)
    {
    _ expander=this.findLogicalParent<expander>();
    
    _ expander.expanded+=更新页边距;
    _ expander.sizechanged+=更新页边距;
    
    this.updateMargins(空,空);
    }
    
    private void updateMargins(对象发送方,routedeventargs e)
    {
    if(parentpanel==null)返回;
    if(_expander==null)返回;
    
    point delta=_expander.translatePoint(新点(0d,0d),父面板);
    
    //创建负边距以允许在边界之外呈现网格(项下的整行)
    this.margin=新厚度(-delta.x,0,delta.x+_expander.actualwidth-parentpanel.actualwidth,0);
    }
    }
    < /代码> 
    
    

    文件:detailedlist.xaml

    <style x:key=“x:type cc:detailedlist”targetType=“x:type cc:detailedlist”
    basedon=“staticresource x:类型列表框”>
    
    <style.resources>
    <资源字典>
    <resourceDictionary.mergedDictionaries>
    <resourceDictionary source=“nobuttonexpander.xaml”/>
    </resourcedictionary.mergeddictionaries>
    </resourcedictionary>
    </style.resources>
    
    <setter property=“grid.isSharedSizeScope”value=“true”/>
    <setter property=“scrollviewer.horizontalscrollbarvisibility”value=“disabled”/>gt;
    <setter property=“selectionmode”value=“single”/>
    
    <setter property=“itemspanel”>
    <setter.value>
    <项模板lt;itemspaneltemplate>
    <wrappanel width=“绑定实际宽度,relativesource=relativesource ancestortype=x:type cc:detailedlist”
    tag=“绑定relativesource=relativesource self”/>gt;
    </itemspaneltemplate>
    </setter.value>
    &;
    
    <setter property=“itemcontainerStyle”>
    <setter.value>
    <style targettype=“x:type listbox项目”>
    <setter property=“focusVisualStyle”value=“x:null”/>gt;
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:类型列表框项”>
    
    <border name=“border”snapstodevicepexels=“true”>
    <expander style=“staticresource nobuttonexpander”verticalaligning=“top”
    isexpanded=“binding isselected,relativesource=relativesource ancestortype=x:类型列表框项”
    width=“绑定实际宽度,relativesource=relativesource ancestortype=x:类型列表框项”>
    
    <expander.header>
    格栅& GT;
    <grid.rowdefinitions>
    <rowdefinition sharedsizegroup=“a”/>
    </grid.rowdefinitions>
    
    <contentPresenter grid.row=“0”/>
    和/格栅& GT;
    </expander.header>
    
    <cc:StretchGrid ParentWrappanel=“绑定路径=标记,
    relativesource=relativesource ancestortype=x:type wrappanel“>
    
    <ContentPresenter ContentTemplate=“绑定详细信息模板,
    relativesource=relativesource ancestortype=x:type cc:detailedlist“/>
    
    </cc:StretchGrid>
    </expander>
    &边界/gt;
    
    <controlTemplate.triggers>
    <trigger property=“isselected”value=“true”>
    <setter targetname=“border”property=“background”
    value=“动态源x:静态系统颜色。highlightbrushkey”/>gt;
    </trigger>
    </controltemplate.triggers>
    
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    </setter.value>
    &;
    &风格/风格;
    < /代码> 
    
    

    文件:nobuttonexpander.xaml

    <style x:key=“expanderRightHeaderStyle”targetType=“x:type toggleButton”>
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:type toggleButton”>
    <border padding=“模板绑定padding”>
    <grid background=“transparent”snapstodevicepexels=“false”>
    <contentPresenter horizontalligence=“center”margin=“0,4,0,0”grid.row=“1”recognizesacesskey=“true”snapstodevicepexels=“true”verticalaligence=“top”/>
    和/格栅& GT;
    &边界/gt;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    
    <style x:key=“expanderUpheaderStyle”targetType=“x:type toggleButton”>
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:type toggleButton”>
    <border padding=“模板绑定padding”>
    <grid background=“transparent”snapstodevicepexels=“false”>
    <contentPresenter grid.column=“1”horizontallight=“left”margin=“4,0,0,0”recognizesacesskey=“true”snapstodevicepexels=“true”verticalaligning=“center”/>
    和/格栅& GT;
    &边界/gt;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    
    <style x:key=“expanderLeftTheaderStyle”targetType=“x:type ToggleButton”>
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:type toggleButton”>
    <border padding=“模板绑定padding”>
    <grid background=“transparent”snapstodevicepexels=“false”>
    <contentPresenter horizontalligence=“center”margin=“0,4,0,0”grid.row=“1”recognizesacesskey=“true”snapstodevicepexels=“true”verticalaligence=“top”/>
    和/格栅& GT;
    &边界/gt;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    
    <style x:key=“expanderHeaderFocusVisual”>
    <setter property=“control.template”>
    <setter.value>
    <控制模板>
    边境;
    <rectangle margin=“0”snapstodevicepexels=“true”stroke=“black”strokethickness=“1”strokedasarray=“1 2”/>gt;
    &边界/gt;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    
    <style x:key=“expanderDownheaderStyle”targetType=“x:type toggleButton”>
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:type toggleButton”>
    <border padding=“模板绑定padding”>
    <grid background=“transparent”snapstodevicepexels=“false”>
    <contentPresenter grid.column=“1”horizontallight=“left”margin=“4,0,0,0”recognizesacesskey=“true”snapstodevicepexels=“true”verticalaligning=“center”/>
    和/格栅& GT;
    &边界/gt;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    
    <style x:key=“nobuttonexpander”targetType=“x:type expander”>
    <setter property=“foreground”value=“dynamicResource x:static systemcolors.controlTextBrushKey”/>gt;
    <setter property=“background”value=“transparent”/>
    <setter property=“HorizontalContentAlignment”value=“Stretch”/>
    <setter property=“VerticalContentAlignment”value=“Stretch”/>
    <setter property=“borderbrush”value=“transparent”/>
    <setter property=“borderthickness”value=“1”/>
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:type expander”>
    <border borderbrush=“templatebinding borderbrush”borderthickness=“templatebinding borderthickness”background=“templatebinding background”cornerradius=“3”snapstodevicepexiles=“true”>
    <dockpanel>
    <toggleButton x:name=“headerSite”contentTemplate=“templateBinding headerTemplate”contentTemplateSelector=“templateBinding headerTemplateSelector”content=“templateBinding header”dockPanel.dock=“top”foreground=“templateBinding foreground”fontweight=“templateBinding fontweight”focusVisualStyle=“staticResource expanderHeaderFocusvisual fontstyle=“templateBinding fontstyle”fontStretch=“templateBinding fontStretch”fontsize=“templateBinding fontSize”fontFamily=“templateBinding fontFamily”horizontalContentAlignment=“templateBinding horizontalContentAlignment”isChecked=“binding isExpanded,mode=twoway,relativesource=relativesource templatedParent”margin=“1“minwidth=“0”minheight=“0”padding=“templateBinding padding”style=“staticResource expanderDownheaderStyle”verticalContentAlignment=“templateBinding verticalContentAlignment”/>gt;
    <contentPresenter x:name=“expandsite”dockpanel.dock=“bottom”focusable=“false”horizontallight=“templateBinding horizontalContentAlignment”margin=“templateBinding padding”visibility=“colled”verticalAlignment=“templateBinding verticalContentAlignment”/>gt;
    </dockpanel>
    &边界/gt;
    <controlTemplate.triggers>
    <trigger property=“isexpanded”value=“true”>
    <setter property=“visibility”targetname=“expandsite”value=“visible”/>
    </trigger>
    <trigger property=“expandDirection”value=“right”>
    <setter property=“dockpanel.dock”targetname=“expandsite”value=“right”/>
    <setter property=“dockpanel.dock”targetname=“headersite”value=“left”/>gt;
    <setter property=“style”targetname=“headersite”value=“staticResource expanderRightHeaderStyle”/>gt;
    </trigger>
    <trigger property=“expandDirection”value=“up”>
    <setter property=“dockpanel.dock”targetname=“expandsite”value=“top”/>
    <setter property=“dockpanel.dock”targetname=“headersite”value=“bottom”/>
    <setter property=“style”targetname=“headersite”value=“staticResource expanderUpherStyle”/>gt;
    </trigger>
    <trigger property=“expandDirection”value=“left”>
    <setter property=“dockpanel.dock”targetname=“expandsite”value=“left”/>gt;
    <setter property=“dockpanel.dock”targetname=“headersite”value=“right”/>
    <setter property=“style”targetname=“headersite”value=“staticResource expanderLeftHeaderStyle”/>gt;
    </trigger>
    <trigger property=“isEnabled”value=“false”>
    <setter property=“foreground”value=“dynamicResource x:static systemcolors.graytextbrushkey”/>gt;
    </trigger>
    </controltemplate.triggers>
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    < /代码> <
    

    细节面板:
    -在两行图像之间显示。
    -保持左右物品就位。

    enter image description here

    解决方案:

    多亏了利特尔比特为这个问题提供了一个非常好的解决方案。基于他的提示,我创建了下面的通用组件,它处理了一些您在创建时最终会遇到的细节利特尔比特溶液生产准备就绪。

    文件:detailedlist.cs

    public class DetailedList : ListBox
    {
        #region DetailsTemplate
        public DataTemplate DetailsTemplate
        {
            get { return (DataTemplate)GetValue( DetailsTemplateProperty ); }
            set { SetValue( DetailsTemplateProperty, value ); }
        }
    
        public static readonly DependencyProperty DetailsTemplateProperty =
            DependencyProperty.Register( nameof( DetailsTemplate ), typeof( DataTemplate ), typeof( DetailedList ) );
        #endregion
    
        static DetailedList()
        {
            Type ownerType = typeof( DetailedList );
    
            DefaultStyleKeyProperty.OverrideMetadata( ownerType,
                new FrameworkPropertyMetadata( ownerType ) );
    
            StyleProperty.OverrideMetadata( ownerType,
                new FrameworkPropertyMetadata( null, ( depObj, baseValue ) =>
                {
                    var element = depObj as FrameworkElement;
                    if( element != null && baseValue == null )
                        baseValue = element.TryFindResource( ownerType );
    
                    return baseValue;
                } ) );
        }
    }
    

    文件:StretchGrid.cs

    internal class StretchGrid : Grid
    {
        private Expander _expander;
    
        #region ParentPanel
        public Panel ParentPanel
        {
            get { return (Panel)this.GetValue( ParentPanelProperty ); }
            set { this.SetValue( ParentPanelProperty, value ); }
        }
    
        public static readonly DependencyProperty ParentPanelProperty = DependencyProperty.Register(
            nameof( ParentPanel ), typeof( Panel ), typeof( StretchGrid ), new PropertyMetadata( null, ParentPanelChanged ) );
    
        private static void ParentPanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var stretchGrid = d as StretchGrid;
            if( stretchGrid == null ) return;
    
            if( e.NewValue is Panel panel )
                panel.SizeChanged += stretchGrid.UpdateMargins;
        }
        #endregion
    
        public StretchGrid()
        {
            this.Loaded += StretchGrid_Loaded;
        }
    
        private void StretchGrid_Loaded( object sender, RoutedEventArgs e )
        {
            _expander = this.FindLogicalParent<Expander>();
    
            _expander.Expanded += UpdateMargins;
            _expander.SizeChanged += UpdateMargins;
    
            this.UpdateMargins( null, null );
        }
    
        private void UpdateMargins( object sender, RoutedEventArgs e )
        {
            if( ParentPanel == null ) return;
            if( _expander == null ) return;
    
            Point delta = _expander.TranslatePoint( new Point( 0d, 0d ), ParentPanel );
    
            //Create negative Margin to allow the Grid to be rendered outside of the Boundaries (full row under the item)
            this.Margin = new Thickness( -delta.X, 0, delta.X + _expander.ActualWidth - ParentPanel.ActualWidth, 0 );
        }
    }
    

    文件:detailedlist.xaml

     <Style x:Key="{x:Type cc:DetailedList}" TargetType="{x:Type cc:DetailedList}"
           BasedOn="{StaticResource {x:Type ListBox}}">
    
        <Style.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="NoButtonExpander.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Style.Resources>
    
        <Setter Property="Grid.IsSharedSizeScope" Value="True"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
        <Setter Property="SelectionMode" Value="Single"/>
    
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type cc:DetailedList}}}" 
                               Tag="{Binding RelativeSource={RelativeSource Self}}" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
    
                                <Border Name="Border" SnapsToDevicePixels="True">
                                    <Expander Style="{StaticResource NoButtonExpander}" VerticalAlignment="Top"
                                          IsExpanded="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" 
                                          Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}">
    
                                        <Expander.Header>
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition SharedSizeGroup="A"/>
                                                </Grid.RowDefinitions>
    
                                                <ContentPresenter Grid.Row="0"/>
                                            </Grid>
                                        </Expander.Header>
    
                                        <cc:StretchGrid ParentWrapPanel="{Binding Path=Tag, 
                                            RelativeSource={RelativeSource AncestorType={x:Type WrapPanel}}}">
    
                                            <ContentPresenter ContentTemplate="{Binding DetailsTemplate, 
                                                RelativeSource={RelativeSource AncestorType={x:Type cc:DetailedList}}}"/>
    
                                        </cc:StretchGrid>
                                    </Expander>
                                </Border>
    
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsSelected" Value="True">
                                        <Setter TargetName="Border" Property="Background"
                                                Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
    
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
    

    文件:nobuttonexpander.xaml

    <Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid Background="Transparent" SnapsToDevicePixels="False">
                            <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid Background="Transparent" SnapsToDevicePixels="False">
                            <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid Background="Transparent" SnapsToDevicePixels="False">
                            <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="ExpanderHeaderFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border>
                        <Rectangle Margin="0" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid Background="Transparent" SnapsToDevicePixels="False">
                            <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="NoButtonExpander" TargetType="{x:Type Expander}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="VerticalContentAlignment" Value="Stretch"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Expander}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
                        <DockPanel>
                            <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            <ContentPresenter x:Name="ExpandSite" DockPanel.Dock="Bottom" Focusable="false" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </DockPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="true">
                            <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Right">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Up">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Left">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   LittleBit    6 年前

    我的方法是使用带有一些修改的

    • listview的 itemspanel 必须具有“wrap”功能,因此我使用了a wrappanel 来在字段中显示图像预览。
    • listViewItem的 itemcontainer 必须有两种状态。图像预览状态和详细信息视图。 expander should do the trick.
    • 图像的详细信息必须显示在图像下的整个列中。我们需要在 listViewItem的边界之外呈现的内容

    现在看起来像这样 由于边界问题,图像细节现在变得一团糟。 height 没问题,因为它只是向下移动下一列,直到适合它。问题在于 width=>code>及其位置(其未左对齐)。

    我创建了一个小的CustomControl, StretchGrid which渲染了整个列和左对齐的 content StretchGrid get the relative distance to the left boundary and set it as negative Margin.Left to render it properly.现在看起来像这样(我希望这正是你想要的)。

    现在 listview的 style

    <!--带细节的图像列表-->
    <style x:key=“piclist”targetType=“x:type listview”>
    &!--只能选择一张图片-->
    <setter property=“selectionmode”value=“single”/>
    
    &!--在项目周围使用包装板启用多行-->
    <setter property=“itemspanel”>
    <setter.value>
    <项模板lt;itemspaneltemplate>
    <wrappanel width=“绑定(listview.actualwidth),relativesource=relativesource findancestor,ancestortype=x:type listview”tag=“绑定relativesource=relativesource self”/>gt;
    </itemspaneltemplate>
    </setter.value>
    &;
    
    &!--覆盖项目的显示区域-->
    <setter property=“itemcontainerStyle”>
    <setter.value>
    <style targettype=“x:type listviewitem”>
    
    &!--定义图像项-->
    <setter property=“template”>
    <setter.value>
    <controlTemplate targetType=“x:类型列表框项”>
    &!--使用Expander标题作为预览/缩略图,展开时显示下面的详细信息-->
    <expander x:name=“picThumbnail”style=“staticResource noButtonExpander”isexpanded=“绑定(listViewItem.isSelected),relativesource=relativesource findancestor,ancestorType=x:type listViewItem”width=“绑定(listViewItem.actualWidth),relativesource=relativesource findancestor,ancestortype=x:type listViewItem”>
    <expander.header>
    &!--缩略图/预览节-->
    <堆叠面板>
    <image source=“/xaml;component/assets/images/thumb.png”height=“16”width=“16”/>gt;
    <label content=“绑定名称”/>
    </stackpanel>
    </expander.header>
    &!--自动拉伸网格(自定义控件)--gt;
    <cc:StretchGrid x:name=“PicDetails”background=“LightGray”parentWrappanel=“绑定路径=标记,relativesource=relativesource findancestor,ancestortype=x:type Wrappanel”>
    &!--图片细节部分(快速&脏设计,稍后更换)->
    <image clipTobounds=“false”source=“/xaml;组件/资产/images/highres.png”width=“128”height=“128”horizontallight=“left”margin=“10,0”/>
    <rectangle fill=“black”height=“128”width=“5”horizontallight=“left”/>
    <rectangle fill=“black”height=“128”width=“5”horizontallight=“right”/>
    <stackpanel margin=“150,0”>
    <label content=“绑定名称”/>
    <label content=“说明:lorem”/>
    <label content=“类别:ipsum”/>
    <label content=“所有者:多尔”/>
    <label content=“大小:5kb”/>
    </stackpanel>
    </cc:StretchGrid>
    </expander>
    </controltemplate>
    </setter.value>
    &;
    &!--将所选元素置于最前面,详细信息请参见编辑-->
    <style.triggers>
    <trigger property=“isselected”value=“true”>
    <setter property=“panel.zindex”value=“1”/>
    </trigger>
    </style.triggers>
    &风格/风格;
    </setter.value>
    &;
    &风格/风格;
    < /代码> 
    
    

    注意:必须添加对StretchGrid的引用。

    以及StretchGridCustom Control

    class StretchGrid:grid
    {
    //父展开器的引用(用于计算网格边距)
    专用扩展器;
    
    //在Style中绑定到Wrappanel的RelativeSource的属性
    公共Wrappanel ParentWrappanel
    {
    获取返回(wrappanel)this.getValue(wrappanel);
    设置this.set value(wrappanel,value);
    }
    
    //RelativeSource绑定到Wrappanel的DependencyProperty(注意:绑定是在样式内部设置的,而不是在PropertyMetadata中以编程方式在此处设置的)
    public static readonly dependencyproperty wrappanel=dependencyproperty.register(“parentwrappanel”,typeof(wrappanel),typeof(stretchgrid),new propertymetadata(null));
    
    / /构造函数
    public StretchGrid():基())
    {
    application.current.mainwindow.loaded+=init;
    application.current.mainwindow.sizechanged+=更新页边距;
    }
    
    private void init(对象发送方,routedeventargs e)
    {
    m_expander=(expander)this.parent;//在XAML标记层次结构更改时更改
    如果(扩音器)!=空)/(或使其与包装板相似
    //relativesource绑定)
    
    m_expander.expanded+=updateMargins;//展开时更新
    m_expander.sizechanged+=updateMargins;//当expander更改大小时更新
    
    //初始化时更新所有拉伸网格
    updateMargins(空,空);
    }
    }
    
    //触发相应事件时计算网格边距
    private void updateMargins(对象发送方,routedeventargs e)
    {
    如果(ParentWrappanel!=空)
    {
    point delta=m_expander.translatePoint(新点(0d,0d),parentWrappanel);
    
    //创建负边距以允许在边界之外呈现网格(图像下的整列)
    this.margin=新厚度(-delta.x,0,delta.x+m_expander.actualwidth-parentwrappanel.actualwidth,0);
    //这些值计算不准确,只是为了举例说明,计算范围很广
    }
    }
    }
    < /代码> 
    
    

    在现有代码中合并有点困难。一个工作示例可能会有所帮助,并且可以找到此处

    旁注:如果我有更多的时间,我会把这些东西打包到一个更大的自定义控件中,像普通的那样使用它。这将大大提高重用性和可用性。


    编辑

    listView中的“new”元素也位于z索引的顶部,因此它是“above”展开的StretchGrid并且一些控件不能被单击,因为它们是“behind”the nextlistView项

    要修复此问题,请添加

    <style.triggers>
    <trigger property=“isselected”value=“true”>
    <setter property=“panel.zindex”value=“1”/>
    </trigger>
    </style.triggers>
    < /代码> 
    
    

    listviewitemstyle。现在,当它可见时,它会将自己放在其他控件之上。

    函数,所以我用了Wrappanel在字段中显示图像预览。

  • 这个ItemContainterListViewItem必须有两种状态。图像预览状态和细节视图Expander应该有技巧。
  • 图像的详细信息必须显示在图像下的整个列中。我们需要的是一些超出列表视图项(更晚些时候)
  • 现在看起来像这样 Image Details messed up 由于边界问题,图像细节现在变得一团糟。这个Height没问题,因为它只是向下移动下一列,直到它适合。问题是Width其位置(未左对齐)。

    我创建了一个小的自定义控件,StretchGrid使其Content穿过整列并左对齐。这个拉伸网格获取到左边界的相对距离并将其设置为负值Margin.Left正确渲染。现在看起来像这样(我希望这正是你想要的)。 Image Details properly displayed

    现在Style列表视图

    <!-- Image List with Detail -->
    <Style x:Key="PicList" TargetType="{x:Type ListView}">
        <!-- Only one Picture can be selected -->
        <Setter Property="SelectionMode" Value="Single"/>
    
        <!-- Enable Multi-Line with a WrapPanel Around the Items -->
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel Width="{Binding (ListView.ActualWidth),RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" Tag="{Binding RelativeSource={RelativeSource Self}}" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    
        <!-- Override Display area of the Item -->
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="{x:Type ListViewItem}">
    
                    <!-- Define Image Item -->
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <!-- Use Expander Header as Preview/Thumbnail and display Details below when expanded -->
                                <Expander x:Name="PicThumbnail" Style="{StaticResource NoButtonExpander}" IsExpanded="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}" Width="{Binding (ListViewItem.ActualWidth), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
                                    <Expander.Header>
                                        <!-- Thumbnail/Preview Section -->
                                        <StackPanel>
                                            <Image Source="/XAML;component/Assets/Images/Thumb.png" Height="16" Width="16" />
                                            <Label Content="{Binding Name}"/>
                                        </StackPanel>
                                    </Expander.Header>
                                    <!-- Self stretching Grid (Custom Control) -->
                                    <cc:StretchGrid x:Name="PicDetails" Background="LightGray" ParentWrappanel="{Binding Path=Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}}">
                                        <!-- Picture Detail Section (quick & dirty designed, replace later) -->
                                        <Image ClipToBounds="False" Source="/XAML;component/Assets/Images/Highres.png" Width="128" Height="128" HorizontalAlignment="Left" Margin="10,0" />
                                        <Rectangle Fill="Black" Height="128" Width="5" HorizontalAlignment="Left"/>
                                        <Rectangle Fill="Black" Height="128" Width="5" HorizontalAlignment="Right"/>
                                        <StackPanel Margin="150,0">
                                            <Label Content="{Binding Name}"/>
                                            <Label Content="Description: Lorem"/>
                                            <Label Content="Category: Ipsum"/>
                                            <Label Content="Owner: Dolor"/>
                                            <Label Content="Size: 5kB"/>
                                        </StackPanel>
                                    </cc:StretchGrid>
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <!-- Brings selected element to front, details see edit -->
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Panel.ZIndex" Value="1" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
    

    注意:必须添加对拉伸网格.

    以及拉伸网格自定义控件

    class StretchGrid : Grid
    {
        //Reference for parent expander (used to calculate Grid Margin)
        private Expander m_expander;
    
        //Property for relativesource Binding to Wrappanel in Style
        public WrapPanel ParentWrappanel
        {
            get { return (WrapPanel)this.GetValue(Wrappanel); }
            set { this.SetValue(Wrappanel, value); }
        }
    
        //DependencyProperty for RelativeSource Binding to Wrappanel in Style (Note: the Binding is set inside the Style, not here programmatically in PropertyMetaData)
        public static readonly DependencyProperty Wrappanel = DependencyProperty.Register("ParentWrappanel", typeof(WrapPanel), typeof(StretchGrid), new PropertyMetadata(null));
    
        //Constructor
        public StretchGrid() : base()
        {
            Application.Current.MainWindow.Loaded += Init;
            Application.Current.MainWindow.SizeChanged += UpdateMargins;
        }
    
        private void Init(object sender, RoutedEventArgs e)
        {
            m_expander = (Expander)this.Parent;                 //Change when xaml markup hirarchy changes
            if(m_expander != null)                              //(or make it similar to the Wrappanel with
            {                                                   //RelativeSource Binding)
    
                m_expander.Expanded += UpdateMargins;             //Update when expander is expanded
                m_expander.SizeChanged += UpdateMargins;          //Update when the expander changes the Size
    
                //Update all StretchGrids on Initialization
                UpdateMargins(null, null);
            }
        }
    
        //Calculate Grid Margin when an according Event is triggered
        private void UpdateMargins(object sender, RoutedEventArgs e)
        {
            if(ParentWrappanel != null)
            {
                Point delta = m_expander.TranslatePoint(new Point(0d, 0d), ParentWrappanel);
    
                //Create negative Margin to allow the Grid to be rendered outside of the Boundaries (full column under the Image)
                this.Margin = new Thickness(-delta.X, 0, delta.X + m_expander.ActualWidth - ParentWrappanel.ActualWidth, 0);
                //Theese Values arent calculated exavtly, just broad for example purpose
            }
        }
    }
    

    在现有代码中合并有点困难。一个有效的例子可能会有帮助,并且可以找到HERE.

    旁注:如果我有更多的时间,我会把这些东西打包到一个更大的自定义控件中,像平常一样使用它。UIElement(例如)Border)这将大大提高重用性和可用性。


    编辑

    中的“最新”元素列表视图也位于z索引的顶部,因此它“高于”扩展的拉伸网格一些控件无法单击,因为它们位于下一个控件的“后面”ListviewItem.

    要修复此问题,请添加

    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Panel.ZIndex" Value="1" />
        </Trigger>
    </Style.Triggers>
    

    列表视图项风格。现在,当它可见时,它会将自己置于其他控件之上。

        2
  •  0
  •   Prateek Shrivastava    6 年前

    这就是我迄今为止所做的:-

    列出的图像:

    单击的图像-将在其下方显示详细信息视图:

    目前,我不会关闭其他详细视图-因此下面可能会为我发生。 但是,所有这些都需要传播一个已单击其他项目的事件。并关闭所有其他详细视图(其MVVM和由bool属性驱动)

    ==================================

    我有一个基本的用户控件,它将以自上而下的方式加载项目:

    网格 格栅& GT; <滚动查看器> <itemsControl itemssource=“绑定GridData,updateSourceTrigger=propertyChanged”> <itemscontrol.itemspanel> <项模板lt;itemspaneltemplate> <stackpanel orientation=“垂直”/> </itemspaneltemplate> </itemscontrol.itemspanel> </itemscontrol> </scrollviewer> 和/格栅& GT; 和/格栅& GT; < /代码>

    此用户控件本身的每一行(项)都使用另一项控件。使图像水平排列。此外,每个项目都有一个详细视图部分(边框的可见性由图像单击控制)

    <usercontrol.resources>
    <资源字典>
    <booleantVisibilityConverter x:key=“booleantVisibilityConverter”/>
    </resourcedictionary>
    </usercontrol.resources>
    格栅& GT;
    格栅& GT;
    <grid.rowdefinitions>
    <rowdefinition height=“*”/>
    <rowdefinition height=“auto”/>
    </grid.rowdefinitions>
    <itemsControl grid.row=“0”itemssource=“绑定imageslist,updateSourceTrigger=propertyChanged”>
    <itemscontrol.itemspanel>
    <项模板lt;itemspaneltemplate>
    <stackpanel orientation=“水平”/>
    </itemspaneltemplate>
    </itemscontrol.itemspanel>
    <itemsControl.itemTemplate>
    <数据模板>
    <button margin=“5”command=“binding dataContext.itemClickedCommand,relativesource=relativesource mode=findancestor,ancestortype=x:type usercontrol”
    commandParameter=“绑定”>
    <button.style>
    <style targettype=“button”>
    <setter property=“template”>
    <setter.value>
    <控制模板>
    格栅& GT;
    <grid.rowdefinitions>
    <rowdefinition height=“*”/>
    <rowdefinition height=“auto”/>
    </grid.rowdefinitions>
    <image grid.row=“0”source=“绑定映像,updateSourceTrigger=propertyChanged”/>
    <textBlock name=“displayText”grid.row=“1”horizontallight=“center”text=“绑定displayText,updateSourceTrigger=propertyChanged”/>gt;
    和/格栅& GT;
    </controltemplate>
    </setter.value>
    &;
    &风格/风格;
    </button.style>
    &按钮/按钮;
    </datatemplate>
    </itemscontrol.itemstemplate>
    </itemscontrol>
    
    <border margin=“2”grid.row=“1”background=“black”padding=“10”
    visibility=“绑定ShowDetailsPanel,UpdateSourceTrigger=PropertyChanged,Converter=StaticResource BooleantVisibilityConverter”>
    格栅& GT;
    <grid.columndefinitions>
    <columnDefinition width=“自动”/>
    <columnDefinition width=“*”/>
    </grid.columndefinitions>
    <border grid.column=“0”background=“white”cornerradius=“10”>
    <image margin=“5”source=“binding selectedImage.image,updateSourceTrigger=propertyChanged”/>gt;
    &边界/gt;
    <grid grid.column=“1”>
    <grid.rowdefinitions>
    <rowdefinition height=“auto”/>
    <rowdefinition height=“自动”/>
    <rowdefinition height=“自动”/>
    <rowdefinition height=“auto”/>
    </grid.rowdefinitions>
    <textBlock grid.row=“0”margin=“20 20 0 0”fontsize=“15”
    text=“binding selectedimage.imagename,stringformat=filename:0”foreground=“white”/>gt;
    <textBlock grid.row=“1”margin=“20 20 0 0”fontsize=“15”
    text=“binding selectedImage.size,stringFormat=size:0 bytes”foreground=“white”/>gt;
    <textBlock grid.row=“2”margin=“20 20 0 0”fontsize=“15”
    text=“binding selectedImage.location,stringFormat=path:0”foreground=“white”/>gt;
    <textBlock grid.row=“3”margin=“20 20 0 0”fontsize=“15”
    text=“binding selectedImage.createdTime,stringFormat=last modified:0”foreground=“white”/>gt;
    和/格栅& GT;
    和/格栅& GT;
    &边界/gt;
    和/格栅& GT;
    和/格栅& GT;
    < /代码> 
    

    单击的图像-将在其下方显示详细信息视图:

    enter image description here

    目前,我不会关闭其他详细视图-因此下面可能会为我发生。 但是,所有这些都需要传播一个已单击其他项目的事件。并关闭所有其他详细视图(其MVVM和由bool属性驱动)

    enter image description here

    ==================================

    我有一个基本的用户控件,它将以自上而下的方式加载项目:

    <Grid>
        <Grid>
            <ScrollViewer>
                <ItemsControl ItemsSource="{Binding GridData, UpdateSourceTrigger=PropertyChanged}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </ScrollViewer>
        </Grid>
    </Grid>
    

    此用户控件本身的每一行(项)都使用另一项控件。使图像水平排列。此外,每个项目都有一个详细视图部分(边框的可见性由图像单击控制)

    <UserControl.Resources>
        <ResourceDictionary>
            <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <ItemsControl Grid.Row="0" ItemsSource="{Binding ImagesList, UpdateSourceTrigger=PropertyChanged}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button Margin="5" Command="{Binding DataContext.ItemClickedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
                                CommandParameter="{Binding}">
                            <Button.Style>
                                <Style TargetType="Button">
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate>
                                                <Grid>
                                                    <Grid.RowDefinitions>
                                                        <RowDefinition Height="*"/>
                                                        <RowDefinition Height="Auto"/>
                                                    </Grid.RowDefinitions>
                                                    <Image Grid.Row="0" Source="{Binding Image, UpdateSourceTrigger=PropertyChanged}"/>
                                                    <TextBlock Name="DisplayText" Grid.Row="1" HorizontalAlignment="Center" Text="{Binding DisplayText, UpdateSourceTrigger=PropertyChanged}"/>
                                                </Grid>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </Button.Style>
                        </Button>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
    
            <Border Margin="2" Grid.Row="1" Background="Black" Padding="10"
                    Visibility="{Binding ShowDetailsPanel, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityConverter}}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Border Grid.Column="0" Background="White" CornerRadius="10">
                        <Image Margin="5" Source="{Binding SelectedImage.Image, UpdateSourceTrigger=PropertyChanged}"/>
                    </Border>
                    <Grid Grid.Column="1">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0" Margin="20 20 0 0" FontSize="15"
                                   Text="{Binding SelectedImage.ImageName, StringFormat={}Filename: {0}}" Foreground="White"/>
                        <TextBlock Grid.Row="1" Margin="20 20 0 0" FontSize="15"
                                   Text="{Binding SelectedImage.Size, StringFormat={}Size: {0} bytes}" Foreground="White"/>
                        <TextBlock Grid.Row="2" Margin="20 20 0 0" FontSize="15"
                                   Text="{Binding SelectedImage.Location, StringFormat={}Path: {0}}" Foreground="White"/>
                        <TextBlock Grid.Row="3" Margin="20 20 0 0" FontSize="15"
                                   Text="{Binding SelectedImage.CreatedTime, StringFormat={}Last Modified: {0}}" Foreground="White"/>
                    </Grid>
                </Grid>
            </Border>
        </Grid>
    </Grid>