Problem with displaymemberpath vs ItemTemplate

Ognjen Milic 26 Reputation points
2021-12-17T01:13:31.117+00:00

Hi,

I came to intriguiing problem in my hobby WinUI 3 WinRT/C++ project.

When I use ItemTempalte in my combo box as below combo box works properly.

<ComboBox x:Name="characterGender" Header="Gender" ItemsSource="{x:Bind Path=characterModel.gendersInputSource, Mode=OneWay}" SelectedValue="{Binding Path=characterModel.character.gender, Mode=TwoWay}" Margin="10,0,0,0" BorderBrush="#66384FB8" Width="200"
Grid.Row="4" Grid.ColumnSpan="2" IsEnabled="{x:Bind Path=characterModel.enabledOnEdit, Mode=OneWay}" SelectionChanged="genderChanged"
>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:GenderEntity">
<TextBlock Text="{x:Bind displayName, Mode=OneWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ComboBox>

However with DisplayMemberPath property which should work equaly as I understand it shows empty string for each item (all options are blank). When item is selected selected value is properly set so SelecedValue and SelectedItem are correctly set.

<ComboBox x:Name="characterGender" Header="Gender" ItemsSource="{x:Bind Path=characterModel.gendersInputSource, Mode=OneWay}" SelectedValue="{Binding Path=characterModel.character.gender, Mode=TwoWay}" Margin="10,0,0,0" BorderBrush="#66384FB8" Width="200"
Grid.Row="4" Grid.ColumnSpan="2" IsEnabled="{x:Bind Path=characterModel.enabledOnEdit, Mode=OneWay}" SelectionChanged="genderChanged" DisplayMemberPath="displayName"
>
</ComboBox>

In MIDL gendersInputSource is defined as below

Windows.Foundation.Collections.IObservableVector<GenderEntity> gendersInputSource{get;};

Any hints why this works differently?

Developer technologies Universal Windows Platform (UWP)
Windows development Windows App SDK
Developer technologies C++
{count} vote

2 answers

Sort by: Most helpful
  1. Ognjen Milic 26 Reputation points
    2021-12-18T00:24:41.263+00:00

    Hi,

    SelectedValue is just fine. I checked this one during debugging. Items are there but blank.
    I placed these combo boxes as two components next to each other as you can see on the pictures I attached.
    Both combos have the same source that is same content. Changing the field Race trigger's input source reload as you will see in the code but that shouldn't matter.

    Here's bit more code.

    -------------------------
    XAML-----------------------------------

    <ComboBox x:Name="characterGender" Header="Gender" ItemsSource="{x:Bind Path=characterModel.gendersInputSource, Mode=OneWay}"  SelectedValue="{Binding Path=characterModel.character.gender, Mode=TwoWay}" Margin="10,0,0,0" BorderBrush="#66384FB8" Width="200"  
    		  Grid.Row="4" Grid.ColumnSpan="1" IsEnabled="{x:Bind Path=characterModel.enabledOnEdit, Mode=OneWay}" SelectionChanged="genderChanged" DisplayMemberPath="displayName"  
    >  
    </ComboBox>  
      
    <ComboBox x:Name="characterGender2" Header="Gender" ItemsSource="{x:Bind Path=characterModel.gendersInputSource, Mode=OneWay}"  SelectedValue="{Binding Path=characterModel.character.gender, Mode=TwoWay}" Margin="10,0,0,0" BorderBrush="#66384FB8" Width="200"  
    		  Grid.Row="4" Grid.ColumnSpan="1" Grid.Column="1" IsEnabled="{x:Bind Path=characterModel.enabledOnEdit, Mode=OneWay}" SelectionChanged="genderChanged"   
    		   >  
       <ItemsControl.ItemTemplate>  
    	  <DataTemplate x:DataType="local:GenderEntity">   
    		<TextBlock Text="{x:Bind displayName, Mode=OneWay}"/>   
    	  </DataTemplate>  
       </ItemsControl.ItemTemplate>  
    </ComboBox>  
    --------------------  
    

    -----------------------------------------------

    -------------
    VIEW CPP --------------------
    void CharacterPage::characterRaceChanged(const Controls::AutoSuggestBox& sender, const Controls::AutoSuggestBoxTextChangedEventArgs& args) const {
    if (args.Reason() == Controls::AutoSuggestionBoxTextChangeReason::UserInput) {
    sender.ItemsSource(mCharacterModel.matchingRaces(sender.Text()));
    }
    }

    void CharacterPage::characterRaceSubmitted(Controls::AutoSuggestBox const& sender, Controls::AutoSuggestBoxQuerySubmittedEventArgs const& args) const {  
        const auto race = args.ChosenSuggestion().as<RaceEntity>();  
        sender.Text(race->displayName());  
        sender.ItemsSource(single_threaded_observable_vector<RMCCGUI::RaceEntity>());  
    	if (race != nullptr && mCharacterModel.character().race() != race->code()) {  
            mCharacterModel.character().race(race->code());  
            mCharacterModel.raceDisplayName(race->displayName());  
            mCharacterModel.raceChanged();  
        }  
    }  
    
    void CharacterPage::genderChanged(Windows::Foundation::IInspectable const& sender, Controls::SelectionChangedEventArgs const& args) {  
          
    	auto value = characterGender().SelectedValue();  
          
        auto value2 = value.as<GenderEntity>();  
    
    	auto selItem = characterGender().SelectedItem();  
        auto selItem2 = selItem.as<GenderEntity>();  
    
    	auto selPath = characterGender().SelectedValuePath();  
    	auto text = characterGender().Text();  
          
    }  
    

    -------------------------------------------

    ------------
    View Model CPP ------------------------

    IObservableVectorRMCCGUI::GenderEntity CharacterViewModel::gendersInputSource() const {
    IObservableVector genderVector(single_threaded_observable_vectorRMCCGUI::GenderEntity());
    const RMCCGUI::RaceEntity race = RaceService::service().race(character().race());

    	for (auto gender : GenderService::service().getAll()) {  
            if (race.genderAllowed(gender.code())) {  
                genderVector.Append(gender);  
            }  
        }  
        return genderVector;  
    }  
    

    void CharacterViewModel::raceChanged() {
    mPropertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"gendersInputSource" });
    mPropertyChanged(*this, Data::PropertyChangedEventArgs{ L"appearancePair" });
    }

    --------------------------------------------------------

    ---------------------
    IDL for Items ----------------------

    namespace RMCCGUI  
    {  
        unsealed runtimeclass Entity {  
            Entity();  
      
            String code;  
      
            String name;  
      
            String displayName;  
      
            Boolean matches(String query);  
        }  
    }  
      
    import "entities/Entity.idl";  
      
    namespace RMCCGUI  
    {  
        [default_interface]  
        runtimeclass GenderEntity : Entity {  
            GenderEntity();  
        }  
    }  
    

    -----------------------------------------------------------

    I use Visual Studio 2019 (16.11.7),
    Min platform version 10.0.18362.0, targeted platform version 10.0.19041
    Platform toolset v142
    Win UI 3 (WindowsAppSDK 1.0.0) as you can see in section from vcxproj file

    <ImportGroup Label="ExtensionTargets">  
        <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.210806.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210806.1\build\native\Microsoft.Windows.CppWinRT.targets')" />  
        <Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22000.194\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22000.194\build\Microsoft.Windows.SDK.BuildTools.targets')" />  
        <Import Project="..\packages\Microsoft.WindowsAppSDK.1.0.0\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.0.0\build\native\Microsoft.WindowsAppSDK.targets')" />  
        <Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.211019.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.211019.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />  
      </ImportGroup>  
    

    Works properly (ItemTemplate)
    158702-combowithtext.png

    Shows blanks (DisplayMemberPath)
    158657-comboempty.png


  2. Ognjen Milic 26 Reputation points
    2022-07-03T21:21:21.383+00:00

    Hi @Nico Zhu (Shanghai Wicresoft Co,.Ltd.) ,

    Sorry I didn't see you replied and I wanted to give it one more try as DisplayMemberPath property doesn't work for me at all in WinUI 3, WinRT C++.
    Which class should implement INotifyPropertyChanged and why? I had exactly the same behavior with AutoSuggestBox. Data template works while DisplayMemberPath does not. I can use DataTemplate but I wan't to understand what I did wrong.

    In AutoSuggestBox I have.

    **<AutoSuggestBox x:Name="characterProfession" Header="{CustomResource ResourceKey=Profession}" Margin="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="#66384FB8" Width="200" Grid.Row="9" Grid.ColumnSpan="2" TextChanged="characterProfessionChanged" QuerySubmitted="characterProfessionSubmitted" TextMemberPath="displayName" DisplayMemberPath="displayName" IsEnabled="{x:Bind Path=characterModel.enabledOnCreation}"/>

    In characterProfessionChanged I populate ItemSource with IObservableVector<rmccgui::ProfessionEntity> where rmccgui::ProfessionEntity has property displayName defined in its idl file.
    List is populated with proper ProfessionEntity values, but all entries are blank. When I select one of blank values it will call characterProfessionSubmitted properly. I would expect that ProfessionEntity::displayName is called for each member of the list but it is not.

    Any hints?

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.