简体   繁体   中英

Binding to a collection of user controls in XAML

I've a collection of UserControls which I want to show in a stack panel. I've no control over how and what those user controls contain. I just know that they are some sort of user controls (could be a button, a textblock or any UIElement.) Here is a small example

public class Car : IHasView
{
     public UserControl MyView { get return new MyCarViewThatHasAButton(); }
}

public class Jeep : IHasView
{
    public UserControl MyView { get return new MyJeepViewThatHasATextblock(); }
}

public class MainView : INotifyPropertyChanged{
    private ICollection _myViews;
    public ICollection MyViews {
    get { return _myViews;}
    set{ 
       _myViews = value; 
       NotifyPropertyChanged("MyViews");
    }

...
...
}

In this example, I want to bind to MyViews and show all the views in the collection in a stack panel. How should I go and bind it? I'm new to WPF world.

Thanks.

Here's an example of 1 way to do it.

The ItemsControl.ItemsPanel part of the ItemsControl can be removed if you just want the default ItemsPanel template which is a vertical stackpanel - I've just redundantly included it so you can see where your StackPanel actually exists, or if you want to change the StackPanel in some way.

The ItemTemplate is referred to by explicitly by the key name of HasViewItemTemplate, because you can't have the data templates applied implicity because your data items are interface types.

[ You might need to do more work like use a singleton on the MyCarViewThatHasAButton and MyCarViewThatHasAButton, use a better pattern for NotifyPropertyChanged, etc. ]


<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfApplication3="clr-namespace:WpfApplication3" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <WpfApplication3:MainView x:Key="MainView"/>
        <DataTemplate x:Key="HasViewItemTemplate">
            <ContentPresenter Content="{Binding Path=MyView}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ItemsControl Background="Yellow" ItemTemplate="{StaticResource HasViewItemTemplate}" ItemsSource="{Binding Source={StaticResource MainView}, Path=MyViews}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</Window>



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace WpfApplication3
{
    public interface IHasView
    {
        UserControl MyView { get; }
    }

    public class Car : IHasView
    {
        public UserControl MyView
        { 
            get
            {
                // Demo UserControl as prodcued by MyCarViewThatHasAButton

                UserControl ctl = new UserControl();

                ctl.Background = Brushes.Red;

                Button button = new Button();

                button.Content = "a car";

                ctl.Content = button;

                return ctl;
            }
        }
    }

    public class Jeep : IHasView
    {
        public UserControl MyView
        {
            get
            {
                // Demo UserControl as produced by MyJeepViewThatHasATextblock

                UserControl ctl = new UserControl();

                ctl.Background = Brushes.Blue;
                ctl.Width = 50;

                TextBlock textblock = new TextBlock();

                textblock.Text = "a jeep";

                ctl.Content = textblock;

                return ctl;
            }
        }
    }

    public class MainView : INotifyPropertyChanged{

        public MainView()
        {
            ObservableCollection<IHasView> list = new ObservableCollection<IHasView>()
                                                      {
                                                          new Car(),
                                                          new Jeep()
                                                      };

            MyViews = list;
        }

        private ICollection _myViews;
        public ICollection MyViews
        {
            get
            {
                return _myViews;
            }
            set
            { 
               _myViews = value; 
               NotifyPropertyChanged("MyViews");
            }
        }

        private void NotifyPropertyChanged(string p)
        {
            if (PropertyChanged != null)
            {
                PropertyChangedEventArgs e = new PropertyChangedEventArgs(p);

                PropertyChanged(this, e);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM