включение элементов без данных в поле со списком данных WPF - PullRequest
1 голос
/ 29 июня 2010

Я работал с двумя различными полями со списком в своем решении (Отдел и Имя). Эти поля со списком в настоящее время привязаны к коллекции списков, которая возвращается из ссылки на внешнюю службу. Вопрос в том, что мне нужно вставить другие элементы в поле со списком, кроме того, что предоставляется API.

Например, в дополнение к отображению всех названий отделов мне нужно, чтобы первый элемент, отображаемый в поле со списком, был "Выбрать отдел ..." Проводя некоторые исследования (как здесь, так и в Интернете), я выгляжу так, как будто я могу сделать это с помощью составной коллекции.

http://zamjad.wordpress.com/2010/05/18/using-composite-collection-in-c/

Мой вопрос касается случаев, когда у меня есть только один элемент, который необходимо представить в качестве первого элемента в поле со списком. Это лучший подход? Или мне нужен другой подход?

Заранее спасибо,

Ответы [ 3 ]

2 голосов
/ 29 июня 2010

Вместо того, чтобы вносить беспорядок в ваши данные, просто чтобы показать временное значение в пользовательском интерфейсе, вы можете сделать это непосредственно в XAML, изменив ComboBox ControlTemplate.Вы можете настроить триггер в шаблоне для замены значения, когда ничего не выбрано.

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="SelectedIndex" Value="-1"/>
        <Condition Property="IsDropDownOpen" Value="false"/>
        <Condition Property="HasItems" Value="True"/>
    </MultiTrigger.Conditions>
    <Setter Property="Content" TargetName="Presenter" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>
</MultiTrigger>

Эта версия дает вам дополнительное преимущество в том, что она не позволяет выбирать пустое значение после выборасделал.Его можно использовать, установив для тега сообщение по умолчанию.

<ComboBox Tag="Select department..." Template="{StaticResource ComboBoxSelectTemplate}" ItemsSource="{Binding Departments}"/>

Вот полная версия на основе шаблона Aero по умолчанию, для которого требуется добавить ссылку на dll и xmlns: Microsoft_Windows_Themes = "clr-namespace: Microsoft.Windows.Themes; assembly = PresentationFramework.Aero "(ButtonChrome и SystemDropShadowChrome можно заменить эффектом Border и DropShadow, чтобы избежать добавления ссылок):

<Geometry x:Key="DownArrowGeometry">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
<Style x:Key="ComboBoxReadonlyToggleButton" TargetType="{x:Type ToggleButton}">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="IsTabStop" Value="false"/>
    <Setter Property="Focusable" Value="false"/>
    <Setter Property="ClickMode" Value="Press"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
                    <Grid HorizontalAlignment="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                        <Path x:Name="Arrow" Fill="Black" HorizontalAlignment="Center" Margin="3,1,0,0" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
                    </Grid>
                </Microsoft_Windows_Themes:ButtonChrome>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Fill" TargetName="Arrow" Value="#AFAFAF"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ControlTemplate x:Key="ComboBoxSelectTemplate" TargetType="{x:Type ComboBox}">
    <Grid x:Name="MainGrid" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
        </Grid.ColumnDefinitions>
        <Popup x:Name="PART_Popup" Margin="1" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Grid.ColumnSpan="2">
            <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
                <Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
                    <ScrollViewer CanContentScroll="true">
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
                    </ScrollViewer>
                </Border>
            </Microsoft_Windows_Themes:SystemDropShadowChrome>
        </Popup>
        <ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
        <ContentPresenter x:Name="Presenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsHitTestVisible="false" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"/>
    </Grid>
    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="SelectedIndex" Value="-1"/>
                <Condition Property="IsDropDownOpen" Value="false"/>
                <Condition Property="HasItems" Value="True"/>
            </MultiTrigger.Conditions>
            <Setter Property="Content" TargetName="Presenter" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>
        </MultiTrigger>
        <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
            <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
            <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
        </Trigger>
        <Trigger Property="HasItems" Value="false">
            <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            <Setter Property="Background" Value="#FFF4F4F4"/>
        </Trigger>
        <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
1 голос
/ 29 июня 2010

Звучит так, как будто вы хотите, чтобы какой-то элемент был видимым, когда ничего не выделено, и являлся частью ComboBox, но был невидимым, когда сделан выбор.

Проще говоря, вы могли быпросто создайте UserControl, в котором был бы ваш ComboBox (если вы добавляете свои элементы в код, а не статическую разметку XAML), а также TextBlock, содержащий ваше приглашение.Например:

<Grid>
    <ComboBox x:Name="ComboBoxControl"
              SelectionChanged="ComboBoxControl_SelectionChanged"
              HorizontalAlignment="Left" VerticalAlignment="Top" 
              MinWidth="{Binding ElementName=UnselectedText, Path=ActualWidth}">
        <ComboBoxItem>One</ComboBoxItem>
        <ComboBoxItem>Two</ComboBoxItem>
        <ComboBoxItem>Three</ComboBoxItem>
    </ComboBox>
    <TextBlock IsHitTestVisible="False" 
               x:Name="UnselectedText" 
               HorizontalAlignment="Left" 
               Text="Select an option..." 
               VerticalAlignment="Top" Margin="4" 
               Padding="0,0,30,0" />
</Grid>

Затем в коде вставьте некоторую логику в обработчик событий:

Private Sub ComboBoxControl_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
    If ComboBoxControl.SelectedIndex = -1 Then
        UnselectedText.Visibility = Windows.Visibility.Visible
    Else
        UnselectedText.Visibility = Windows.Visibility.Hidden
    End If
End Sub

Установка свойства IsHitTestVisible="False" DependencyProperty в TextBlock позволяет событиям мыши проходить черезтак что вы можете щелкнуть ComboBox и установить видимость на Hidden в выделенном фрагменте кода, чтобы компоновка внешнего вида ComboBox по умолчанию не перепрыгивала, когда текст приглашения скрыт.

Естественно, всеэто также можно сделать, создав пользовательский элемент управления MyComboBox, унаследованный от ComboBox, с добавленным «UnselectedPromptProperty» в качестве свойства зависимости.Тогда логика для отображения или скрытия «UnselectedPromptProperty» будет исходить из обратного вызова проверки на DP.Это более продвинутый вариант, но он позволит вам распространять шаблоны стилей, отличные от заданных по умолчанию, в ваш элемент управления, позволяя другим изменять его.

0 голосов
/ 29 июня 2010

Я использую составной класс для включения встроенной помощи («Выберите отдел ...») в ComboBox, и я думаю, что она работает хорошо.

Когда пользователь выбирает отдел, я рекомендую удалить встроенную помощь.

...