开发者

Is it possible to dynamically choose which Control to render based on bindable attribute in Silverlight 4?

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>
                                <DataTempla开发者_JAVA百科te>
                                    <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 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