Question

My small objective is to implement a dynamic on-the-go generation of controls and associate their respective properties, such as Visibility and IsEnabled.

The controls must be inserted into the StackPanel. And based on some conditions, the children nodes properties would change. I've used the following nasted StackPanel structure:

  1. The Parent StackPanel with Vertical orientation of Children (collection of Labels ad input Fields to simulate a form)
  2. The Child node StackPanel with Horizontal orientation of Children (Label and an input field)

The main idea is that there is only one input field per each label: Date Picker, Combo, Text or any other. As result, I created a Label and a Grid with multiple Controls. I manipulate Visibility and IsEnabled properties of the input controls via Converters.

Here is the question: is it possible to implement all these by other means (more efficient/aesthetic)? Constructive criticism and suggestions are more than welcome :)

Thank you in advance.

XAML:

<StackPanel Grid.Row="1" Orientation="Vertical">
    <ItemsControl ItemsSource="{Binding DataClass}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" Margin="0, 5, 0, 0" >
                    <Label Content="{Binding KeyName}" Width="150"/>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="190"/>
                        </Grid.ColumnDefinitions>
                        <DatePicker Text="{Binding Value}"
                            Visibility="{Binding Type, Converter={StaticResource TypeVisiblity}, ConverterParameter='DateTime'}"
                            IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource VisibilityEnabled}}"/>
                        <ComboBox Text="{Binding Value}" 
                            Visibility="{Binding Type, Converter={StaticResource TypeVisiblity}, ConverterParameter='Lookup'}"
                            IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource VisibilityEnabled}}"/>
                        <TextBox Text="{Binding Value}" 
                            Visibility="{Binding Type, Converter={StaticResource TypeVisiblity}, ConverterParameter='Number'}"
                            IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource VisibilityEnabled}}"/>
                        <TextBox Text="{Binding Value}" 
                            Visibility="{Binding Type, Converter={StaticResource TypeVisiblity}, ConverterParameter='Text'}"
                            IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource VisibilityEnabled}}"/>
                    </Grid>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

Visibility Converter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool isMatched;
        string type,
               controlType;

        // Safe Convert.
        type = System.Convert.ToString(value);
        controlType = System.Convert.ToString(parameter);

        if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(controlType))
        {
            return Visibility.Hidden;
        }

        // Check matching.
        isMatched = string.Equals(type, controlType, StringComparison.CurrentCultureIgnoreCase);

        return isMatched ? Visibility.Visible : Visibility.Hidden;
    }

IsEnabled Converter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    Control control;

    control = value as Control;

    if (control == null)
    {
        return false;
    }

    return control.Visibility == Visibility.Visible;
}
Was it helpful?

Solution

I would use a ContentControl and set the ContentTemplate in a style

<ContentControl>
    <ContentControl.Style>
        <Style TargetType="{x:Type ContentControl}">
            <!-- Default Template -->
            <Setter Property="ContentTemplate" 
                    Value="{DynamicResource TextBoxTemplate}" />

            <Style.Triggers>
                <DataTrigger Binding="{Binding Type}" Value="DateTime">
                    <Setter Property="ContentTemplate" 
                            Value="{DynamicResource DateTimeTemplate}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Type}" Value="Lookup">
                    <Setter Property="ContentTemplate" 
                              Value="{DynamicResource ComboBoxTemplate}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

OTHER TIPS

Create a user control that has your DatePicker, ComboBox, TextBox etc as user interface and implement all necessary logic in code behind of this user control. You can add dependency properties to implement your logic without converters.

You can add your user control into StackPanel easily by adding it into its Children property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top