2016-06-15 3 views
2

My ViewModel имеет свойства типа MultipleSelectionInfo, которые выглядят следующим образом (я удалил связанный код PropertyChanged для ясности, но мои работы по связыванию):WPF - Как добавить текстовое поле на панель, содержащую элементы ItemsControl

public abstract class MultipleSelectionInfo 
{ 
    // A SelectableObject is made of a bool IsSelected and a string ObjectData 
    public ObservableCollection<SelectableObject<string>> Items 
    { get; set; } 

    public string Others 
    { get; set; } 
} 

отобразить эти свойства так:

TextBox pushed to the bottom TextBox pushed to the right

Моя XAML выглядит следующим образом:

<DataTemplate x:Key="PrepControl"> 
     <WrapPanel Orientation="Horizontal" HorizontalAlignment="Left"> 
      <ItemsControl ItemsSource="{Binding Items}"> 
       <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
         <WrapPanel Orientation="Horizontal"/> 
        </ItemsPanelTemplate> 
       </ItemsControl.ItemsPanel> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <StackPanel Orientation="Horizontal"> 
          <CheckBox Content="{Binding ObjectData}" IsChecked="{Binding IsSelected}" Margin="0,6,8,0"/> 
         </StackPanel> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 

      <TextBox MaxWidth="400" MinWidth="100" 
        MaxHeight="20" Text="{Binding Others}" IsEnabled="{Binding IsOthersSelected}" 
         HorizontalAlignment="Left"/> 
     </WrapPanel> 
    </DataTemplate> 

Подводя итог, я показываю элементы MultipleSelectionInfo в ItemsControl (горизонтальный WrapPanel), затем я показываю TextBox. Наконец, я завершаю все в горизонтальной WrapPanel.

Проблема с этим заключается в том, что TextBox не выравнивается хорошо с элементами из-за WrapPanels. В идеале, если бы я мог добавить TextBox внутри WrapPanel элемента ItemsControl, это исправило бы его. Но я не мог этого сделать.

Возможно ли это? Как мне это сделать? Я бы с удовольствием избегал манипулирования элементами управления/панелями программным способом. Если мне действительно нужно, я не очень хорошо знаком с MVVM, не могли бы вы объяснить?

Ниже я ожидаю достичь: Expected display 1 Expected display 2

+2

ItemsSource является 'ObservableCollection и DataTemplate' деталей использует '{Binding ObjectData}' и '{Binding IsSelected}'. Он не должен работать – ASh

+0

Вы правы. Я упростил код для лучшей читаемости. Позвольте мне обновить. – corentinaltepe

ответ

1

универсальный подход заключается в создании DataTemplateSelector

Как правило, вы создаете DataTemplateSelector, когда у вас есть более одного DataTemplate для того же типа объектов, и вы хотите предоставить свою собственную логику для выбора DataTemplate для применения на основе свойств каждого объекта данных.

в данном случае я бы попробовать триггер, который модифицирует ContentTemplate для Others пункта:

<DataTemplate x:Key="PrepControl"> 
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <CheckBox Content="{Binding ObjectData}" 
          IsChecked="{Binding IsSelected}" 
          Margin="0,6,8,0"> 
        <CheckBox.Style> 
         <Style TargetType="CheckBox"> 
          <Style.Triggers> 
           <Trigger Property="Content" Value="Others"> 
            <Setter Property="ContentTemplate"> 
             <Setter.Value> 
              <DataTemplate> 
               <StackPanel Orientation="Horizontal"> 
                <TextBlock Text="{Binding}" VerticalAlignment="Center"/> 
                <TextBox Margin="5,0" VerticalAlignment="Center" 
                   MinWidth="50" 
                   IsEnabled="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" 
                   Text="{Binding Path=DataContext.Others, ElementName=Lst}"/> 
               </StackPanel> 
              </DataTemplate> 
             </Setter.Value> 
            </Setter> 
           </Trigger> 
          </Style.Triggers> 
         </Style> 
        </CheckBox.Style> 
       </CheckBox> 
      </StackPanel> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
</DataTemplate> 


вариант с выбором DataTemplate через Trigger

<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst"> 
    <ItemsControl.Resources> 
     <DataTemplate x:Key="CheckItem"> 
      <CheckBox Content="{Binding ObjectData}" 
        IsChecked="{Binding IsSelected}" 
        Margin="0,6,8,0"/> 
     </DataTemplate> 

     <DataTemplate x:Key="OthersItem"> 
      <StackPanel Orientation="Horizontal"> 
       <CheckBox IsChecked="{Binding IsSelected}" 
          Content="{Binding ObjectData}" 
          Margin="0,6,8,0"/> 
       <TextBox Margin="5,0" VerticalAlignment="Center" 
         MinWidth="50" 
         IsEnabled="{Binding IsSelected}" 
         IsHitTestVisible="True" 
         Text="{Binding Path=DataContext.Others, ElementName=Lst}"/> 
      </StackPanel> 
     </DataTemplate> 
    </ItemsControl.Resources> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <ContentPresenter Content="{Binding}"> 
       <ContentPresenter.Style> 
        <Style TargetType="ContentPresenter"> 
         <Setter Property="ContentTemplate" Value="{StaticResource CheckItem}"/> 
         <Style.Triggers> 
          <DataTrigger Binding="{Binding Path=ObjectData}" Value="Others"> 
           <Setter Property="ContentTemplate" Value="{StaticResource OthersItem}"/> 
          </DataTrigger> 
         </Style.Triggers> 
        </Style> 
       </ContentPresenter.Style> 
      </ContentPresenter> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
+0

Ничего себе, это сделал трюк! Спасибо. UX еще лучше, потому что TextBox включен в CheckBox (нажатие на отключенный TextBox нажимает на «Other» CheckBox, который позволяет TextBox). Я не уверен, как все же. Не могли бы вы исправить меня, если я ошибаюсь? Каждый элемент отображается как «нормальный» CheckBox, за исключением случаев, когда контент (текст) является «другим». Затем стиль добавляет TextBox, текст которого привязан к элементу вне коллекции Items. Я раньше пробовал что-то подобное, но не смог правильно связать содержимое текстового поля. Он работает сейчас! – corentinaltepe

+1

@corentin, CheckBox происходит от ToggleButton, поэтому все его содержимое можно щелкнуть, включая отключенный TextBox. Я забыл об этом. Пожалуйста, см. Мое редактирование без такого поведения (TextBox не входит в шаблон CheckBox) – ASh

Смежные вопросы