Как можно растянуть вложенные элементы ToolBar?

291
09 сентября 2018, 03:00

Как можно растянуть вложенные в ToolBar элементы на всю ширину ToolBar? Чтобы можно было через margin задавать расположение кнопок относительно правого края приложения. Заранее благодарен за ответ.

<ToolBar x:Name="toolBar" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" MinHeight="46" MaxHeight="46" VerticalAlignment="Bottom">
    <DockPanel HorizontalAlignment="Stretch" Width="Auto">
        <ToolBarPanel Orientation="Horizontal" MinHeight="25" DockPanel.Dock="Top" >
            <Button x:Name="btn1" Width="35" VerticalAlignment="Stretch">
                ...
            </Button>
        </ToolBarPanel>
    </DockPanel>
</ToolBar>
Answer 1

"Сердцем" ToolBar является ToolBarPanel, которая в свою очередь является StackPanel и умеет размещать дочерние элементы только последовательно друг за другом. Заменить эту панель на другую, которая поддерживает какое-нибудь позиционирование невозможно.

Я предлагаю вам несколько иное решение — добавить в шаблон ToolBar место, выровненное по правому краю, в которое можно будет поместить дополнительный контент. Для этого в дизайнере VS щелкните правой кнопкой по тулбару и выберите Edit Template-Edit a Copy..., введите желаемое наименование для шаблона и место его размещения, нажмите OK.

Стандартный шаблон будет добавлен в проект, теперь можно его отредактировать. Найдите в нем примерно такое место:

<Border x:Name="MainPanelBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" Style="{StaticResource ToolBarMainPanelBorderStyle}">
    <DockPanel KeyboardNavigation.TabIndex="1" KeyboardNavigation.TabNavigation="Local">
        <Thumb x:Name="ToolBarThumb" Margin="-3,-1,0,0" Padding="6,5,1,6" Style="{StaticResource ToolBarThumbStyle}" Width="10"/>
        <ContentPresenter x:Name="ToolBarHeader" ContentSource="Header" HorizontalAlignment="Center" Margin="4,0,4,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
        <ToolBarPanel x:Name="PART_ToolBarPanel" IsItemsHost="true" Margin="0,1,2,2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
    </DockPanel>
</Border>

Это и есть основная часть шаблона, давайте добавим сюда ContentControl с выравниванием по правому краю:

<Border x:Name="MainPanelBorder" ...>
    <DockPanel ...>
        <ContentControl DockPanel.Dock="Right" Margin="0,1,2,2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
        </ContentControl>
        <Thumb x:Name="ToolBarThumb" .../>
        <ContentPresenter x:Name="ToolBarHeader" .../>
        <ToolBarPanel x:Name="PART_ToolBarPanel" ... Margin="0,1,0,2" .../>
    </DockPanel>
</Border>

Я немного поправил у него и у ToolBarPanel свойство Margin, для того, чтобы всё выглядело "монолитно".

Теперь нужно как-то предоставить возможность помещать в этот ContentControl нужный нам контент из разметки (а не чтобы он был жестко закодирован внутри стиля). Стандартное решение здесь — использовать Attached Property. Создадим static-класс и опишем в нем одно AP:

public static class Extension
{
    public static object GetContent(DependencyObject obj)
        => obj.GetValue(ContentProperty);
    public static void SetContent(DependencyObject obj, object value)
        => obj.SetValue(ContentProperty, value);
    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.RegisterAttached("Content", typeof(object),
            typeof(Extension), new PropertyMetadata(null));
}

Хорошо, теперь внутри стиля можно привязаться к нему:

<ContentControl ... Content="{TemplateBinding local:Extension.Content}">
</ContentControl>

Теперь в разметке ToolBar можно поместить в это свойство кнопку (или панель с кнопками/любыми другими контролами):

<ToolBar Style="{DynamicResource MyToolBarStyle}">
    <local:Extension.Content>
        <Button Content="4444"/>
    </local:Extension.Content>
    <Button Content="1111"/>
    <Button Content="2222"/>
    <Button Content="3333"/>
</ToolBar>

Остается нюанс с тем, что кнопка имеет обычный выпуклый стиль, а не плоский, как все остальные кнопки внутри тулбара. Исправить это можно, задав ей соответствующий стиль: Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}". Но это не совсем правильно и лучше нужный стиль для кнопки положить в ресурсы нашего ContentControl, чтобы он подхватывался автоматически:

    <ContentControl ...>
        <ContentControl.Resources>
            <Style TargetType="Button" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"/>
        </ContentControl.Resources>
    </ContentControl>

Готово:

<ToolBar Style="{DynamicResource MyToolBarStyle}">
    <local:Extension.Content>
        <StackPanel Orientation="Horizontal">
            <Button Content="4444"/>
            <Button Content="5555"/>
        </StackPanel>
    </local:Extension.Content>
    <Button Content="1111"/>
    <Button Content="2222"/>
    <Button Content="3333"/>
</ToolBar>

READ ALSO
Оператор switch вложенный в другой. Как сократить?

Оператор switch вложенный в другой. Как сократить?

Суть такова - есть динамическое кол-во игроков которое определяется юзеромНам нужно сделать что бы при вызове метода менялся цвет игрока...

307
c# получение dom в winform

c# получение dom в winform

Хотел бы узнать есть ли какой либо другой элемент работы с DOM на с# кроме WebBrowserПричина следующая: WebBrowser использует движок IE и давально старый,...

321
Интерактивный режим для Explicit тестов

Интерактивный режим для Explicit тестов

Часто использую тесты Nunit в качестве песочницы

243