自己的DataTemplateSelector MVVM

自己的DataTemplateSelector MVVM,mvvm,binding,datatemplate,datatrigger,datatemplateselector,Mvvm,Binding,Datatemplate,Datatrigger,Datatemplateselector,我正在使用MVVM模式和ModelView优先的方法。到目前为止,这很好用。 现在我有了一个UserControl(视图),它应该根据ViewModel中的属性显示各种内容 首先,我尝试用DataTemplates和DataTemplateSelector()解决这个问题,这很好。但是我对这个解决方案不满意,因为我有一个类(重写的DataTemplateSelector),它没有连接到ViewModel,不能从模型中填充 因此,我尝试创建一个自己的TemplateSelector,它使用View

我正在使用MVVM模式和ModelView优先的方法。到目前为止,这很好用。 现在我有了一个UserControl(视图),它应该根据ViewModel中的属性显示各种内容

首先,我尝试用DataTemplates和DataTemplateSelector()解决这个问题,这很好。但是我对这个解决方案不满意,因为我有一个类(重写的DataTemplateSelector),它没有连接到ViewModel,不能从模型中填充

因此,我尝试创建一个自己的TemplateSelector,它使用ViewModel中的属性。不幸的是,DataTrigger没有触发。从复选框到ViewModel的绑定也在工作,但不在DataTrigger处(即使设计者也找不到该路径)

好的,请看一下代码:

<UserControl.Resources>     
        <!--Define Template which is displayed for Users-->
        <DataTemplate x:Key="templateUser">     
            <Image 
                Name="logo"
                Source="blanked out"
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" />
        </DataTemplate>

        <!--Define Template which is displayed for Administrators-->
        <DataTemplate x:Key="templateAdmin">
            <TextBlock Background="Yellow" Margin="3" Text="YEAH, I'm an Administrator" />
        </DataTemplate>

        <!--My own TemplateSelectpr-->
        <DataTemplate x:Key="myTemplateSelector">
            <ContentControl x:Name="DynamicContent" ContentTemplate="{StaticResource templateUser}"/>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=IsAdministrator}" Value="true">
                    <Setter TargetName="DynamicContent" Property="ContentTemplate" Value="{StaticResource templateAdmin}" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
            <ContentPresenter ContentTemplate="{StaticResource myTemplateSelector}"/>
    </Grid> 

当然,我可以在两个进一步的contentcontrols中分离任务,但是如果相同的内容相交,我不想维护它们。 有人能提出什么建议吗


致以最良好的问候,并提前表示感谢

越简单越好:使用一个模板,其中包含需要显示的所有控件。然后使用绑定将其可见性切换到您的属性:

<UserControl.Resources>
    <DataTemplate x:Key="myTemplate">
      <Grid>
        <Grid Visibility="{Binding IsAdministrator, Converter={StaticResource BooleanToVisibilityConverter}}">
           <!-- Content for admin -->
        </Grid>
        <Grid Visibility="{Binding IsAdministrator, Converter={StaticResource NotBooleanToVisibilityConverter}}">
           <!-- Content for user -->
        </Grid>
      </Grid>
    </DataTemplate>
</UserControl.Resources>

<Grid>
        <ContentPresenter ContentTemplate="{StaticResource myTemplate}"/>
</Grid> 

答案是渴望得到评论 Arnaud Weil让我走上了正确的道路:

要从Datatemplate访问ViewModel中的属性“IsAdministrator”,我为UserControl指定了一个名称,例如:

<UserControl    
    x:Class="blanked out"
    x:Name="this"
再次感谢Arnaud Weil


关于XAML代码:

<UserControl x:Class="ExamSystemWithoutPrism.Views.QuestionsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ExamSystemWithoutPrism.Views"
             mc:Ignorable="d" 
             xmlns:template="clr-namespace:ExamSystemWithoutPrism.Helpers"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <ResourceDictionary>
            <template:QuestionOptionTemplateSelector x:Key="questionOptionTemplateSelector"/>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="45"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Margin="5" DataContext="{Binding SelectedQuestionAnswerModel}">
            <WrapPanel Margin="0,0,0,20">
                <TextBlock Text="{Binding SequenceNumber}" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,0,3,0"/>
                <TextBlock Text="{Binding Question}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
            </WrapPanel>
            <ItemsControl ItemsSource="{Binding QuestionOptions}" HorizontalAlignment="Left" VerticalAlignment="Top">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter ContentTemplateSelector="{StaticResource questionOptionTemplateSelector}" Content="{Binding}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button x:Name="btnPrevious" Content="Previous" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding PreviousCommand}"/>
            <Button x:Name="btnNext" Content="Next" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding NextCommand}"/>
            <Button x:Name="btnReview" Content="Review" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding ReviewCommand}"/>
            <Button x:Name="btnSubmit" Content="Submit" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding SubmitCommand}"/>
        </StackPanel>
    </Grid>
