Используйте другой элемент управления в WPF ListBox - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть такой код:

    <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>

введите описание изображения здесь

1 Ответ

0 голосов
/ 27 апреля 2020

Прежде чем перейти к коду, хочу отметить, что это работа для шаблонов данных , а не шаблонов управления. Свойство 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 } }

    ...
}

Я начинаю с определения двух различных ItemTemplate внутри Resources из ListBox. Вы должны определить один для каждого из различных элементов управления, которые вам нужно использовать. Обратите внимание, что я остановился на «AlertRecord.» из привязок. Это потому, что каждый экземпляр DataTemplate будет иметь AlertRecord в качестве DataContext.

Для свойства ItemTemplate я заимствовал из этого ответа здесь: { ссылка }. Я сделал DataTemplate с ContentControl и использовал Style, чтобы изменить ContentTemplate на основе DataTrigger с. Это позволяет вам изменять шаблон на основе свойств вашего элемента списка.

На основе вашего комментария стиль устанавливается так, что по умолчанию используется "OtherControlItem" (элемент управления без расширения), и AlertExpanderItem используется, когда HasPositiveValue возвращает true. HasPositiveValue - это свойство, которое вам нужно добавить к AlertRecord.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...