Как настроить группировку RadioButton в DataTemplate
Я разрабатываю программу динамического конструктора тестов. Для динамического создания и изменения элементов дизайнера используются CollectionView и комбинированный DataTemplate, который определяется как ресурс на уровне страницы.
Сначала перейдем к модели
Этот класс представляет ItemsSource CollectionView, в котором IsGrouped="True"
public class Question : ObservableCollection<IItem>
{
public Question() { }
public Question(IEnumerable<IItem> items) : base(items)
{
}
private string questionName;
public string QuestionName
{
get => questionName;
set => questionName = value;
}
}
Эти классы представляют собой объекты, которые хранятся в классе Question, и на их основе создается DataTemplate.
public class CheckBoxItem : IItem
{
private string text;
public string Text
{
get => text;
set => text = value;
}
private bool correctAnswer = false;
public bool CorrectAnswer
{
get => correctAnswer;
set => correctAnswer = value;
}
public (string, int) IItem;
public bool Compare(object obj)
{
if (obj is CheckBoxItem cb)
{
if (correctAnswer == cb.correctAnswer)
return false;
}
return true;
}
}
public class RadioButtonItem : IItem
{
private string text;
public string Text
{
get => text;
set => text = value;
}
private bool correctAnswer = false;
public bool CorrectAnswer
{
get => correctAnswer;
set => correctAnswer = value;
}
public bool Compare(object obj)
{
if (obj is RadioButtonItem rb)
{
if (correctAnswer == rb.correctAnswer)
return false;
}
return true;
}
}
public class TextItem : IItem
{
private string correctAnswer;
public string CorrectAnswer
{
get => correctAnswer;
set => correctAnswer = value;
}
public bool Compare(object obj)
{
if (obj is TextItem ti)
{
if (correctAnswer == ti.correctAnswer)
return false;
}
return true;
}
}
Сам код представляет собой страницу CreateTestPage, на которой с помощью кнопок можно динамически создавать вопросы класса Question на выбор с помощью CheckBox, RadioButton и Text, а также динамически изменять количество этих элементов.
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ListTemplateCheckBox" x:DataType="model:CheckBoxItem">
<HorizontalStackLayout>
<CheckBox x:Name="ch" IsChecked="{Binding CorrectAnswer, Mode=TwoWay}"/>
<Editor x:Name="ed" IsTextPredictionEnabled="True" Background="Transparent" HorizontalOptions="Fill" IsSpellCheckEnabled="True" Placeholder="Enter your answer" Text="{Binding Text, Mode=TwoWay}"/>
<ImageButton x:Name="RemoveItem" Background="White" Source="/Images/del.png"
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path=RemoveItemCommand}"
CommandParameter="{Binding}"/>
</HorizontalStackLayout>
</DataTemplate>
<DataTemplate x:Key="ListTemplateRadioButton" x:DataType="model:RadioButtonItem">
<HorizontalStackLayout RadioButtonGroup.GroupName="{Binding Source={RelativeSource TemplatedParent}, Path=Context}">
<RadioButton IsChecked="{Binding CorrectAnswer, Mode=TwoWay}"/>
<Editor IsTextPredictionEnabled="True" Background="Transparent" HorizontalOptions="Fill" IsSpellCheckEnabled="True" Placeholder="Enter your answer" Text="{Binding Text, Mode=TwoWay}"/>
<ImageButton x:Name="RemoveItem" Background="White" Source="/Images/del.png"
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path=RemoveItemCommand}"
CommandParameter="{Binding}"/>
</HorizontalStackLayout>
</DataTemplate>
<DataTemplate x:Key="ListTemplateText" x:DataType="model:TextItem">
<HorizontalStackLayout>
<Editor IsTextPredictionEnabled="True" Background="Transparent" HorizontalOptions="Fill" IsSpellCheckEnabled="True" Placeholder="Enter your answer" Text="{Binding CorrectAnswer, Mode=TwoWay}"/>
<ImageButton BackgroundColor="White" x:Name="RemoveItem" Source="/Images/del.png"
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path= RemoveItemCommand}"
CommandParameter="{Binding}"/>
</HorizontalStackLayout>
</DataTemplate>
<templates:CreateTestTemplate x:Key="ItemSelector" CheckBox="{StaticResource ListTemplateCheckBox}"
RadioButton="{StaticResource ListTemplateRadioButton}"
Text="{StaticResource ListTemplateText}"/>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.15*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<VerticalStackLayout Grid.Row="0" HorizontalOptions="Fill">
<Button Text="CreateTest" Command="{Binding CreateTestCommand}"/>
<Editor Text="{Binding Test.Name, Mode=TwoWay}"/>
</VerticalStackLayout>
<CollectionView x:Name="Qestions" Grid.Row="1" ItemsSource="{Binding Test.Questions}"
SelectionMode="None" VerticalOptions="Fill" HorizontalOptions="StartAndExpand" RadioButtonGroup.GroupName="1" IsGrouped="True" ItemTemplate="{StaticResource ItemSelector}">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="model:Question">
<HorizontalStackLayout HorizontalOptions="Fill">
<Editor Placeholder="Enter a question title" Text="{Binding QuestionName}" HorizontalOptions="FillAndExpand"/>
<ImageButton Source="/Images/del.png" Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path= RemoveQuestionCommand}" CommandParameter="{Binding}"/>
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.GroupFooterTemplate>
<DataTemplate x:DataType="vm:CreateTestPageViewModel">
<ImageButton HorizontalOptions="Center" Source="/Images/plus.png" Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path= AddItemCommand}" CommandParameter="{Binding}"/>
</DataTemplate>
</CollectionView.GroupFooterTemplate>
<CollectionView.ItemsLayout>
<LinearItemsLayout RadioButtonGroup.GroupName="1" Orientation="Vertical" BindingContext="{x:Reference Qestions}"/>
</CollectionView.ItemsLayout>
</CollectionView>
<Border Background="White" Grid.Row="{Binding Test.Questions.Count}" StrokeShape="RoundRectangle 25,0,25,0" HorizontalOptions="End" VerticalOptions="Start">
<VerticalStackLayout>
<Button BackgroundColor="Red" Command="{Binding CreateQuestionCheckBoxItemsCommand}"/>
<Button BackgroundColor="Red" Command="{Binding CreateQuestionRadioButtomItemsCommand}"/>
<Button BackgroundColor="Red" Command="{Binding CreateQuestionTextItemsCommand}"/>
</VerticalStackLayout>
</Border>
</Grid>
Я попытался настроить RadioButtonGroup, переопределив
<CollectionView.ItemsLayout>
<LinearItemsLayout RadioButtonGroup.GroupName="1" Orientation="Vertical" BindingContext="{x:Reference Qestions}"/>
</CollectionView.ItemsLayout>
1 был написан в качестве эксперимента, чтобы понять, сгруппированы ли элементы DataTemplate или нет.
Но это не помогло, поскольку элементы DataTemplate не видят элементы страницы, хотя они определены на уровне страницы. Также попробовал x:Reference и RelativeSource для доступа к элементам извне DataTemplate и использовал их {Binding} для привязки группировки непосредственно к родительскому классу вопроса к контейнеру внутри DataTemplate, но не смог получить к ним доступ.
Ответы (1 шт):
<RadioButton IsChecked="{Binding CorrectAnswer, Mode=TwoWay}">
<RadioButton.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type vm:CreateTestPageViewModel}}, Path=RadioButtonChekcedCommand}"
CommandParameter="{Binding}"/>
</RadioButton.GestureRecognizers>
</RadioButton>
[RelayCommand]
private void RadioButtonChekced(RadioButtonItem item)
{
var items = Test.Questions.Single(x => x.Contains(item));
foreach (RadioButtonItem item2 in items)
{
item2.CorrectAnswer = false;
}
item.CorrectAnswer = true;
}