简体   繁体   中英

Automatically set window width and height to ItemsControl Item

I have a base window which acts as a generalised container for UserControls. It works as expected, except the width and the height do not seem to be determined by the size of the child item (which with width and height set to auto, I would expect). The xaml for the base window is as follows:

<local:BaseView x:Class="Program.UI.Views.BaseWindowView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:local="clr-namespace:Program.UI.Views"
            xmlns:converters="clr-namespace:Program.UI.Converters"
            xmlns:presenter="clr-namespace:Program.Presenter"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            mc:Ignorable="d" 
            ResizeMode="NoResize" WindowStyle="None"
            d:DesignHeight="300" d:DesignWidth="300" AllowsTransparency="True">
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Closing">
        <presenter:EventToCommand Command="{Binding Mode=OneWay, Path=CloseWindow}" PassEventArgsToCommand="True"/>
    </i:EventTrigger>
</i:Interaction.Triggers>    
<local:BaseView.Resources>
    <ResourceDictionary>
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
        <converters:SystemEventToForegroundColor x:Key="SystemEventToForegroundColor" />
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Program;component/UI/Templates/Generic.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</local:BaseView.Resources>
<local:BaseView.Foreground>
    <SolidColorBrush Color="Black" Opacity="100"/>
</local:BaseView.Foreground>
<local:BaseView.Background>
    <SolidColorBrush Color="White" Opacity="0"/>
</local:BaseView.Background>
<Border BorderBrush="#FF838383" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="1" Height="auto" Width="auto" Margin="0,0,5,5">
    <Canvas Background="#E8F6F6" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch" Height="auto" Width="auto">
        <Canvas.Effect>
            <DropShadowEffect RenderingBias="Quality" Opacity="0.3" ShadowDepth="3" BlurRadius="4"/>
        </Canvas.Effect>
        <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                   Margin="0,0,0,0" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0"
                   Width="{Binding ActualWidth, ElementName=InfoCanvas}"
                   Height="{Binding ActualHeight, ElementName=InfoCanvas}"
                   d:DesignWidth="294"
                   d:DesignHeight="294">

            <Grid Width="auto" Height="auto" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid Grid.Row="0" Width="auto" HorizontalAlignment="Stretch" Height="30" VerticalAlignment="Top">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="30" />
                    </Grid.ColumnDefinitions>
                    <Border Grid.Column="0" BorderBrush="#FF838383" BorderThickness="0,0,0,1" Height="30" VerticalAlignment="Top">
                        <Label Style="{StaticResource WindowHeaderControlTitle}" MouseDown="Label_MouseDown"/>
                    </Border>
                    <Border Grid.Column="1" BorderBrush="#FF838383" BorderThickness="1,0,0,1">
                        <Label Style="{StaticResource WindowHeaderControlCloseLabel}" MouseEnter="Label_MouseEnter" MouseLeave="Label_MouseLeave" MouseLeftButtonUp="Label_MouseLeftButtonUp" MouseLeftButtonDown="Label_MouseLeftButtonDown" FontSize="14" FontFamily="Segoe UI Black" FontStretch="UltraExpanded" Content="X"/>
                    </Border>
                </Grid>
                <ItemsControl Grid.Row="1" Height="auto" Width="auto" ItemsSource="{Binding ChildView}"/>
            </Grid>

        </DockPanel>
    </Canvas>
</Border>

The view is generated on the click event of an Excel ribbon button, the code-behind for which is:

var childView = new DatapointDefinitionsView();
childView.DataContext = new DatapointDefinitionsViewModel();

ApplicationData.Presenter.ShowView<BaseWindowView>(
    new BaseWindowViewModel(childView, ApplicationData.Presenter), true);

The ShowView code is:

    private BaseWindowView _windowView;
    public void ShowView<T>(BaseWindowViewModel viewModel, bool asModal) where T : BaseWindowView, new()
    {
        _windowView = new T
        {

            DataContext = viewModel,
            ShowInTaskbar = false,
            Title = viewModel.Caption,

        };
        //Width = viewModel.ChildView[0].Width,
        //Height = viewModel.ChildView[0].Height
        if (asModal)
        {
            _windowView.ShowDialog();
            _windowView = null;
        }
        else
        {
            _windowView.Show();
        }
    }

Setting the width and height explicitly to the child height will set the width to the specified width, but has no effect on the height. Even if it did, however, this is not a satisfactory solution as it means the values are fixed and will not update if the usercontrol dimensions change.

Is there another way to achieve what I want?

So I was able to resolve this in the end, with all the desired functionality, as follows:

I bound the canvas height (in xaml) to the height of the DockPanel Height="{Binding ElementName=ReferenceInfo, Path=ActualHeight}"

but the width to the ItemsControl element Width="{Binding ElementName=ChildUserControl, Path=ActualWidth}"

I removed Height and Width from the DockPanel and re-enabled SizeToContent="WidthAndHeight" window attribute as per @lokusking earlier suggestion.

In order to enable CanResizeWithGrip functionality (and have the content of the child usercontrol dynamically resize accordingly) I hooked into the window SizeChanged event and added the following code:

    private void BaseView_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var window = sender as Window;

        if (ChildUserControl.HasItems)
        {
            var chlidControl = ChildUserControl.Items[0] as UserControl;
            var context = (BaseWindowViewModel)window.DataContext;

            // Ignore the first 3 resize events - these occur on view generation
            if (!context.InitialResizeComplete)
                if (context.ResizeOperations < 3)
                {
                    context.ResizeOperations++;
                    return;
                }

            context.InitialResizeComplete = true;

            // Subtract all fixed size elements from window dimensions
            chlidControl.Width = window.ActualWidth - (OuterBorder.BorderThickness.Left + OuterBorder.BorderThickness.Right + OuterBorder.Margin.Right + OuterBorder.Margin.Left);
            chlidControl.Height = window.ActualHeight - (OuterBorder.BorderThickness.Top + OuterBorder.BorderThickness.Bottom + OuterBorder.Margin.Top + OuterBorder.Margin.Bottom + TaskBarGrid.Height);
        }
    }

I've yet to determine what drives the initial 3 resize operations. My first guess was initialisation, then x, then y - but on reflection it could possibly be 1 for the baseview, 1 for the basewindow and 1 for the usercontrol. If that's the case then attached usercontrols that themselves have multiple views could prove problematic using this approach, but I've yet to test.

Hope somebody can find this useful, and thanks to those who offered help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM