#c# #wpf #xaml
#c# #wpf #xaml
Вопрос:
Я создал a ListBox
с закругленными углами. Я также добавил нижнюю границу для всех ListBoxItem
s, кроме последнего.
Однако буквы ListBoxItem
s имеют нормальные квадратные углы, поэтому при наведении курсора мыши на первый или последний элемент или выборе первого или последнего элемента вы можете увидеть перекрытие между круглым ListBox
углом и квадратными ListBoxItem
углами.
Я не могу установить cornerRadius так же, как я установил BorderThickness — я думаю, это потому, что cornerRadius является свойством свойства Border(?).
Я могу заставить ВСЕ ListBoxItem
s иметь все круглые углы, что исправляет перекрытие, но тогда у ВСЕХ ListBoxItem
s будут круглые подчеркивания и выделения, чего я бы предпочел не иметь. Мне нужны только эти круглые углы в нижней части последнего элемента (и, в конечном итоге, в верхней части первого элемента)
Я хотел бы использовать аналогичный триггер для настройки CornerRadius
, который я делаю для настройки BrushThickness
.
Есть ли способ установить радиус угла только для последнего элемента в a ListBox
? (и, в конечном итоге, для первого элемента)
В моем тесте я использую пакет MaterialDesignTheme от NuGet. Поскольку это нестандартно, я добавлю сюда весь свой код (также обратите внимание: я новичок в WPF, поэтому не стесняйтесь критиковать все, что выглядит не так):
App.xaml:
<Application . . .
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainWindow.xaml: (Обратите внимание, если вы раскомментируете раздел с комментариями, он будет стилизован так ListBoxItems
, как я бы хотел, чтобы был только последний ListBoxItem
стиль)
<Window . . .
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}">
<Window.Resources>
<local:IsLastItemInContainerConverter x:Key="IsLastItemInContainerConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Margin="5">
<ListBox x:Name="GameListBox"
BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="1">
<ListBox.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<!--<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="0 0 10 10"/>
</Style>
</Style.Resources>-->
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}" Value="False">
<Setter Property="BorderThickness" Value="0 0 0 1" />
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignDivider}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}" Value="True">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem>
<TextBlock> Plain
</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock> Old
</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock> ListBox
</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock> Full of junk
</TextBlock>
</ListBoxItem>
</ListBox>
</StackPanel>
</Grid>
</Window>
…и в MainWindow.xaml.cs я определил конвертер для поиска последнего элемента:
public class IsLastItemInContainerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item)
== ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Комментарии:
1. Я бы попробовал маску непрозрачности и обрезал весь элемент управления. У списка есть граница вокруг него, поэтому я думаю, вы могли бы адаптировать этот подход: chriscavanagh.wordpress.com/2008/10/03 /…
Ответ №1:
Прежде всего, пожалуйста, поймите, что MaterialDesignTheme
пакет не использовался в моем коде.
Items.cs
Вместо использования Converter
я добавил класс модели.
public class Items
{
public string Name { get; set; }
public bool IsFirst { get; set; }
public bool IsLast { get; set; }
}
App.xaml
Я определил стили ListBoxItem
, ListBox
как показано ниже.
<Style TargetType="{x:Type ListBoxItem}" x:Key="listboxitem">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="border"
Background="White"
BorderBrush="#AAAAAA"
BorderThickness="1 1 1 0"
CornerRadius="0">
<TextBlock Text="{Binding Name}" Foreground="Black" FontSize="13" FontWeight="Normal"
Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsFirst}" Value="True">
<Setter TargetName="border" Property="CornerRadius" Value="10 10 0 0"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsLast}" Value="True">
<Setter TargetName="border" Property="CornerRadius" Value="0 0 10 10"/>
<Setter TargetName="border" Property="BorderThickness" Value="1 1 1 1"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#666666"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border" Property="Background" Value="#666666"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListBox}" x:Key="listbox">
<Setter Property="Width" Value="200"/>
<Setter Property="Height" Value="200"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource listboxitem}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border Background="Transparent"
BorderBrush="#AAAAAA"
BorderThickness="0 0 0 0"
CornerRadius="10">
<ItemsPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow.xaml
<ListBox x:Name="lbx" Style="{StaticResource listbox}"/>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lbx.ItemsSource = GetItems();
}
private List<Items> GetItems()
{
List<Items> source = new List<Items>();
source.Add(new Items { Name = "Plain", IsFirst = true });
source.Add(new Items { Name = "Old" });
source.Add(new Items { Name = "ListBox" });
source.Add(new Items { Name = "Full of junk", IsLast = true }); ;
return source;
}
}
Это будет показано следующим образом..
Комментарии:
1. это действительно работает, но требует, чтобы вы изменили модель, включив в нее свойства first и last, вероятно, должен быть лучший способ.
2. @AthulRaj Если вы не можете изменить модель, вам придется найти другой способ, но этот метод выглядит естественным и хорошим. Кроме того, это сложно обрабатывать в основном потому, что вам нужно настроить cornerRadius в верхней и нижней части списка и даже заполнить его, когда он находится в состоянии выбора. Поэтому было бы лучше использовать Trigger для обработки его просто через свойства модели.
3. Естественно и хорошо? Это список. Что происходит, когда в этом пространстве 10 элементов вместо 4, поэтому вам нужно прокручивать?
4. @Andy Да, это список. Однако он часто используется как RadioButton .
5. Как вы сказали, если вам нужно прокручивать, вы должны исправить cornerRadius в верхней и нижней части ItemsPresenter в шаблоне списка. Но если вы это сделаете, возникнет проблема с заполнением элемента списка.