WPF MVVM Binding dynamic control in code behind an

2019-03-06 22:36发布

问题:

I am working on WPF application using MVVM. I have two page. I have multiple UserControls in a page 1, on selection of UserControls from page 1, I want to show that selected userControl in 2nd page. Below are my code.

ViewModel Code

public RelayCommand<string> OnClickSelectWidgetCommand => new RelayCommand<string>((setUserControlName) =>
    {
        using (new CursorWait())
        {
            var MyContentControl = setUserControlName;
            MessageBox.Show(MyContentControl);

            //How to render UserControl to View?
        }

    }, true);

Here in above code I get the UserControl name in setUserControlName variable. Now how to bind that UserControl to XAML page? Below are my code that I have tried.

View Code

<StackPanel Background="Black" VerticalAlignment="Top">
<Border Name="UserControl1BorderLow" BorderBrush="White" BorderThickness="0" >
    <ItemsControl ItemsSource="{Binding LowCollection}" Margin="4,0" >
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel HorizontalAlignment="Left" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <controls:UserControlColumn1XL HorizontalAlignment="Left" Margin="2" />
                <!--what can I do here in above line to make it dynamically render the userControl in place of UserControlColumn1XL-->
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Border></StackPanel>

Above code, In DataTemplate what need to be change to bind UserControls dynamically?

回答1:

There are two ways to solve this, one involves setting the template based on your data type (DataTemplates) and the second involves setting it based on the data itself (DataTriggers).

In the first case your LowCollection should be an array of objects, or some base class that your view models are all derived from (ViewModel1, ViewModel2 etc). In this case you can get rid of your itemtemplate altogether and just add DataTemplates to specify how each of the items in your ItemsControl should be represented:

<ItemsControl.Resources>

    <DataTemplate DataType="{x:Type local:ViewModel1}">
        <UserControl1 />
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:ViewModel2}">
        <UserControl2 />
    </DataTemplate>

    ... etc...

In the second case you need to set a template based on the value of some property in your view model. In this case you do need to set the ItemTemplate, and you give it a Style which uses data triggers to set an appropriate DataTemplate:

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding}">
                <ContentPresenter.Style>
                    <Style TargetType="{x:Type ContentPresenter}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding YourProperty}" Value="YourValue1">
                                <Setter Property="ContentTemplate" Value="{StaticResource YourDataTemplate1}" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding YourProperty}" Value="YourValue2">
                                <Setter Property="ContentTemplate" Value="{StaticResource YourDataTemplate2}" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentPresenter.Style>
            </ContentPresenter>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

The relevant parts to note here are that there is a property in your view model called YourProperty which can have two values i.e. YourValue1 or YourValue2; the style above then selects either YourDataTemplate1 or YourDataTemplate2, depending on the value of YourProperty.