views:

30

answers:

2

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.

A: 

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.

AnthonyWJones
A: 

[This is not an answer. Since I accidently asked the question while not logged in, the Q was put out as by one not registered]

AnthonyWJones' answer above works perfectly when it comes to the showing and hiding the controls based on some bound attribute!!

thanx!

Thomas
The problem is still how to bind to a property within a collection of objects - as is for the TextBox!
Thomas