Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
436 views
in Technique[技术] by (71.8m points)

.net - WPF MVVM Creating Dynamic controls

WPF MVVM Creating Dynamic controls - I have a grid on which I have a job's (you can say something like a sql server job) details.

Now for every job there could be 'n' number of job variables. When I fetch the record for a job it gets this collection of Job variables which are Name-value pair, where value could be a collection or a datetime value or even an int or a string.

Now what I am trying to achieve here is : -- If the run variable is a datetime then I need a datepicker -- If it is a int/String I need a text box -- If it is a collection then a combo box . -- it it is a bit field then a check box

I am not sure how to achieve it since these values can differ for every single job.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I am assuming that you will put some kind of objects representing these name/value pairs into an ItemsControl by setting its ItemsSource property.

There are a couple of solutions you can use.

Using a DataTemplate with triggers:

This approach involves exposing the "type" of each of your objects through the YourPropertyType property as a string. You will set the ItemTemplate of your ItemsControl to a template which hosts a ContentControl. The ContentControl itself will have its ContentTemplate selected dynamically with triggers.

All of this can be done declaratively in XAML.

I am assuming you have further DataTemplates named DefaultTemplate (this can be empty), IntegerTemplate, StringTemplate, etc to sketch out the visual tree for each case.

This would then be the ItemsControl.ItemTemplate:

<DataTemplate>
    <ContentControl
        x:Name="MyContentControl"
        Content="{Binding}"
        ContentTemplate="{StaticResource DefaultTemplate}"/>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding YourPropertyType}" Value="Integer">
            <Setter TargetName="MyContentControl" Property="ContentTemplate"
                    Value="{StaticResource IntegerTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding YourPropertyType}" Value="String">
            <Setter TargetName="MyContentControl" Property="ContentTemplate"
                    Value="{StaticResource StringTemplate}" />
        </DataTrigger>
        <!-- and so on -->
    </DataTemplate.Triggers>
</DataTemplate>

Using a DataTemplateSelector:

This approach requires code-behind, but it does not force you to expose the "type" of each name/value pair as a string and it allows you to choose which template to use with much more complex logic.

It involves creating a class to be the template selector:

class YourObjectDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var yourObject = (YourObjectType) item;

        // Get hold of a DataTemplate based on any attribute of item
        var templateToUse = this.DefaultTemplate;

        return templateToUse;
    }
}

Then, you need to instantiate a template selector somewhere (let's say inside your UserControl)

<UserControl.Resources>
    <localNamespace:YourObjectDataTemplateSelector
      x:Key="TemplateSelector"
      DefaultTemplate="{StaticResource DefaultTemplate}"
    />
</UserControl.Resources>

Notice that I exposed a DefaultTemplate property from YourObjectDataTemplateSelector and set that to a template from XAML. In practice, you would define more properties of type DataTemplate on YourObjectDataTemplateSelector, and "configure" the template selector when adding it into the resource dictionary of your control. This allows you to directly set the templates for each case using the StaticResource markup extension from XAML.

Finally, wire the template selector to your ItemsControl:

<ItemsControl 
  ItemsSource="..."
  ItemTemplateSelector={StaticResource TemplateSelector}"
/>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...