-1

I am working on program that use wpf with design of mvvm. I have a collection of Control, each item can be Button\RadioButton\TextBox ...

ObservableCollection<Control> controls_lst = new ...

I want to iterate over this list by the xaml code of the view, and create and display each control. but the problem is that i need to check the type before i write

there is a way to iterate over this list and create and display the control by checking the type from the xaml ? i

  • ObservableCollection is not mvvm ;). check this https://stackoverflow.com/questions/11095189/adding-controls-dynamically-in-wpf-mvvm answer here to get an understanding. – blindmeis Mar 09 '20 at 14:16
  • You would usually have an ObservableCollection with different types of data items. Then declare a DataTemplate for each type of data item, and bind the ItemsSource property of an ItemsControl to the ObservableCollection. Start reading here: [Data Templating Overview](https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/data-templating-overview). – Clemens Mar 09 '20 at 14:18
  • Why do you need to check the type? – BionicCode Mar 11 '20 at 09:48

1 Answers1

0
  1. You should never define collections of controls or any other UI element. If this collection is defined in a view model, this would also violate the MVVM pattern. A collection of controls eliminates all the flexibility to create controls dynamically.

    The recommended way is to define item models and let them dynamically render with the help of a corresponding DataTemplpate and an ItemsControl:

    Data model definitions

    // Common base type
    interface ISelectorItem
    {
      public string Text { get; set; }
    }
    
    // Model to represent a ToggleButton
    class BooleanItem : ISelectorItem
    {
    }
    

    ViewModel.cs

    class ViewModel
    {
      public ObservableCollection<ISelectorItem> DataModels { get; set; }
    
      public ViewModel()
      {
        this.DataModels = new ObservableCollection<ISelectorItem>() { new BooleanItem() { Text = "Click Me"}};
      }
    }
    

    MainWindow.xaml

    <Window>
      <Window.DataContext>
        <ViewModel />
      </Window.DataContext>
    
      <Window.Resources>
        <DataTemplate DataType="{x:Type BooleanItem}">
          <ToggleButton Content="{Binding Text}" />
        </DataTemplate>
      </Window.Resources>
    
      <ListView ItemsSource="{Binding DataModels}" />
    </Window>
    

  1. You can use a DataTrigger in conjunction with a custom type converter (also works with solution 1):

    Implementation of TypeConverter (IValueConverter)

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
      => value.GetType();
    

    View implementation

    <ListView ItemsSource="{Binding CollectionWithControls}">
      <ListView.Resources>
        <TypeConverter x:Key="TypeConverter" />
      </ListView.Resources>
      <ListView.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
          <Style.Triggers>
            <DataTrigger Binding="{Binding Path=., Converter={StaticResources TypeConverter}} 
                         Value="{x:Type RadioButton}">
              <Setter ... />
            </DataTrigger>
          </Style.Triggers>
        </Style>
      <ListView.ItemContainerStyle>
    </ListView>
    

  1. Use DataTemplate:

    <ListView ItemsSource="{Binding CollectionWithControls}">
      <ListView.Resources>
        <DataTemplate DataType="{x:Type RadioButton}">
    
          <!-- Type specific layout -->
          ...
        </DataTemplate>
      </ListView.Resources>
    </ListView>
    
BionicCode
  • 1
  • 4
  • 28
  • 44