How Can I Bind ItemsSource of a ComboBox in a ControlTemplate?

MERUN KUMAR MAITY 511 Reputation points
2022-09-20T19:43:14.483+00:00

Hi there, I have a WPF application where I use a ComboBox. My ComboBox ItemSource is bind to a List <> which I populate from C# in background.

Here is the C# code of that List<> :

 // Main code  
        List<AudioDevice> devices = new List<AudioDevice>();  
    HRESULT hr = HRESULT.E_FAIL;  
    Guid CLSID_MMDeviceEnumerator = new Guid("{BCDE0395-E52F-467C-8E3D-C4579291692E}");  
    Type MMDeviceEnumeratorType = Type.GetTypeFromCLSID(CLSID_MMDeviceEnumerator, true);  
    object MMDeviceEnumerator = Activator.CreateInstance(MMDeviceEnumeratorType);  
    IMMDeviceEnumerator pMMDeviceEnumerator = (IMMDeviceEnumerator)MMDeviceEnumerator;  


    if (pMMDeviceEnumerator != null)  
    {  
        string sIdDefaultRender = null;  
        string sIdDefaultCapture = null;  
        IMMDevice pDefaultDevice = null;  
        hr = pMMDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, out pDefaultDevice);  
        if (hr == HRESULT.S_OK)  
        {  
            IntPtr hGlobal = Marshal.AllocHGlobal(260);  
            hr = pDefaultDevice.GetId(out hGlobal);  
            sIdDefaultRender = Marshal.PtrToStringUni(hGlobal);  
            Marshal.FreeHGlobal(hGlobal);  
            Marshal.ReleaseComObject(pDefaultDevice);  
        }  

        hr = pMMDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eCapture, ERole.eConsole, out pDefaultDevice);  
        if (hr == HRESULT.S_OK)  
        {  
            IntPtr hGlobal = Marshal.AllocHGlobal(260);  
            hr = pDefaultDevice.GetId(out hGlobal);  
            sIdDefaultCapture = Marshal.PtrToStringUni(hGlobal);  
            Marshal.FreeHGlobal(hGlobal);  
            Marshal.ReleaseComObject(pDefaultDevice);  
        }  

        IMMDeviceCollection pDeviceCollection = null;  
        hr = pMMDeviceEnumerator.EnumAudioEndpoints(EDataFlow.eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, out pDeviceCollection);  
        if (hr == HRESULT.S_OK)  
        {  
            uint nDevices = 0;  
            hr = pDeviceCollection.GetCount(out nDevices);  

            devices.Add(new AudioDevice() { Name = "System default", Direction = "Playback", Id = sIdDefaultRender, Default = true });  
            for (uint i = 0; i < nDevices; i++)  
            {  
                IMMDevice pDevice = null;  
                hr = pDeviceCollection.Item(i, out pDevice);  
                if (hr == HRESULT.S_OK)  

                {  
                    IPropertyStore pPropertyStore = null;  
                    hr = pDevice.OpenPropertyStore(STGM_READ, out pPropertyStore);  
                    if (hr == HRESULT.S_OK)  
                    {  
                        string sFriendlyName = null;  
                        string sDesc = null;  
                        PROPVARIANT pv = new PROPVARIANT();  
                        hr = pPropertyStore.GetValue(ref PKEY_Device_FriendlyName, out pv);  
                        if (hr == HRESULT.S_OK)  
                        {  
                            sFriendlyName = Marshal.PtrToStringUni(pv.pwszVal);  
                        }  
                        hr = pPropertyStore.GetValue(ref PKEY_Device_DeviceDesc, out pv);  
                        if (hr == HRESULT.S_OK)  
                        {  
                            sDesc = Marshal.PtrToStringUni(pv.pwszVal);  
                        }  

                        IntPtr hGlobal = Marshal.AllocHGlobal(260);  
                        hr = pDevice.GetId(out hGlobal);  
                        string sId = Marshal.PtrToStringUni(hGlobal);  
                        Marshal.FreeHGlobal(hGlobal);  

                        IMMEndpoint pEndpoint = null;  
                        pEndpoint = (IMMEndpoint)pDevice;  
                        EDataFlow eDirection = EDataFlow.eAll;  
                        hr = pEndpoint.GetDataFlow(out eDirection);  
                        //System.Diagnostics.Trace.WriteLine("\tDirection : " + eDirection.ToString());  
                        string sDirection = "";  
                        if (eDirection == EDataFlow.eRender)  
                            sDirection = "Playback";  
                        else if (eDirection == EDataFlow.eCapture)  
                            sDirection = "Recording";  

                        int nState = 0;  
                        hr = pDevice.GetState(out nState);  
                        if ((nState == DEVICE_STATE_ACTIVE))  
                        {  

                            devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Id = sId, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });  

                            //sFriendlyName += (sId == sIdDefaultRender || sId == sIdDefaultCapture) ? " (System default)" : "";  
                            //devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });  
                            ////devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });  
                        }  

                        Marshal.ReleaseComObject(pPropertyStore);  
                    }  
                    Marshal.ReleaseComObject(pDevice);  
                }  
            }  

            devices.Insert(devices.Count - 0, new AudioDevice() { Name = "Selected application ...", Direction = "Recording", Id = "Idlast", Default = false });  

        }  
        Marshal.ReleaseComObject(pDeviceCollection);  
        ListCollectionView lcv = new ListCollectionView(devices);  
        lcv.GroupDescriptions.Add(new PropertyGroupDescription("Direction"));  
        this.cmb1.ItemsSource = lcv;  
    }  
}  


