2

I am trying to bind on property IsSelected of ComboBoxItem in order to show correct icon, if item is selected the red icon should be shown, otherwise gray for the rest of the opened list. The way how am I trying to achieve that functionality is shown in the code below.

<ComboBox
    ItemsSource="{Binding Icons}"
    SelectedItem="{Binding SelectedIcon, Mode=TwoWay}"
    Style="{ThemeResource DefaultComboBoxStyle}"
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                    <Image
                        Width="20"
                        Height="20"
                        Source="{Binding IconId, Mode=TwoWay, Converter={StaticResource IconConverter}, ConverterParameter={StaticResource True}}"
                        Visibility="{Binding Path=IsSelected,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
                    <Image
                        Width="20"
                        Height="20"
                        Source="{Binding IconId, Mode=TwoWay, Converter={StaticResource IconConverter}}"
                        Visibility="{{Binding Path=IsSelected,RelativeSource={RelativeSource Mode=TemplatedParent} Converter={StaticResource BoolToVisibilityInverted}}" />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

The icon id of an item is the same for both images converter will return correct image link depending on passed parameter. I have tried to get parent data context and try to use IsSelected property of comboBoxItem (SelectorItem) but it doesn't work.

I don't want to add IsSlected property in ViewModel through which I iterate, I assume that some syntax exists but I couldn't find it. I just want to get value of property IsSelected and to bind in xaml without code changing code in the ViewModel.

Something like in the code below is achieved but hard coded elements. Depending on IsSelected item property of ComboBoxItem correct icon is shown. I want the same functionality using ItemsSource and DataTemplate.

 <ComboBox
    SelectedIndex="{Binding IconType, Mode=TwoWay, Converter={StaticResource IconTypeIndexToIconConverter}}"
    Style="{ThemeResource DefaultComboBoxStyle}">
    <ComboBoxItem x:Name="SwitchIcon">
        <StackPanel Orientation="Horizontal">
                <Image
                    Source="{Binding Source=1, Converter={StaticResource IconConverter}}"
                    Style="{ThemeResource DeviceTypeImageBlockStyle}"
                    Visibility="{Binding IsSelected, ElementName=SwitchIcon, Converter={StaticResource BoolToVisibilityInverted}}" />
                <Image
                    Source="{Binding Source=1, Converter={StaticResource IconConverter}, ConverterParameter={StaticResource True}}"
                    Style="{ThemeResource DeviceTypeImageBlockStyle}"
                    Visibility="{Binding IsSelected, ElementName=SwitchIcon, Converter={StaticResource BoolToVisibilityConverter}}" />
        </StackPanel>
    </ComboBoxItem>
    <ComboBoxItem x:Name="LightDimmingIcon">
        <StackPanel Orientation="Horizontal">
                <Image
                    Source="{Binding Source=2, Converter={StaticResource IconConverter}}"
                    Style="{ThemeResource DeviceTypeImageBlockStyle}"
                    Visibility="{Binding IsSelected, ElementName=LightDimmingIcon, Converter={StaticResource BoolToVisibilityInverted}}" />
                <Image
                    Source="{Binding Source=2, Converter={StaticResource IconConverter}, ConverterParameter={StaticResource True}}"
                    Style="{ThemeResource DeviceTypeImageBlockStyle}"
                    Visibility="{Binding IsSelected, ElementName=LightDimmingIcon, Converter={StaticResource BoolToVisibilityConverter}}" />
        </StackPanel>
    </ComboBoxItem>
</ComboBox>

Any ideas? Solution?

mata94
  • 43
  • 4

1 Answers1

1

Binding the IsSelected property of ComboBoxItem in DataTemplate UWP

I'm afraid you can't bind the IsSelected property of ComboBoxItem in DataTemplate UWP. Because TemplatedParent RelativeSource is ContentPresenter but not ComboBoxItem, and you could use the follow xaml to verify.

<ComboBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <Border DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">
                <TextBlock x:Name="Print" Text="{Binding}"/>
            </Border>
            <TextBlock Text="{Binding}" />
        </StackPanel>
    </DataTemplate>
</ComboBox.ItemTemplate>

It will will display Windows.UI.Controls.ContentPresenter in Print textblock.

I don't want to add IsSlected property in ViewModel through which I iterate, I assume that some syntax exists but I couldn't find it.

In general, we do deal with the scenario by add IsSlected into model class. And get the select item modify the IsSlected value to effect UI. I have make complete sample below.

Code Behind

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public List<CBContent> Items { get; set; } = new List<CBContent>();
    public MainPage()
    {
        this.InitializeComponent();
        Items.Add(new CBContent { Content = "Item1", IsSelected = false });
        Items.Add(new CBContent { Content = "Item2", IsSelected = false });
        Items.Add(new CBContent { Content = "Item3", IsSelected = false });
        Items.Add(new CBContent { Content = "Item4", IsSelected = false });
        Items.Add(new CBContent { Content = "Item5", IsSelected = false });
        Items.Add(new CBContent { Content = "Item6", IsSelected = false });
        this.DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    private CBContent _selectItem;

    private CBContent _previousSelectItem;
    public CBContent SelectItem
    {
        get
        {
            return _selectItem;
        }
        set
        {
            _selectItem = value;              
            value.IsSelected = true;
            if(_previousSelectItem != null)
            {
                _previousSelectItem.IsSelected = false;
            }
            _previousSelectItem = _selectItem;
            OnPropertyChanged();               
        }
    }
}
public class CBContent : INotifyPropertyChanged
{
    public string Content { get; set; }
    private bool _isSelect;
    public bool IsSelected
    {
        get
        {
            return _isSelect;
        }
        set
        {
            _isSelect = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Xaml

<Grid>
    <ComboBox ItemsSource="{Binding Items, Mode=OneWay}" SelectedItem="{Binding SelectItem,Mode=TwoWay}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">

                    <Rectangle
                        Width="20"
                        Height="20"
                        Fill="Red"
                        Visibility="{Binding IsSelected, Mode=TwoWay}"
                        />
                    <TextBlock Text="{Binding Content}" />
                </StackPanel>

            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
</Grid>
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • Thank you for answer and explanation. I did it like you with previous/current selected and changing last and current in selected item property, but I don't like that solution, I hoped that some syntax exists. I maybe try to achieve something similar with complex converter. However thank you again. – mata94 Jul 16 '20 at 06:27
  • You have not used mvvm design, you could use visual tree helper to edit `ComboBoxItem`'s content directly. – Nico Zhu Jul 16 '20 at 06:38