I have a CollectionView with some controls in <CollectionView.GroupHeaderTemplate>, two of then are ImageButton. I would like to change the source if I have sound or not. The next is my code:
<CollectionView x:Name="lvWords" Grid.Row="3" Grid.Column="0" ZIndex="6" Grid.ColumnSpan="7" Background="Transparent" ItemsSource="{Binding WordsGroups}" IsGrouped="True" SelectionChanged="lvWords_SelectionChanged" SelectionMode="Single">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" Margin="5,0,0,0">
<Label Text="{Binding Name}" TextColor="White" VerticalOptions="CenterAndExpand" BackgroundColor="Transparent" FontSize="24" FontAttributes="Bold" />
<Label Text="W" TextColor="Black" BackgroundColor="Transparent" FontSize="14" VerticalTextAlignment="Start" HorizontalTextAlignment="End" VerticalOptions="Start" HorizontalOptions="End"/>
<Label Text="{Binding Ipauk}" TextColor="LightGray" VerticalOptions="CenterAndExpand" BackgroundColor="Transparent" FontSize="18" FontAttributes="Italic" />
<ImageButton x:Name="imgbUk1" ZIndex="4" Margin="5,0,0,0" BackgroundColor="Transparent" CornerRadius="0" Source="uk_sound.png" HeightRequest="48" WidthRequest="48" Clicked="imgbUk_Clicked"/>
<ImageButton x:Name="imgbUs1" ZIndex="5" Margin="5,0,0,0" BackgroundColor="Transparent" CornerRadius="0" Source="us_sound.png" HeightRequest="48" WidthRequest="48" Clicked="imgbUs1_Clicked"/>
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*" />
<ColumnDefinition Width = "*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
<RowDefinition Height = "*"/>
<RowDefinition Height = "10"/>
</Grid.RowDefinitions>
<StackLayout Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Margin="20,0,0,0">
<Label Text="(" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="14" VerticalTextAlignment="End" HorizontalTextAlignment="Start" VerticalOptions="End" HorizontalOptions="Start"/>
<Label Text="{Binding Type}" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="14" VerticalTextAlignment="End" HorizontalTextAlignment="Center" VerticalOptions="End" HorizontalOptions="Center"/>
<Label Text=")" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="14" VerticalTextAlignment="End" HorizontalTextAlignment="End" VerticalOptions="End" HorizontalOptions="End"/>
<Label Text="{Binding Translation}" TextColor="Wheat" Margin="20,0,0,0" BackgroundColor="Transparent" FontSize="14" VerticalTextAlignment="End" HorizontalTextAlignment="Center" VerticalOptions="End" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Horizontal" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="30,0,0,0">
<Label Text="(" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="18" HorizontalTextAlignment="Start" VerticalOptions="Start" HorizontalOptions="Start"/>
<Label Text="{Binding Level}" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="18" HorizontalTextAlignment="Start" VerticalOptions="Start" HorizontalOptions="Start"/>
<Label Text=")" TextColor="GreenYellow" BackgroundColor="Transparent" FontSize="18" HorizontalTextAlignment="Start" VerticalOptions="Start" HorizontalOptions="Start"/>
<Label Text="{Binding Mainmeaning}" Margin="10,0,0,0" TextColor="White" BackgroundColor="Transparent" FontSize="18" HorizontalTextAlignment="Start" VerticalOptions="Start" HorizontalOptions="Start"/>
</StackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
My idea is to change the IsEnabled property in imgbUk1 and imgbUs1 depending on whether I have sound or not, but my problem is that I don’t know how to access imgbUk1 and imgbUs1 control from my code C#:
List<Words> list = new List<Words>();
// First, Group the words to add to the CollectionView
var dict = words.GroupBy(o => o.Word).ToDictionary(g => g.Key, g => g.ToList());
// Get the the words to find the pronuntation's sound into the Data Base.
List<string> _words_list = dict.Keys.ToList();
sounds = await _iWord_SoundsRepository.GetGroupWords_Sound(_words_list);
WordsGroups = new List<WordsGroup>();
foreach (KeyValuePair<string, List<Words>> item in dict)
{
WordsGroups.Add(new WordsGroup(item.Key, new List<Words>(item.Value), " /" + item.Value[0].IPAUK + "/ " + " /" + item.Value[0].IPAUS + "/", new List<Words>(item.Value)));
// In this point, if the Header word has sound I wnant:
var sound = sounds.Where(q => q.Word == item.Key.ToString()).Select(x => x.Sound1);
if (sound==null)
imgbUks1.IsEnabled= false;
sound = sounds.Where(q => q.Word == item.Key.ToString()).Select(x => x.Sound2);
if (sound == null)
imgbUs1.IsEnabled = false;
}
lvWords.ItemsSource = WordsGroups;
lblStatus.Text = "Fouund Words:" + dict.Count.ToString();
In this code, the error I get is:
The name 'imgbUks1' does not exist in the current context
We cannot access the control in DataTemplate by using x:Name. I recommend to use data bindings. GroupHeader also binds to each Words Group. So each Groupheader behaves differently. Make some changes to the WordsGroup and binds the IsEnabled property could make it. I make a small demo.
Note: I don't know what the exactly data in your sounds list. To make it easy, I suppose it's a list consists of different strings (if has no sound it may return a null string) and each Group has a corresponding value in sound list.
So for WordsGroup, just add a new property named it Sound. You could also implement INotifyPropertyChanged, then UI will change if data source change. For more info, you could refer to Viewmodels and property-change notifications
public class WordsGroup : List<Words>,INotifyPropertyChanged
{
...
public string sound { get; set; }
public string Sound
{
get
{
return sound;
}
set
{
sound = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Sound)));
}
}
public Grouped_list(string name, List<Words> words, string sound) : base(words) // You may add other property in your case
{
Name = name;
Sound = sound;
}
public event PropertyChangedEventHandler PropertyChanged;
}
In ViewModel, we make some changes to the construction of WordsGroups. We add a new value that is sound, which get from GetGroupWords_Sound method.
int count = 0 // ensure that each words group and sound is corresponding
foreach (var key in _words_list)
{
// I notice you have added other property which I don't take into consideration.
WordsGroups.Add(new WordsGroup(key, new List<Words>(dict[key]), sounds[count]));
count ++;
}
Finally, we could consume it in CollectionView. We have a lot of ways to do it. That depends on the data type in the sounds list. In this example, we suppose sounds list is consist of string (if no sound, it is null). we could use a StringToBoolConverter. For more info, you could refer to Binding value converters.
<ContentPage.Resources>
<local:StringToBoolConverter x:Key="StringToBool"/>
</ContentPage.Resources>
......
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" Margin="5,0,0,0">
......
// in this way, we change string sound to bool based on whether it is null or not
<ImageButton x:Name="imgbUk1" IsEnabled={Binding Sound,Converter={StaticResource StringToBool}} />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
For StringToBoolConverter.cs, such like this:
public class StringToBoolConverter : IValueConverter
{
public StringToBoolConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.ToString() == "")
{
return false;
}
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Hope it works for you. If you still have any question, feel free to ask.