public class AudioDevice  
        {  
            public string Name { get; set; }  
            public string Direction { get; set; }  
            public string Id { get; set; }  
            public bool Default { get; set; }  
  
        }  

If you carefully see the code then You see this line this.cmb1.ItemsSource = lcv; That means the List<> is added as ItemSource of the ComboBox, Now, I have a control template for comboBoxItem, my ComboBoxitem control template have lots of visual customisation and effects according to my choice.

Here is my ComboBoxItem controltemplate :

 <Style x:Key="ItemStyleOne" TargetType="{x:Type ComboBoxItem}">  
            <Setter Property="SnapsToDevicePixels" Value="True"/>  
            <Setter Property="UseLayoutRounding" Value="True"/>  
            <Setter Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>  
            <Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>  
            <Setter Property="Template">  
                <Setter.Value>  
                    <ControlTemplate TargetType="{x:Type ComboBoxItem}">  
                        <Grid>  
                            <Border x:Name="gd" Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}},Path=Background}" BorderThickness="0" SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.ClearTypeHint="Enabled">  
                                <ContentPresenter  
                                Name="ContentSite" Margin="25, 3, 0, 11" VerticalAlignment="Center">  
                                    <ContentPresenter.ContentTemplate>  
                                    <DataTemplate>  
                                        <TextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased">  
                                            <Run FontSize="10">MP4 A</Run><Run FontSize="9">udio</Run>  
                                        </TextBlock>  
                                    </DataTemplate>  
                                </ContentPresenter.ContentTemplate>  
                                </ContentPresenter>  
                            </Border>  
                            <Rectangle x:Name="Border1" Width="12" Height="10" Margin="-220,-7,0,0"          RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.ClearTypeHint="Auto" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Unspecified">  
                                <Rectangle.Fill>  
                                    <DrawingBrush>  
                                        <DrawingBrush.Drawing>  
                                            <DrawingGroup>  
                                                <DrawingGroup.Children>  
                                                    <GeometryDrawing Brush="#d0021b" Geometry="M95.118,21.399L86.601,12.882C85.422,11.703,83.523,11.703,82.344,12.882L38.799,58.854 13.839,33.882C12.648,32.691,10.716,32.691,9.52499999999999,33.882L0.896999999999991,42.516C-0.294000000000009,43.704,-0.294000000000009,45.636,0.896999999999991,46.83L36.396,83.154C37.083,83.844 38.016,84.081 38.913,83.964 39.84,84.102 40.806,83.868 41.517,83.154L95.118,25.659C96.294,24.483,96.294,22.575,95.118,21.399z">  
                                                        <GeometryDrawing.Pen>  
                                                            <Pen LineJoin="Round" Brush="#d0021b" Thickness="2.5"/>  
                                                        </GeometryDrawing.Pen>  
                                                    </GeometryDrawing>  
                                                </DrawingGroup.Children>  
                                            </DrawingGroup>  
                                        </DrawingBrush.Drawing>  
                                    </DrawingBrush>  
                                </Rectangle.Fill>  
                            </Rectangle>  
                        </Grid>  
                        <ControlTemplate.Triggers>  
                            <Trigger Property="ComboBoxItem.IsMouseOver" Value="True">  
                                <Setter TargetName="gd" Property="Background" Value="#3c3c3c"></Setter>  
                                <Setter TargetName="gd" Property="TextElement.Foreground" Value="#ffffff"></Setter>  
                                <Setter TargetName="gd" Property="SnapsToDevicePixels" Value="True"/>  
                                <Setter TargetName="gd" Property="UseLayoutRounding" Value="True"/>  
                                <Setter TargetName="gd" Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>  
                                <Setter TargetName="gd" Property="RenderOptions.ClearTypeHint" Value="Enabled"/>  
                                <Setter TargetName="Border1" Property="Visibility" Value="Collapsed"/>  
                            </Trigger>  
                            <Trigger Property="ComboBoxItem.IsMouseOver" Value="False">  
                                <!--<Setter TargetName="gd" Property="Background" Value="#3c3c3c"></Setter>  
                                <Setter TargetName="gd" Property="TextElement.Foreground" Value="#ffffff"></Setter>  
                                <Setter TargetName="gd" Property="SnapsToDevicePixels" Value="True"/>  
                                <Setter TargetName="gd" Property="UseLayoutRounding" Value="True"/>  
                                <Setter TargetName="gd" Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>  
                                <Setter TargetName="gd" Property="RenderOptions.ClearTypeHint" Value="Enabled"/>-->  
                                <Setter TargetName="Border1" Property="Visibility" Value="Hidden"/>  
                            </Trigger>  
                            <Trigger Property="ComboBoxItem.IsSelected" Value="True">  
                                <Setter TargetName="Border1" Property="Visibility" Value="Visible"/>  
                                <!--<Setter TargetName="gd" Property="SnapsToDevicePixels" Value="True"/>  
                                <Setter TargetName="gd" Property="UseLayoutRounding" Value="True"/>  
                                <Setter TargetName="gd" Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>  
                                <Setter TargetName="gd" Property="RenderOptions.ClearTypeHint" Value="Enabled"/>-->  
                            </Trigger>  
                        </ControlTemplate.Triggers>  
                    </ControlTemplate>  
                </Setter.Value>  
            </Setter>  
        </Style>  

