У меня есть ComboBox с разными разделами и заголовками для каждого, Video, Audio, Image.
Используя XAMLStyle, я добавил 7px поле над заголовками, чтобы разделить разделы.
Как я могу удалить только первое поле заголовка, чтобы оно было на одном уровне с верхней частью ComboBox?
Я попытался установить ComboBox<Grid> на Margin = "0,-7,0,0", но это относилось ко всем элементам.
<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");
}
}
@Cizzl да, но тогда ему нужно было бы установить только последний элемент каждого раздела, так что проблема все еще здесь.
Вы можете попробовать использовать AlternationIndex ComboBox в триггере данных, чтобы настроить стиль вашего первого элемента. Или реализовать еще одно свойство внутри Container. Или используйте конвертер XAML, поскольку ответ ниже следует





Если бы я делал это в коммерческом приложении, я бы, вероятно, предоставил свойство в своем 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, но в конце концов вы все равно добавляете логический код к слою представления, который на самом деле ему не принадлежит, даже если он является универсальным. преобразователь.
Что касается самого вопроса, все, что вам нужно, это 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 для настройки презентации.
Вы можете определить другое свойство, такое как Исфирстхеадер, и добавить маржу только к нему.
Я бы сказал IsNotFirstHeader и добавил поля ко всем заголовкам, кроме первого.
Не уверен, что это сработает при применении в качестве триггера стиля, но попробуйте.
<DataTrigger Binding = "{Binding RelativeSource = {RelativeSource PreviousData}}" Value = "{x:Null}">
<Setter Property = "Margin" Value = "0,0,0,0"/>
</DataTrigger>
Вы можете установить
marginв конце элемента. НравитсяMargin = "0 0 0 7"