2013-07-10 5 views
2

У меня есть холст, который содержит несколько разных фигур, которые являются статическими и связаны с разными свойствами в модели представления (MVVM). В настоящее время, холст определяется следующим образом (упрощенный):ItemsControl and Canvas - только первый элемент виден

<Canvas> 
<Polygon Fill="Red" Stroke="Gray" StrokeThickness="3" Points="{Binding StorageVertices}" /> 
<Ellipse Fill="Blue" Width="{Binding NodeWidth}" Height="{Binding NodeHeight}" /> 

<!-- And some more static shapes --> 
<!-- ...       --> 
</Canvas> 

К этому холсту, я хочу, чтобы добавить динамический список, где каждый элемент преобразуется в многоугольник. Я думал, что лучшим подходом будет ItemsControl. Это то, что я использовал в моем подходе, но отображается только первый элемент в коллекции (списке).

<Canvas> 
<!-- ...               --> 
<!-- Same canvas as earlier with the addition of the ItemsControl --> 

<ItemsControl ItemsSource="{Binding Offices, Mode=OneWay, Converter={...}}"> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
    <Polygon Fill="AliceBlue" Stroke="Gray" StrokeThickness="1" Points="{Binding Points}" /> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
</Canvas> 

С помощью этого кода, отображается только первый элемент в Offices коллекции. Как так? Если я вижу визуальное дерево, все полигоны находятся внутри него. Я очень новичок в WPF, поэтому могу только догадываться, но я подумал, что дефолт StackPanel как ItemPresenter может быть неуместным в этом случае, но я могу только догадываться ...

+0

Я так не думаю, потому что если я отформатирую коллекцию (так что другой «Полигон» первый), он даже не перекрывается с ранее отображаемым «Полигоном». –

+0

где именно вы поступили в собственность "Офисы"? – chris6523

+0

В моем представлении конструктор модели, с которым связан этот холст («Холст» находится в «UserControl», который слабо связан с моей моделью просмотра). –

ответ

6

Что ж, здесь есть несколько вещей. Во-первых, при работе с панелью Canvas каждый элемент на панели будет помещен в верхнем левом углу, если не указано относительное местоположение. Ниже приведен пример Canvas с вашими элементами, один находится возле верхней (40 пикселей вниз, 40 вправо), а другой расположен в нижней (100 пикселей влево от правого края):

<Canvas> 
    <Polygon Canvas.Left="40" Canvas.Top="40" ... /> 
    <Ellipse Canvas.Right="100" Canvas.Bottom="0" ... /> 
</Canvas> 

Теперь, помните, что Canvas - это тип Panel. Основная цель - не быть каким-то списком, но, кроме того, определить как элемент управления (или элементов управления) - , представленный. Если вы хотите представить список/список (перечисление) элементов управления, то вы должны использовать тип ItemsControl. Оттуда вы можете указать ItemsSource и настроить ItemsPanel (а также ItemTemplate, которые могут потребоваться).

Во-вторых, и это часто возникает, это «Как добавить статические элементы в код ItemsSource, связанный с данными?», на который следует ответить CompositeCollection, а затем CollectionContainer. В вашей ситуации у вас есть два (2) статических элемента (плюс больше), которые вы хотите добавить в свою коллекцию офисов. Я предполагаю, что эти «статические формы» действительно заменяют образ плана.


Вот пример того, что ваш XAML будет выглядеть, если вы хотите сделать свой план выставки:

<ItemsControl> 
    <ItemsControl.Resources> 
     <CollectionViewSource x:Key="cvs" Source="{Binding Floors}" /> 
    </ItemsControl.Resources> 
    <ItemsControl.ItemsSource> 
     <CompositeCollection> 
      <CollectionContainer Collection="{Binding Source={StaticResource cvs}" /> 

      <!-- Static Items --> 
     </CompositeCollection> 
    </ItemsControl.ItemsSource> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <Canvas ... /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

я не уверен, что каждый из ваших объектов в вашей Floor коллекции, но они не должны быть какой-либо формы вообще. Это должен быть какой-то объект, который просто содержит информацию о местонахождении офиса, цвете и т. Д.Вот пример того, я предполагаю, что в виду того что вы не обеспечивают то, что коллекция элементов состоит из:

// This can (and should) implement INotifyPropertyChanged 
public class OfficeViewModel 
{ 
    public string EmployeeName { get; private set; } 

    public ReadOnlyObservableCollection<Point> Points { get; private set; } 

    ... 
} 

public class Point 
{ 
    public double X { get; set; } 
    public double Y { get; set; } 
} 

Здесь вы бы использовать DataTemplate перевести объект (модель/ViewModel) в то, что должны выглядеть на ваш взгляд:

<ItemsControl> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Polygon Points="{Binding Points}" Color="AliceBlue" ... /> 
     <DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

конечно, если вы хотите иметь несколько представлений о том, что каждый элемент выглядит как из вашей коллекции, Offices, то вам придется воспользоваться DataTemplateSelector (который будет быть установленным к свойству ItemsControl.ItemTemplateSelector), чтобы выбрать из набора DataTemplate s. Вот хороший ответ/ссылка на что: https://stackoverflow.com/a/17558178/347172


И, наконец, последнее замечание ... держать все в масштабе, и ваши очки как типы double. Лично я всегда использовал шкалу 0-1, или 0-100. Пока все ваши очки и статические предметы подходят в пределах этой границы, вы можете растянуть свой ItemsControl на любую высоту/ширину, и все, что внутри, также будет хорошо подстраиваться и соответствовать.


Update: Это было совсем немного времени, и я забыл, что CompositeCollection класс не является типом FrameworkElement, поэтому он не имеет DataContext. Если вы хотите, чтобы привязка одного из ваших коллекций, вы должны указать ссылку на FrameworkElement с желаемым DataContext:

<CollectionContainer Collection="{Binding DataContext.Offices, Source={x:Reference someControl}}"/> 

Update 2: Порывшись в Интернете на некоторое время, я нашел лучший способ разрешить привязки данных для работы с CompositeCollection раздел ответа выше был обновлен, чтобы учесть это, используя CollectionViewSource для создания ресурса, связанного с коллекцией. Это намного лучше, чем использование x:Reference. Надеюсь, это поможет.

+0

Я не мог попросить лучшего ответа. СПАСИБО! –

+1

Я обновил свой принятый ответ, чтобы показать лучший способ использования 'CompositeCollection'. Я не использовал его так долго, что забыл, как правильно его использовать. Надеюсь, что обновленный ответ помогает и упрощает понимание. –

+0

Это просто спасло мою жизнь, я не мог найти никакого хорошего или глубокого объяснения ItemsControl, и здесь я только что нашел его – Tofandel

0

Попробуйте установить

yourItemsControl.DataContext = Offices; 

в коде позади.

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