After adding this controltemplate in my ComboBoxitem my comboBox looks amazing. This is how I add this ComboBoxItem Style="{StaticResource ItemStyle}" ,

But in this case my ComboBox content is added from a List<> not from a ComboBox item, My question is then How can I add these controltemplate
visual effect to my ComboBox content, because we know ControlTemplate contains the tree of elements that define the desired look.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,671 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,238 questions
0 comments No comments
{count} votes

Accepted answer
  1. Hui Liu-MSFT 38,251 Reputation points Microsoft Vendor
    2022-09-21T05:56:48.457+00:00

    I changed the code as follows and populated the data. You could try to refer to it.

    <Window.Resources>  
      
            <Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">  
             ...  
                <Setter Property="Template">  
                    <Setter.Value>  
                        <ControlTemplate TargetType="{x:Type ComboBoxItem}">  
                            <Grid>  
                             ...  
                                            <DataTemplate>  
                                                <TextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased">  
                                                
                                                    <Run Text="{Binding Name}"/>  
                                                </TextBlock>  
                                            </DataTemplate>  
                                        ...  
                            </Grid>  
                            <ControlTemplate.Triggers>  
                               ....  
                            </ControlTemplate.Triggers>  
                        </ControlTemplate>  
                    </Setter.Value>  
                </Setter>  
            </Style>  
             
          
        </Window.Resources>  
        <Grid>  
            <ComboBox  x:Name="cb" Width="200" Height="40">  
            </ComboBox>  
        </Grid>  
    

    Codebehind:
    243166-2222.txt

    Update:

        <Application.Resources>  
    
        <local:FirstValueConverter x:Key="FirstValueConverter"/>  
    
        <local:RestValueConverter x:Key="RestValueConverter"/>  
    
                <Style x:Key="MyItemStyle" TargetType="{x:Type ComboBoxItem}">  
                  ...  
                    <Setter Property="Template">  
                        <Setter.Value>  
                                    ...  
                                                <DataTemplate>  
                                                    <TextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased">  
                                                        <Run x:Name="first" FontSize="18" Text="{Binding Name,Converter={StaticResource FirstValueConverter }}" />  
                                                        <Run x:Name="rest" FontSize="10" Text="{Binding Name, Converter={StaticResource RestValueConverter}}" />  
                                                    </TextBlock>  
                                                </DataTemplate>  
                               ...  
                        </Setter.Value>  
                    </Setter>  
                </Style>     
     </Application.Resources>  
    
        <ComboBox  x:Name="cb" Width="200" Height="40" ItemContainerStyle="{StaticResource MyItemStyle}">  
            
        </ComboBox>  
    

    Converter:

     public class FirstValueConverter : IValueConverter  
        {  
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
            {  
                var p=value as string;  
      
                var first="";  
                if (!string.IsNullOrWhiteSpace(p))  
                {  
                    first = p.Substring(0, 1);  
                }  
                return first;  
            }  
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
            {  
                throw new NotImplementedException();  
            }  
        }  
      
        public class RestValueConverter : IValueConverter  
        {  
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
            {  
                var p = value as string;  
                var rest = "";  
                if (!string.IsNullOrWhiteSpace(p))  
                {  
                    rest = p.Substring(1, p.Length - 1);  
                }  
                return  rest;  
                  
            }  
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
            {  
                throw new NotImplementedException();  
            }  
        }  
    

    The result:

    243834-image.png

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

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful