问题
I have a ListBox with an ItemTemplate which renders a Grid with two columns. The first column is a TextBlock and the second is a ComboBox.
The idea is to present to the user a list of questions and a Combo from which the user can choose an answer. This works ok with this xaml:
<ListBox x:Name="QAListBox" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedIndex="-1" ItemsSource="{Binding Questions}" IsTabStop="True" TabIndex="5" ScrollViewer.HorizontalScrollBarVisibility="Auto" Margin="10" BorderThickness="0"> <ListBox.ItemTemplate> <DataTemplate> <Grid d:DesignWidth="931" d:DesignHeight="61" d:IsLocked="True" Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width=".80*" MinWidth="800"/> <ColumnDefinition Width=".20*" MinWidth="200"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Path=QuestionText}" Padding="10" FontSize="21.333" FontWeight="Bold" Margin="0" Grid.Column="0" d:IsLocked="True" /> <ComboBox ItemsSource="{Binding Path=AnswerAlternative}" SelectedValue="{Binding Path=QuestionsAndAnswers}" SelectedValuePath="AnswerAlternativeId" FontSize="21.333" FontWeight="Bold" Grid.Column="1" Margin="60,0,0,0" d:IsLocked="True" SelectionChanged="ComboBox_SelectionChanged"> <ComboBox.ItemTemplate> <DataTemplate> <TextBox Text="{Binding Path=AnswerText, Mode=TwoWay}" BorderThickness="0"> <TextBox.Background> <SolidColorBrush /> </TextBox.Background> </TextBox> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
The reason for putting a TextBox inside the DataTemplate (in stead of TextBlock), is my first attempt on allowing the user to enter free text in addition to choosing from the dropdown. It kind of work, however, the TextBox is inside the ComboBox. That is not what I want.
Is it possible to have a "plain" TextBox render in stead of a ComboBox based upon some bindable attribute?
So that if an attribute InputType==FreeText the view is rendered with a TextBox and if the attribute is Inputtype==Combo it is rendered as above?
t.
回答1:
A simplistic solution to your specific problem is to include both and use a value converter on the Visibility property:-
public class EqualityToValueConverter<T> : IValueConverter
{
public T FalseValue { get; set; }
public T TrueValue { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return FalseValue;
else
return value.ToString().Equals(parameter) ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value != null && value.Equals(TrueValue) ? parameter : null;
}
}
public class EqualityToVisibilityConverter : EqualityToValueConverter<Visibility> { }
Then your Xaml can look like:-
<ListBox x:Name="QAListBox" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedIndex="-1"
ItemsSource="{Binding Questions}" IsTabStop="True" TabIndex="5"
ScrollViewer.HorizontalScrollBarVisibility="Auto" Margin="10" BorderThickness="0">
<ListBox.Resources>
<local:EqualityToVisibilityConverter x:Key="converter"
TrueValue="Visible" FalseValue="Collapsed" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid d:DesignWidth="931" d:DesignHeight="61" d:IsLocked="True" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".80*" MinWidth="800"/>
<ColumnDefinition Width=".20*" MinWidth="200"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=QuestionText}" Padding="10" FontSize="21.333" FontWeight="Bold" Margin="0" Grid.Column="0" d:IsLocked="True" />
<ComboBox ItemsSource="{Binding Path=AnswerAlternative}"
SelectedValue="{Binding Path=QuestionsAndAnswers}" SelectedValuePath="AnswerAlternativeId"
FontSize="21.333" FontWeight="Bold" Grid.Column="1" Margin="60,0,0,0" d:IsLocked="True" SelectionChanged="ComboBox_SelectionChanged"
Visibility={Binding InputType, Converter={StaticResource converter}, ConverterParameter=Combo}">
<TextBox Text="{Binding Path=AnswerText, Mode=TwoWay}" Grid.Column="1" Margin="60,0,0,0"
Visibility={Binding InputType, Converter={StaticResource converter}, ConverterParameter=FreeText}">
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
More sophisticated solutions would use a sub-class of ListBox
and an override or PrepareContainerForItemOverride
to allow variety of ItemTemplates to be assigned. However I think that would be overkill for this problem.
来源:https://stackoverflow.com/questions/3841943/is-it-possible-to-dynamically-choose-which-control-to-render-based-on-bindable-a