</UserControl>
public class QuestionOptionTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate dataTemplate = null;
        FrameworkElement frameworkElement = container as FrameworkElement;
        if (frameworkElement != null && item != null)
        {
            var questionOption = item as QuestionOption;
            var optionType = (OptionType)Enum.Parse(typeof(OptionType), questionOption.OptionType.ToString());
            switch (optionType)
            {
                case OptionType.Checkbox:
                    dataTemplate = frameworkElement.FindResource("CheckBoxTemplate") as DataTemplate;
                    break;
                case OptionType.Radiobutton:
                    dataTemplate = frameworkElement.FindResource("RadioButonTemplate") as DataTemplate;
                    break;
            }
        }
        return dataTemplate;
    }
}

谢谢,在实现了这两个转换器以及绑定到一个复选框(该复选框绑定到它正在工作的属性)之后。我不知道为什么,但我不能直接绑定到IsAdministrator属性。如果我这样做,两个网格将同时显示不客气。您的第二个问题可能是由于您的财产未通知。是否在set方法中引发INotifyPropertyChanged.PropertyChanged事件?不,就像我告诉过你的那样:如果我将复选框绑定到正在工作的属性(InotifyPC已实现),则在绑定到ElementName=checkbox Path=IsChecked的可见性后,一切都正常工作!我正在做;)然后在调试输出中查找绑定错误。很可能该属性在早期调用时引发了异常。Florian,我意识到我忽略了一个事实,即该属性位于ViewModel本身,而不是列表中的业务对象上,这正是我所假设的。这就是为什么在访问绑定表达式中的属性时需要重写默认DataContext。下次我会读得更好。。。
<UserControl x:Class="ExamSystemWithoutPrism.Views.QuestionsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ExamSystemWithoutPrism.Views"
             mc:Ignorable="d" 
             xmlns:template="clr-namespace:ExamSystemWithoutPrism.Helpers"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <ResourceDictionary>
            <template:QuestionOptionTemplateSelector x:Key="questionOptionTemplateSelector"/>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="45"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Margin="5" DataContext="{Binding SelectedQuestionAnswerModel}">
            <WrapPanel Margin="0,0,0,20">
                <TextBlock Text="{Binding SequenceNumber}" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,0,3,0"/>
                <TextBlock Text="{Binding Question}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
            </WrapPanel>
            <ItemsControl ItemsSource="{Binding QuestionOptions}" HorizontalAlignment="Left" VerticalAlignment="Top">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter ContentTemplateSelector="{StaticResource questionOptionTemplateSelector}" Content="{Binding}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button x:Name="btnPrevious" Content="Previous" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding PreviousCommand}"/>
            <Button x:Name="btnNext" Content="Next" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding NextCommand}"/>
            <Button x:Name="btnReview" Content="Review" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding ReviewCommand}"/>
            <Button x:Name="btnSubmit" Content="Submit" Width="100" Height="27" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" Command="{Binding SubmitCommand}"/>
        </StackPanel>
    </Grid>
</UserControl>
public class QuestionOptionTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate dataTemplate = null;
        FrameworkElement frameworkElement = container as FrameworkElement;
        if (frameworkElement != null && item != null)
        {
            var questionOption = item as QuestionOption;
            var optionType = (OptionType)Enum.Parse(typeof(OptionType), questionOption.OptionType.ToString());
            switch (optionType)
            {
                case OptionType.Checkbox:
                    dataTemplate = frameworkElement.FindResource("CheckBoxTemplate") as DataTemplate;
                    break;
                case OptionType.Radiobutton:
                    dataTemplate = frameworkElement.FindResource("RadioButonTemplate") as DataTemplate;
                    break;
            }
        }
        return dataTemplate;
    }
}