Привязать пользовательский элемент управления, содержащийся в ObservableCollection‹CustomClass›, в WrapPanel

У меня есть класс, определенный таким образом:

    public class CustomClass
    {
        string Name;
        int Age;
        Usercontrol usercontrol;
    }

где Usercontrol — это визуальный элемент, который я хочу вставить в WrapPanel.

CustomClass организован в статической коллекции ObservableCollection.

    public static class CollectionClass
    {
        public static ObservableCollection<CustomClass> MyCollection = new ObservableCollection<CustomClass>();
    }

Я хочу связать свойство usercontrol CustomClass в коллекции для визуализации в WrapPanel, поэтому визуальные элементы отображаются в том же порядке, что и элементы в коллекции.

Прямо сейчас я заполняю WrapPanel вручную с помощью кода, но я подумал, что должен быть способ сделать это быстро и легко с помощью привязки данных. Я пытаюсь сделать это с помощью ItemsControl, определенного следующим образом:

    <ItemsControl Name="SensorMenuWrap"  ItemsSource="{Binding }">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

но я не знаю, как заставить случиться волшебство.

ИЗМЕНИТЬ:

Я попробовал решение, предложенное ChrisO, реализованное так:

1 - я сделал коллекцию свойством

2 - я сделал UserControl свойством

3 - я устанавливаю DataContex из кода:

SensorMenuWrap.Datacontext = CollectionClass.MyCollection

4 - Обвязка:

         <ItemsControl Name="SensorMenuWrap"  ItemsSource="{Binding }">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding usercontrol}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

Теперь я могу визуализировать первый элемент коллекции. Если первый элемент изменяется, я визуализирую новый первый элемент. Как я могу визуализировать всю коллекцию?


person Hamma    schedule 08.09.2014    source источник


Ответы (1)


Я не тестировал это. Кроме того, убедитесь, что userControl является свойством, а не полем. Я предполагаю, что вы знаете, как правильно настроить DataContext для ссылки на свойство MyCollection.

<ItemsControl Name="SensorMenuWrap"  ItemsSource="{Binding MyCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding userControl}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Вам также следует подумать о прямой ссылке на UserControl в DataTemplate, а не на привязку к нему как к свойству класса. Это будет выглядеть так

<ItemsControl Name="SensorMenuWrap"  ItemsSource="{Binding MyCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Изменить:

В ответ на ваше редактирование вам было бы гораздо лучше решить эту проблему с помощью многократно используемого UserControl с DataBindings в свойствах CustomClass. Вот что мне нужно для этого:

Класс коллекции

public static class CollectionClass
    {
        public static ObservableCollection<CustomClass> MyCollection { get; set; }

        static CollectionClass()
        {
            MyCollection = new ObservableCollection<CustomClass>();

            MyCollection.Add(new CustomClass { Age = 25, Name = "Hamma"});
            MyCollection.Add(new CustomClass { Age = 32, Name = "ChrisO"});
        }
    }

Пользовательский класс

public class CustomClass
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

Содержимое UserControl

<StackPanel>
        <TextBlock Background="Tan" Text="{Binding Name}" />
        <TextBlock Background="Tan" Text="{Binding Age}" />
    </StackPanel>

Главное окно

<ItemsControl Name="SensorMenuWrap"  ItemsSource="{Binding }">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <so25728310:Usercontrol Margin="5" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

Здесь вместо того, чтобы запекать пользовательский элемент управления в свои данные, вы сохраняете его в представлении. Всегда хорошо иметь разделение между вашим представлением и данными. Вы даже можете отказаться от Usercontrol и иметь два текстовых поля непосредственно в DataTemplate, но это зависит от того, хотите ли вы повторно использовать это представление в другом месте.

person ChrisO    schedule 08.09.2014
comment
Это не будет работать. MyCollection сама по себе не является свойством. Его DataContext должен быть объектом, статический класс этого не обеспечит. - person Maximus; 08.09.2014
comment
Не обязательно, вы можете установить DataContext элемента в статический класс, если хотите. Однако MyCollection должен быть свойством этого статического класса. - person ChrisO; 08.09.2014
comment
Ваше решение работает частично. Не могли бы вы увидеть правку и помочь мне исправить ее? - person Hamma; 09.09.2014
comment
Я не могу использовать ваш подход, потому что у меня есть несколько пользовательских элементов управления внутри класса. Тот, который я написал, является упрощенным примером, чтобы было легко понять, как взаимодействуют элементы, но на данный момент я не могу изменить структуру. - person Hamma; 09.09.2014
comment
Я только что узнал, что частично работающее решение было моим плохим: я предположил, что WrapPanel получает ширину своего родителя без явного объявления этого, в то время как дочерние элементы расширяются по горизонтали за пределы ширины родителя. Поэтому я их не видел и думал, что показывается только первый элемент коллекции. Решение работает, поэтому я отмечаю его как ответ. - person Hamma; 09.09.2014