条件数据模板 returns 对象
Conditional DataTemplate returns object
对于一个学校项目,我需要一个问题对象的选择性模板。根据其类型,我必须显示不同的类型(类型为:开放式、多项选择和封闭式)
我定义的模板如下
<ResourceDictionary>
<UserControl.Resources>
<DataTemplate x:Key="Open" >
<WrapPanel>
<Label Content="Open"/>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="multipleChoice" >
<WrapPanel>
<Label Content="multipleChoice"/>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="Closed" >
<WrapPanel>
<Label Content="Closed"/>
</WrapPanel>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
如您所见,它现在只包含一个测试标签。
为了展示,我使用 ItemsControl
和设置器。基于此处在 Whosebug 上显示的另一个示例。但是这个例子 returns 对我来说是 System.Data.Entity.DynamicProxies
,我不知道为什么。注释代码有效,因此可以访问属性。
<ItemsControl ItemsSource="{Binding SelectedInspection.Questionaire.Questions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding type}" Value="Open">
<Setter Property="ContentTemplate"
Value="{StaticResource Open}" />
</DataTrigger>
<DataTrigger Binding="{Binding type}" Value="multipleChoice">
<Setter Property="ContentTemplate"
Value="{StaticResource multipleChoice}" />
</DataTrigger>
<DataTrigger Binding="{Binding type}" Value="Closed">
<Setter Property="ContentTemplate"
Value="{StaticResource Closed}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
<!--
<DataTemplate>
<WrapPanel>
<Label Content="{Binding Path=QuestionContent}" />
</WrapPanel>
</DataTemplate>
-->
</ItemsControl.ItemTemplate>
</ItemsControl>
我正在绑定我的问题模型,它看起来像这样
public class Question
{
public Question()
{
this.Answers = new ObservableCollection<Answer>();
}
[Key]
public virtual int Id { get; set; }
public String QuestionContent { get; set; }
public string OpenAnswer { get; set; }
public string type { get; set; }
public virtual ObservableCollection<Answer> Answers { get; set; }
public virtual Questionaire Questionaire { get; set; } }
}
我是不是做错了什么?我该如何解决这个问题?
更新:已解决。给定的示例工作正常。数据库给的数据不正确导致错误。
DataTemplates 旨在与类型一起使用...如 System.Type
中所示。它们是交换 UI 元素的简单方法,旨在与特定类型进行交互。你正在做的可能是滥用这一点。原因如下。
为了以这种方式使用 DataTemplates,您必须重构它(我认为您有)
enum TestType { open, multiplechoice, closed }
class Mahveurmerder // view model
{
public TestType type {get;set;}
// snip
}
但是,为了正确使用数据模板,您必须将测试类型表示为实际类型。这就是我的意思:
// describes a type of test
abstract class TestType { }
// implementations of this type
class OpenBookTest : TestType {}
class ClosedBookTest : TestType {}
class MultipleTypeTest : TestType {}
并且您必须通过视图模型属性公开此类型的实例
class Mahveurmerder
{
public TestType type {get;set;}
}
一旦您在模板上指定了数据类型:
<DataTemplate
xmlns:models="clr-namespace:ermagerdmerassinmernt.models"
DataType="{x:Type OpenBookTest:}" >
<WrapPanel>
<Label Content="Open"/>
</WrapPanel>
</DataTemplate>
ItemsControl 会自动拾取它们(是的,就这么简单)
<ItemsControl ItemsSource="{Binding SelectedInspection.Questionaire.Questions}" />
注意,ItemsControl 元素已关闭。没有数据触发 BS 塞在它和它的结束标签之间。
现在,当然,正确的方法来做你想做的事情是使用IValueConverter 将 type
(我希望这是您的应用程序中的枚举)转换为字符串表示形式。这个的实现将是七八行,而且非常琐碎。你可以在这里找到很多例子,所以我会留给你去发现。
那么,您需要做的就是
<!-- up in your window's or app's Resources -->
<converters:MerTestTyerpCernverter x:Name="Duh" />
在你的 ItemsControl.ItemTemplate 中(摆脱所有其他废话)
<Label Content="{Binding type, converter={StaticResource Duh}}"/>
一旦您理解了模式,WPF 就非常容易了。如果您陷入困境,请停下来重新考虑您正在做的事情——可能有更简单的方法。
type
属性是怎么设置的?您能否验证这些值是否符合您的预期?
根据对象模型和您关于绑定到 QuestionContent
的声明,看起来您的 DataContext 层次结构设置正确,因此最可能的问题原因是数据本身。
我还注意到您没有在对象模型上实现 INotifyPropertyChanged
,因此如果它是在对象绑定到之后设置的,那么 UI 将不知道它需要刷新。
对于一个学校项目,我需要一个问题对象的选择性模板。根据其类型,我必须显示不同的类型(类型为:开放式、多项选择和封闭式)
我定义的模板如下
<ResourceDictionary>
<UserControl.Resources>
<DataTemplate x:Key="Open" >
<WrapPanel>
<Label Content="Open"/>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="multipleChoice" >
<WrapPanel>
<Label Content="multipleChoice"/>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="Closed" >
<WrapPanel>
<Label Content="Closed"/>
</WrapPanel>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
如您所见,它现在只包含一个测试标签。
为了展示,我使用 ItemsControl
和设置器。基于此处在 Whosebug 上显示的另一个示例。但是这个例子 returns 对我来说是 System.Data.Entity.DynamicProxies
,我不知道为什么。注释代码有效,因此可以访问属性。
<ItemsControl ItemsSource="{Binding SelectedInspection.Questionaire.Questions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding type}" Value="Open">
<Setter Property="ContentTemplate"
Value="{StaticResource Open}" />
</DataTrigger>
<DataTrigger Binding="{Binding type}" Value="multipleChoice">
<Setter Property="ContentTemplate"
Value="{StaticResource multipleChoice}" />
</DataTrigger>
<DataTrigger Binding="{Binding type}" Value="Closed">
<Setter Property="ContentTemplate"
Value="{StaticResource Closed}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
<!--
<DataTemplate>
<WrapPanel>
<Label Content="{Binding Path=QuestionContent}" />
</WrapPanel>
</DataTemplate>
-->
</ItemsControl.ItemTemplate>
</ItemsControl>
我正在绑定我的问题模型,它看起来像这样
public class Question
{
public Question()
{
this.Answers = new ObservableCollection<Answer>();
}
[Key]
public virtual int Id { get; set; }
public String QuestionContent { get; set; }
public string OpenAnswer { get; set; }
public string type { get; set; }
public virtual ObservableCollection<Answer> Answers { get; set; }
public virtual Questionaire Questionaire { get; set; } }
}
我是不是做错了什么?我该如何解决这个问题?
更新:已解决。给定的示例工作正常。数据库给的数据不正确导致错误。
DataTemplates 旨在与类型一起使用...如 System.Type
中所示。它们是交换 UI 元素的简单方法,旨在与特定类型进行交互。你正在做的可能是滥用这一点。原因如下。
为了以这种方式使用 DataTemplates,您必须重构它(我认为您有)
enum TestType { open, multiplechoice, closed }
class Mahveurmerder // view model
{
public TestType type {get;set;}
// snip
}
但是,为了正确使用数据模板,您必须将测试类型表示为实际类型。这就是我的意思:
// describes a type of test
abstract class TestType { }
// implementations of this type
class OpenBookTest : TestType {}
class ClosedBookTest : TestType {}
class MultipleTypeTest : TestType {}
并且您必须通过视图模型属性公开此类型的实例
class Mahveurmerder
{
public TestType type {get;set;}
}
一旦您在模板上指定了数据类型:
<DataTemplate
xmlns:models="clr-namespace:ermagerdmerassinmernt.models"
DataType="{x:Type OpenBookTest:}" >
<WrapPanel>
<Label Content="Open"/>
</WrapPanel>
</DataTemplate>
ItemsControl 会自动拾取它们(是的,就这么简单)
<ItemsControl ItemsSource="{Binding SelectedInspection.Questionaire.Questions}" />
注意,ItemsControl 元素已关闭。没有数据触发 BS 塞在它和它的结束标签之间。
现在,当然,正确的方法来做你想做的事情是使用IValueConverter 将 type
(我希望这是您的应用程序中的枚举)转换为字符串表示形式。这个的实现将是七八行,而且非常琐碎。你可以在这里找到很多例子,所以我会留给你去发现。
那么,您需要做的就是
<!-- up in your window's or app's Resources -->
<converters:MerTestTyerpCernverter x:Name="Duh" />
在你的 ItemsControl.ItemTemplate 中(摆脱所有其他废话)
<Label Content="{Binding type, converter={StaticResource Duh}}"/>
一旦您理解了模式,WPF 就非常容易了。如果您陷入困境,请停下来重新考虑您正在做的事情——可能有更简单的方法。
type
属性是怎么设置的?您能否验证这些值是否符合您的预期?
根据对象模型和您关于绑定到 QuestionContent
的声明,看起来您的 DataContext 层次结构设置正确,因此最可能的问题原因是数据本身。
我还注意到您没有在对象模型上实现 INotifyPropertyChanged
,因此如果它是在对象绑定到之后设置的,那么 UI 将不知道它需要刷新。