![](/img/trans.png)
[英]how to add two different controls (checkbox and combobox) as list item in ListBox wpf
[英]Use a different item controls in WPF ListBox
我有這樣的代碼:
<ListBox Name="lstBox"
ItemsSource="{Binding ViewModelsView}"
SelectedItem="{Binding SelectedAlertViewOutput, Mode=OneWayToSource}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}" Padding="1" >
<ScrollViewer Padding="{TemplateBinding Padding}" >
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected"
Value="{Binding AlertRecord.IsSelected, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<controls:AlertExpander
Margin="1"
Value="{Binding AlertRecord.AlertCategory}"
IsExpanded="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
IsActive="{Binding AlertRecord.IsActive, Mode=OneWay }"
StartTime="{Binding AlertRecord.Timestamp, Mode=OneWay}"
StopTime="{Binding AlertRecord.EndTimestamp, Mode=OneWay}"
AlertId="{Binding AlertRecord.Id, Mode=OneWay}"
<controls:AlertExpander.Content>
<ContentPresenter>
</ContentPresenter>
</controls:AlertExpander.Content>
</controls:AlertExpander>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Style>
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:AlertUnknownViewModel}">
<local:AlertUnknownView></local:AlertUnknownView>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="4">
<ContentPresenter Content="{Binding}"></ContentPresenter>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
ListBox
使用我的控件AlertExpander
作為ListBoxItem
。
是否可以創建一個不僅包含AlertExpander
類型元素的列表? 我希望另一種類型的元素也使用AlertExpander
所依賴的參數。
我有幾種類型的控件,它們接受與AlertExpander
相同的參數,但看起來不同,我需要在列表中顯示所有類型的元素,而不僅僅是AlertExpander
。
AlertExpander.xaml:
<Expander
<Control.Style>
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<ToggleButton Name="HeaderButton">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="IsChecked" Value="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="IsEnabled" Value="{Binding Path=Expandable, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Border>
<!-- Border shade -->
<Border Name="BorderShade" Grid.Row="1" BorderThickness="1" BorderBrush="Transparent" Visibility="Collapsed"
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" Margin="10">
<Image.OpacityMask>
<ImageBrush ImageSource="{Binding SelectedItem.IconSource, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"/>
</Image.OpacityMask>
<Image.Source>
<MultiBinding Mode="OneWay" Converter="{converters:GrayscaleImageSourceConverter}">
<Binding Path="SelectedItem" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
<Binding Path="IsActive" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
</MultiBinding>
</Image.Source>
</Image>
<StackPanel x:Name="topHeader" Grid.Row="0" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Bottom">
</StackPanel>
<Label x:Name="bottomHeader" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Background="Transparent" Padding="0,2,0,0" FontSize="9pt"
Content="{Binding AlertHeaderTime, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="BorderShade" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding IsAlertHeaderTimeShown, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}" Value="false">
<Setter TargetName="topHeader" Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="topHeader" Property="Grid.RowSpan" Value="2"/>
<Setter TargetName="bottomHeader" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay, Converter={converters:AlertExpanderCornerRadiusTopConverter}}">
</Border>
<!-- Border shade -->
<Border Name="BorderShade" Grid.Row="1" BorderThickness="1" BorderBrush="Transparent" Visibility="Collapsed"
Background="{Binding MouseOverShade, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay, Converter={converters:AlertExpanderCornerRadiusTopConverter}}">
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" Margin="10">
<Image.OpacityMask>
<ImageBrush ImageSource="{Binding SelectedItem.IconSource, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"/>
</Image.OpacityMask>
<Image.Source>
<MultiBinding Mode="OneWay" Converter="{converters:GrayscaleImageSourceConverter}">
<Binding Path="SelectedItem" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
<Binding Path="IsActive" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
</MultiBinding>
</Image.Source>
</Image>
<StackPanel x:Name="topHeader" Grid.Row="0" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<Label Background="Transparent" Padding="0,0,0,2" FontSize="12pt"
FontWeight="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:BoolToFontWeightConverter}}"
Content="{Binding AlertHeader, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
<Label Background="Transparent" Padding="4,0,0,2" FontSize="12pt"
FontWeight="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:BoolToFontWeightConverter}}"
Visibility="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:InactiveNoteVisibilityConverter}}"
Content="{Binding InactiveNote, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</StackPanel>
<Label x:Name="bottomHeader" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Background="Transparent" Padding="0,2,0,0" FontSize="9pt"
Content="{Binding AlertHeaderTime, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="BorderShade" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding IsAlertHeaderTimeShown, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}" Value="false">
<Setter TargetName="topHeader" Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="topHeader" Property="Grid.RowSpan" Value="2"/>
<Setter TargetName="bottomHeader" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<!-- Content -->
<ScrollViewer Name="ContentScrollViewer" Grid.Row="1"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Bottom"
Visibility="Visible">
<Border Name="ExpanderContentBorder" BorderThickness="1,0,1,1" BorderBrush="Black">
<ContentPresenter ContentSource="Content"/>
</Border>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Control.Style>
在開始編寫代碼之前,我想指出這是數據模板的工作,而不是控制模板。 Template
屬性采用ControlTemplate
並用於定義控件的結構。 這通常在您從頭開始構建控件或顯着更改控件時使用。 您要做的只是更改數據在現有控件中的顯示方式。 為此,有DataTemplate
屬性,例如ItemTemplate
。
順便說一句,我為您整理了一些代碼,這些代碼至少應該為您指明正確的方向:
<ListBox Name="lstBox" ItemsSource="{Binding ViewModelsView}" SelectedItem="{Binding SelectedAlertViewOutput, Mode=OneWayToSource}">
<ListBox.Resources>
<DataTemplate DataType="local:AlertRecord" x:Key="AlertExpanderItem">
<controls:AlertExpander Margin="1"
Value="{Binding AlertCategory}"
IsExpanded="{Binding IsSelected, Mode=TwoWay}"
IsActive="{Binding IsActive, Mode=OneWay }"
StartTime="{Binding Timestamp, Mode=OneWay}"
StopTime="{Binding EndTimestamp, Mode=OneWay}"
AlertId="{Binding Id, Mode=OneWay}"/>
</DataTemplate>
<DataTemplate DataType="local:AlertRecord" x:Key="OtherControlItem">
<controls:OtherControl Margin="1"
Value="{Binding AlertCategory}"
IsExpanded="{Binding IsSelected, Mode=TwoWay}"
IsActive="{Binding IsActive, Mode=OneWay }"
StartTime="{Binding Timestamp, Mode=OneWay}"
StopTime="{Binding EndTimestamp, Mode=OneWay}"
AlertId="{Binding Id, Mode=OneWay}"/>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource OtherControlItem}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="0">
<Setter Property="ContentTemplate" Value="{StaticResource AlertExpanderItem}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
...
public class AlertRecord
{
...
public bool HasPositiveValue { get { return Value >= 0 } }
...
}
我首先在ListBox
的Resources
中定義兩個不同的ItemTemplate
。 您將為需要使用的每個不同控件定義一個。 請注意,我從綁定中刪除了“ AlertRecord.
”。 這是因為每個DataTemplate
實例都將AlertRecord
作為其DataContext
。
對於ItemTemplate
屬性,我在這里借用了這個答案: https://stackoverflow.com/a/10191762/5086631 。 我用ContentControl
制作了一個DataTemplate
並使用Style
來更改基於DataTrigger
的ContentTemplate
。 這使您可以根據列表項的屬性更改模板。
根據您的評論,樣式設置為默認使用“ OtherControlItem
”(非擴展控件),並在AlertExpanderItem
返回 true 時使用HasPositiveValue
。 HasPositiveValue
是您需要添加到AlertRecord
的屬性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.