Search code examples
c#wpfadd-in

WPF UI AddIn not updating its size


I've been trying to pass a UserControl through AppDomain boundaries and noticed a weird behavior with FrameworkElementAdapters.ViewToContractAdapter() and ContractToViewAdapter(). After the INativeHandleContract has been converted back to a FrameworkElement using FrameworkElementAdapters.ContractToViewAdapters(), the wrapped UserControl doesn't change its size anymore if one of its children grows.

This behavior can be easily demonstrated using a simple, empty, WPF window:

public partial class MainWindow : Window
{
    private ListBox listBox;
    private Button myButton;

    public MainWindow()
    {
        InitializeComponent();

        listBox = new ListBox();
        Content = listBox;

        myButton = new Button { Content = "Click me" };
        myButton.Click += (sender, args) => myButton.Content = "Lorem ipsum dolor sit amet.";
        myButton.SizeChanged += (sender, args) => Debug.WriteLine($"{myButton.DesiredSize}");
        //listBox.Items.Add(myButton);

        var frameworkElement = FrameworkElementAdapters.ContractToViewAdapter(FrameworkElementAdapters.ViewToContractAdapter(myButton));
        listBox.Items.Add(frameworkElement);
    }
}

If you click the button, the text changes as expected. the button doesn't resize itself, though, which leaves you with a truncated text. If you comment out the last two lines and just add the button, it will work as expected.

I think its basically the same problem as in this case, but there doesn't seem to be a solution. Does anyone have an idea how to get rid of this?

Thanks in advance!


Solution

  • As mentioned in my comment, additionally wrapping everything in a Grid seems to do the trick or, at least, allows you to receive a SizeChanged event which you can then use to resize the resulting FrameworkElement.

    public partial class MainWindow : Window
    {
        private ListBox listBox;
        private Button myButton;
        private Grid dummyGrid;
    
        public MainWindow()
        {
            InitializeComponent();
    
            listBox = new ListBox();
            Content = listBox;
    
            myButton = new Button { Content = "Click me" };
            myButton.Click += (sender, args) =>
            {
                myButton.Content = "Lorem ipsum dolor sit amet.";
                myButton.FontSize = 24;
            };
    
            dummyGrid = new Grid();
            dummyGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
            dummyGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
            dummyGrid.Children.Add(myButton);
    
            var frameworkElement =
                FrameworkElementAdapters.ContractToViewAdapter(
                    FrameworkElementAdapters.ViewToContractAdapter(dummyGrid));
            listBox.Items.Add(frameworkElement);
    
            // Automatically adjust HwndHost's size when the grid changes
            dummyGrid.SizeChanged += (sender, args) =>
            {
                frameworkElement.Width = args.NewSize.Width;
                frameworkElement.Height = args.NewSize.Height;
            };            
        }
    }
    

    In my case i had to do some magic to get the event to pass through the AppDomain boundaries (e.g. SizeChangedEventArgs not beeing serializable etc.).