Удалить маржу только с первого элемента в ComboBox - PullRequest
0 голосов
/ 18 марта 2019

У меня есть ComboBox с различными разделами и заголовками для каждого, Video, Audio, Image.

Используя XAML Style, я добавил 7pxполе над заголовками, чтобы разделить разделы.

Как удалить только поле первого заголовка, чтобы оно находилось на одном уровне с верхней частью ComboBox?

Я попытался установить ComboBox <Grid> до Margin="0,-7,0,0", но применяется ко всем элементам.

ComboBox Header Margins


ComboBox

<ComboBox x:Name="cboContainer" 
          ItemsSource="{Binding Format_Container_Items}"
          SelectedValuePath="Name"
          SelectedValue="{Binding Format_Container_SelectedItem, Mode=TwoWay}"
          Style="{DynamicResource ComboBoxCustom}"
          ItemContainerStyle="{DynamicResource ComboBoxCustomItem}" 
          HorizontalAlignment="Left"
          VerticalAlignment="Top" 
          Width="105" 
          Height="22"
          Margin="0,2,0,0">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <TextBlock DataContext="{Binding}">
                    <TextBlock.Text>
                        <Binding Path="Name"/>
                    </TextBlock.Text>
                </TextBlock>
            </Grid>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Стиль предмета

<Style x:Key="ComboBoxCustomItem" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="Template" Value="{StaticResource ComboBoxCustom.Item.ControlTemplate}"/>
    <Setter Property="Foreground" Value="#FF000000" />
    <Setter Property="Background" Value="#FFFFFFFF" />
    <Setter Property="BorderBrush" Value="#FFFFFFFF" />
    <Style.Triggers>

        <!-- Selected -->
        <Trigger Property="IsSelected" Value="true">
            <Setter Property="Foreground" Value="{StaticResource ComboBoxCustom.Static.Foreground}" />
            <Setter Property="Background" Value="{StaticResource ComboBoxCustom.Static.Background}" />
        </Trigger>

        <!-- Mouse Over -->
        <Trigger Property="IsMouseOver" Value="true">
            <Setter Property="Foreground" Value="{StaticResource ComboBoxCustom.MouseOver.Foreground}" />
            <Setter Property="Background" Value="{StaticResource ComboBoxCustom.MouseOver.Background}" />
        </Trigger>

        <!-- Headers -->
        <DataTrigger Binding="{Binding IsHeader}" Value="True">
            <Setter Property="IsEnabled" Value="False"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <!-- 7px Margin Applied Here -->
            <Setter Property="Margin" Value="0,7,0,0"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding IsHeader}" Value="False">
            <Setter Property="Margin" Value="0,0,0,0"/>
        </DataTrigger>

    </Style.Triggers>
</Style>

Источник предметов

public class FormatContainer
{
    public string Name { get; set; }
    public bool IsHeader { get; set; }
}

public List<FormatContainer> _Format_Container_Items = new List<FormatContainer>()
{
    new FormatContainer() { Name = "Video", IsHeader = true  },
    new FormatContainer() { Name = "webm",  IsHeader = false },
    new FormatContainer() { Name = "mp4",   IsHeader = false },
    new FormatContainer() { Name = "mkv",   IsHeader = false },

    new FormatContainer() { Name = "Audio", IsHeader = true  },
    new FormatContainer() { Name = "mp3",   IsHeader = false },
    new FormatContainer() { Name = "m4a",   IsHeader = false },
    new FormatContainer() { Name = "ogg",   IsHeader = false },

    new FormatContainer() { Name = "Image", IsHeader = true  },
    new FormatContainer() { Name = "jpg",   IsHeader = false },
    new FormatContainer() { Name = "png",   IsHeader = false },
    new FormatContainer() { Name = "webp",  IsHeader = false },
};

public List<FormatContainer> Format_Container_Items
{
    get { return _Format_Container_Items; }
    set
    {
        _Format_Container_Items = value;
        OnPropertyChanged("Format_Container_Items");
    }
}

Ответы [ 4 ]

2 голосов
/ 18 марта 2019

Для самого вопроса все, что вам нужно, это ItemsPanelTemplate.

        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Margin="0 -7 0 0"/>
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>

Но для правильного способа делать то, что вы хотите, я настоятельно рекомендую вам изменить структуру данных на

public class FormatContainer
{
    public string Name { get; set; }
    public string Category { get; set; }
}

, затем сгруппируйте представление Format_Container_Items с Category и используйте ComboBox.GroupStyle, чтобы настроить презентацию.

2 голосов
/ 18 марта 2019

Вы можете определить другое свойство, например IsFirstHeader и добавить поле только к нему.

1 голос
/ 18 марта 2019

Если бы я делал это в коммерческом приложении, я бы, вероятно, выставил свойство в моем FormatContainer, чтобы указать представлению, какой элемент в списке является первым, но это можно сделать в XAML с использованием преобразователя равенства, который возвращает true, если любые два элемента совпадают:

public class EqualityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return Object.Equals(values[0], values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Затем, вернувшись в свой XAML, вы просто добавляете дополнительный DataTrigger, используя его в качестве преобразователя и передавая как текущий объект, так и первый в исходном списке:

<DataTrigger Value="True">
    <DataTrigger.Binding>
        <MultiBinding>
            <MultiBinding.Converter>
                <conv:EqualityConverter />
            </MultiBinding.Converter>
            <Binding Path="DataContext.Format_Container_Items[0]" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ComboBox}" />
            <Binding />
        </MultiBinding>
    </DataTrigger.Binding>
    <Setter Property="Margin" Value="0,0,0,0"/>
</DataTrigger>

Я бы порекомендовал вам справиться с этим в вашей модели представления, используя обычный DataTrigger. Методы, подобные той, что я использовал здесь, демонстрируют всю мощь механизма связывания WPF, но в конце концов вы все еще добавляете логический код для просмотра слоя, который не является тем, чем он на самом деле принадлежит, даже если он является общим конвертер.

0 голосов
/ 18 марта 2019

Не уверен, будет ли он работать при применении в качестве триггера стиля, но попробуйте.

<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
    <Setter Property="Margin" Value="0,0,0,0"/>
</DataTrigger>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...