仅从组合框中的第一个项目删除边距

时间:2019-03-18 07:13:21

标签: c# wpf xaml combobox

我有一个ComboBox,其中包含不同的部分,每个部分的标题分别为VideoAudioImage

我使用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 个答案:

答案 0 :(得分:2)

对于问题本身,您只需要一个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自定义演示文稿。

答案 1 :(得分:2)

您可以定义另一个属性,例如 IsFirstHeader ,并仅向其添加边距。

答案 2 :(得分:1)

如果我是在商业应用程序中执行此操作,则可能会在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绑定引擎的强大功能,但是到最后,您仍然要向逻辑层添加逻辑代码,该层并不是它真正所属的,即使它是通用的转换器。

答案 3 :(得分:0)

不确定将其用作样式触发器时是否可以使用,请尝试一下。

<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
    <Setter Property="Margin" Value="0,0,0,0"/>
</DataTrigger>