【问题标题】:WPF Toolbar Items HorizontalAligment="Right"WPF 工具栏项 Horizo​​ntalAligment="Right"
【发布时间】:2011-01-13 04:30:01
【问题描述】:

是否可以使 WPF 工具栏中的元素具有 Right 的 Horizo​​ntalAlignment?

<ToolBar Height="38" VerticalAlignment="Top" Grid.Row="1">
    <Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
    <Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
    <ComboBox Width="120" HorizontalAlignment="Right"/>
</ToolBar>

我尝试将内部元素添加到网格中,并将ColumnDefinitions 也分配给左/右。我也试过StackPanel。无论我尝试什么,我似乎都无法让 ComboBox 被“锚定”在工具栏的右侧。

更新:

<DockPanel LastChildFill="True">

不起作用,它不会像填充普通元素那样填充 ToolBar 元素。

【问题讨论】:

    标签: wpf xaml toolbar alignment


    【解决方案1】:

    进一步的调查表明,为了做到这一点,我需要在ToolBar 内设置Grid 的宽度,或者将ToolBar 内的DockPanel 动态设置为ToolBar 的宽度Toolbar 的宽度使用RelativeSource。

    但是,这并不是一个干净的解决方案。让Toolbar 在调整大小时正确更新是相当复杂的。所以相反,我发现了一些 hack,看起来,并且通过添加外部 Grid 来操作更清晰。

    <Grid>
        <ToolBar Height="38" VerticalAlignment="Top" Grid.Row="1">
            <Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
            <Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
        </ToolBar>
        
        <ComboBox Margin="0,0,15,0" Width="120" HorizontalAlignment="Right" Grid.Row="1"/>
    </Grid>
    

    由于我的所有元素都在网格上,我可以将ComboBox 放在ToolBar 的顶部,方法是将其Grid.Row 分配到与工具栏相同的行。在将我的Margins 设置为稍微拉动ComboBox 以免影响外观后,它会根据需要运行而没有错误。由于我发现这样做的唯一其他方法是动态设置 DockPanel/Grid 的 Width 属性,我实际上觉得这是更清洁更有效的方法。

    【讨论】:

    • 实际上我发现这是一个绝妙(而且非常简洁)的解决方案。我被这个问题困扰了很久。谢谢!
    • 这真是一个绝妙的主意。谢谢!
    • 对长期存在的臀部疼痛的简单而出色的解决方案 :-)
    • 这将导致您的右对齐项目(在您的情况下为 ComboBox)如果调整大小(由于窗口大小调整)到最右边的工具栏项目一直在的位置,则浮动在工具栏项目上向右。
    【解决方案2】:

    对于寻找解决方案的其他人,以下方法对我有用:

    <ToolBar HorizontalAlignment="Stretch" ToolBarTray.IsLocked="True">
      <ToolBar.Resources>
        <Style TargetType="{x:Type DockPanel}">
          <Setter Property="HorizontalAlignment" Value="Right" />
        </Style>
    </ToolBar.Resources>
    

    我使用的是 .NET 4.6 和 VS2015,但我相信这也适用于以前的版本。

    【讨论】:

      【解决方案3】:

      我意识到这是一个老话题,但在提问时它仍然会弹出。这就是我处理这个问题的方式:

      <Grid>
          <Grid.RowDefinitions>
              <RowDefinition x:Name="MenuRow"    Height="25"/>
              <RowDefinition x:Name="ToolbarRow" Height="25"/>
              <RowDefinition x:Name="CatalogRow" Height="*"/>
              <RowDefinition x:Name="RecipeRow"  Height="0.4*"/>
          </Grid.RowDefinitions>
          <ToolBar Grid.Row="1">
              <Button x:Name="tbFileOpen" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Load.png"/></Button>
              <Button x:Name="tbFileSave" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Save.png"/></Button>
              <Button x:Name="tbFileClear" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/New document.png"/></Button>
          </ToolBar>
          <ToolBar Grid.Row="1" HorizontalAlignment="Right">
              <Button x:Name="tbFileExit" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Exit.png"/></Button>
          </ToolBar>
      </Grid>
      

      实际上:我创建了两个工具栏对象并将它们放在同一个 Grid.row 上。第一个具有默认(左)对齐,第二个是右对齐。它似乎对我有用。

      【讨论】:

        【解决方案4】:
            <ToolBar Width="100" VerticalAlignment="Top" >
                <ToolBar.Resources>
                    <Style TargetType="{x:Type ToolBarPanel}">
                        <Setter Property="Orientation" Value="Vertical"/>
                    </Style>
                </ToolBar.Resources>
        
                <DockPanel>
                    <ToolBarPanel Orientation="Horizontal" >
                        <Button>A</Button>
                        <Button>B</Button>
                    </ToolBarPanel>
                    <Button DockPanel.Dock="Right" HorizontalAlignment="Right">C</Button>
                </DockPanel>
            </ToolBar>
        

        【讨论】:

        • 您的答案有效,但如果在按钮 A 和 B 之间放置分隔符,则分隔符不会显示,但会保持其边距。知道为什么它不显示吗?
        【解决方案5】:

        我就是这样做的:

        我为工具栏创建了一个样式

            <Style x:Key="{x:Type ToolBar}" TargetType="{x:Type ToolBar}">
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToolBar}">
                        <Grid Background="{StaticResource ToolGridBackground}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Image Grid.Column="0" Style="{StaticResource LogoImage}"/>
                            <ToolBarPanel Grid.Column="2" x:Name="PART_ToolBarPanel" IsItemsHost="true" Margin="0,1,2,2" Orientation="Horizontal"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        

        重要的部分是:

        <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
        

        还有

        <ToolBarPanel Grid.Column="2"/>
        

        这样,您的按钮将右对齐

        【讨论】:

        • 这行得通,但它很糟糕,因为我们完全替换了 ToolBar 的模板,因此失去了默认样式。
        【解决方案6】:

        我对“WidthConverter”解决方案不是很满意,因为最后我得到了一些动态元素。进一步的搜索让我找到了here,这似乎对我来说是完美的。如果您有兴趣,这是我的代码示例:

        <ToolBar Name="toolBar">
            <DockPanel Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ToolBarPanel}}}">
                <DockPanel.Resources>
                    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"></Style>
                </DockPanel.Resources>
                <Button x:Name="btnRefresh" ToolTip="Refresh" Click="btnRefresh_Click">
                    <Image Margin="2 0" Source="/Resources/refresh.ico" Height="16" Width="16"/>
                </Button>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <Image Margin="2 0" Source="/Resources/Help.ico" Height="16" Width="16"/>
                    <TextBlock Text="Help" Margin="2 0" VerticalAlignment="Center"/>
                </StackPanel>
            </DockPanel>
        </ToolBar>
        

        【讨论】:

        • 啊,这种方法在窗口调整大小时效果不佳。
        • 这不起作用,因为如果您缩小窗口,所有工具栏按钮都会消失。否则,它会完美运行。因此,如果对这种方法进行微调以使其发挥作用,那就太好了。
        • 好的,我在social.msdn.microsoft.com/Forums/en-US/wpf/thread/…(来自 dhbusch2)找到了另一个帖子,这对我来说真的很完美,除了我必须对按钮应用样式,例如 Style="{StaticResource {x:Static ToolBar .ButtonStyleKey}}"
        【解决方案7】:

        我对此的解决方案是创建一个具有类似“弹簧”功能的标签控件,这样它就可以在工具栏上的按钮之间填充空白,从而“右对齐”工具栏的组合框(或任何其他控件)需要“右对齐”。

        为此,我创建了一个 WidthConverter,它将获取 ToolBar 控件的实际宽度,然后减去右对齐组合框所需的空间。:

        public class WidthConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return Math.Max(System.Convert.ToDouble(value) - System.Convert.ToDouble(parameter), 0.0);
            }
        
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
        

        然后,我在工具栏中添加了一个标签控件,放置在您需要右对齐的组合框的左侧。将标签的 Width 绑定到工具栏的 ActualWidth 并应用 WidthConverter:

        <Label Width="{Binding Converter={StaticResource WidthConverter}, ElementName=toolBar1, Path=ActualWidth, ConverterParameter=50}" />
        

        您需要根据您的特定需求调整 ConverterParameter,直到获得所需的“右对齐”。数字越大,组合框的空间越大,数字越小,空间越小。

        使用此解决方案,只要您的工具栏调整大小,标签就会自动调整大小,使您的组合框看起来正确对齐。

        与向工具栏添加网格相比,此解决方案有两个很大的好处。首先是如果你需要使用工具栏上的按钮,你不会失去工具栏按钮的样式。第二个是如果通过调整窗口大小来减少工具栏长度,溢出将按预期工作。单个按钮将根据需要进入溢出。如果将按钮放入网格中,则网格将放入溢出中,并带有所有按钮。

        正在使用的 XAML:

        <ToolBarPanel>
            <ToolBar Name="toolBar1">
                <Button>
                    <Image Source="save.png"/>
                </Button>
            <Label Width="{Binding Converter={StaticResource Converters.WidthConverter},
                          ElementName=toolBar1,
                          Path=ActualWidth,
                          ConverterParameter=231}" HorizontalAlignment="Stretch" ToolBar.OverflowMode="Never"/>
            <Button>
                <Image Source="open.png"/>
            </Button>
        </ToolBar>
        

        如果您希望始终保留工具栏上的最后一个按钮,例如您希望始终可见的帮助按钮,请将 ToolBar.OverflowMode="Never" 属性添加到其元素。

        【讨论】:

        • 您的解决方案确实看起来更干净。但是,我不能让它为我工作。能否提供一个左侧一个按钮,右侧另一个按钮的工具栏的完整示例?
        • 更新了答案以包含一个示例。第一个按钮将左对齐,第二个按钮将右对齐。您需要调整转换器参数以获得所需的结果。
        【解决方案8】:

        您是否尝试过使用填充工具栏的 DockPanel,然后您可以将 ComboBox 停靠在右侧。

        请记住,对于停靠面板,您放置项目的顺序非常重要。

        HTH

        【讨论】:

        • 如何用 DockPanel 填充工具栏?我试过了,只能动态地做。除非有什么我不知道的,这是工具栏的问题。这就是为什么这对我不起作用。
        • 现在工作太忙了,我会在这个周末发布一个解决方案,感觉应该会更干净一些。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多