-13

I need an item control with popup (because I need to use it in a data grid so when it is expanded the column width is not affected) which presents items horizontally. Ideally it would be combobox with horizontal "drop-down". Even better if it doesnt drop down but pop up above the center of the combo button (selecting item or Esc key would close it). Items are fixed size squares 30x30 and few in number, so scroll view is not needed.

I found this "code" which doesnt work at all (nothing renders on the screen):

<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="120">
    <ComboBox.Items>
        <ComboBoxItem>Item 1</ComboBoxItem>
        <ComboBoxItem>Item 2</ComboBoxItem>
        <ComboBoxItem>Item 3</ComboBoxItem>
    </ComboBox.Items>
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
        </Style>
    </ComboBox.ItemContainerStyle>
    <ComboBox.Template>
        <ControlTemplate TargetType="{x:Type ComboBox}">
            <Grid>
                <Popup x:Name="PART_Popup" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom">
                    <Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
                        <ScrollViewer x:Name="DropDownScrollViewer">
                            <StackPanel IsItemsHost="true"/>
                        </ScrollViewer>
                    </Border>
                </Popup>
            </Grid>
        </ControlTemplate>
    </ComboBox.Template>
</ComboBox>

How to make it work?

Boppity Bop
  • 9,613
  • 13
  • 72
  • 151
  • 4
    This reads as you used ChatGPT as code writer service and now you try here. I'm not a free code writer. I'm trying to do some sort of tutoring/teaching to help people solve their problems more or less on their own. This may just a phrasing issue here with the question but the pseudo gamification you put in there also does not help either. Maybe retry asking? – Ralf Jun 06 '23 at 07:51
  • Why don't you simply modify the original ControlTemplate? This gives all the freedom to position the flyout where ever you want. –  Jun 06 '23 at 08:00
  • @BionicCode. I never done that before I have no idea how to position the popup. I modified the code a little and now it does what I want but now the popup stays on the same position on the screen while the parent window moves. it looks weird. I am obv not up to it. – Boppity Bop Jun 06 '23 at 08:44
  • 2
    I think it would be easier to figure out this problem from scratch than to understand what ChatGPT generated. – Lukasz Szczygielek Jun 06 '23 at 09:10
  • I agree. I posted the code because many people down vote because they ask - what have you done first.. but then there are others who would downvote anyway.. its no win no win environment – Boppity Bop Jun 06 '23 at 14:48

1 Answers1

0

This Behaviour should solve the popup positioning problem.

using Microsoft.Xaml.Behaviors;
using System;
using System.Runtime.Versioning;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace MCS.UI.WpfUICommon.AttachedProperties
{
[SupportedOSPlatform("windows")]
public class AutoRepositionPopupBehavior : Behavior<Popup>
{
    private const int WM_MOVING = 0x0216;

    // should be moved to a helper class
    private DependencyObject GetTopmostParent(DependencyObject element)
    {
        var current = element;
        var result = element;

        while (current != null)
        {
            result = current;
            current = (current is Visual || current is Visual3D) ?
               VisualTreeHelper.GetParent(current) :
               LogicalTreeHelper.GetParent(current);
        }
        return result;
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        //AssociatedObject.LayoutUpdated += (sender, e) => Update();
        AssociatedObject.Loaded += (sender, e) =>
        {
            if (GetTopmostParent(AssociatedObject.PlacementTarget) is Window root)
            {
                var helper = new WindowInteropHelper(root);
                var hwndSource = HwndSource.FromHwnd(helper.Handle);
                if (hwndSource != null)
                {
                    hwndSource.AddHook(HwndMessageHook);
                }
            }
        };
    }

    private IntPtr HwndMessageHook(IntPtr hWnd,
            int msg, IntPtr wParam,
            IntPtr lParam, ref bool bHandled)
    {
        if (msg == WM_MOVING)
        {
            Update();
        }
        return IntPtr.Zero;
    }

    public void Update()
    {
        // force the popup to update it's position
        var mode = AssociatedObject.Placement;
        AssociatedObject.Placement = PlacementMode.Relative;
        AssociatedObject.Placement = mode;
    }
}
}

And the usage in xaml:

         xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 
         xmlns:attachedprops="clr-namespace:YourBehaviourNameSpace"

 <Popup .... >
    <b:Interaction.Behaviors>                      
        <attachedprops:AutoRepositionPopupBehavior/>
    </b:Interaction.Behaviors>
</Popup>
bazsisz
  • 394
  • 2
  • 11
  • thank you. thats very neat. however I would just like to know - how "native" wpf combo works? I cant believe it needs that much code including windows message pump processing to just keep a popup in place. – Boppity Bop Jun 06 '23 at 14:50