开发者

Set form MinWidth and MinHeight based on child property

I'm writing an application in WPF using the MVVM pattern. In my appli开发者_如何学Pythoncation I've got an IPopupWindowService which I use to create a popup dialog window.

So to show a ViewModel in a popup window you'd do something like this:

var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
var popupService = container.Resolve<IPopupWindowService>();
var myViewModel = container.Resolve<IMyViewModel>();
popupService.Show((ViewModelBase)myViewModel);

This is all well and good. What I want to do is be able to set the MinHeight and MinWidth on the View bound to myViewModel and have the popup window use those settings so that a user cannot make the window smaller than its contents will allow. At the moment when the user shrinks the window the contents stops resizing but the window doesn't.

EDIT:

I map my Views to my ViewModels in ResourceDictionarys like so:

<DataTemplate DataType="{x:Type ViewModels:MyViewModel}">
     <Views:MyView />
</DataTemplate>

And my popup view looks like this:

<Window x:Class="TheCompany.Cubit.Shell.Views.PopupWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterOwner">
<DockPanel x:Name="panelContent">
    <StackPanel HorizontalAlignment="Right" DockPanel.Dock="Bottom" Orientation="Horizontal" Visibility="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=ButtonPanelVisibility}">
        <Button Width="75" IsDefault="True" x:Uid="ViewDialog_AcceptButton" Click="OnAcceptButtonClick" Margin="4">OK</Button>
        <Button Width="75" IsCancel="True" x:Uid="ViewDialog_CancelButton" Click="OnCancelButtonClick" Margin="0,4,4,4">Cancel</Button>
    </StackPanel>
    <ContentPresenter Content="{Binding}" />
</DockPanel>


You can define MinHeight and MinWidth properties on your ViewModel and use databinding to bind the View to those properties in XAML:

<...
    MinHeight="{Binding Path=MinHeight}"
    MinWidth="{Binding Path=MinWidth}"
.../>


I designed exactly the same generic modal dialog control (using Type-targeted DataTemplates) and also stumbled into this problem.

  • Using a RelativeSource does not work because you can only find ancestors that way (afaik).

  • Another possible solution was to name the ContentPresenter and bind to properties on that using ElementName binding. However, the ContentPresenter does not "inherit" the MinHeight and MinWidth properties from the Visual child it renders.

The solution eventually was to use VisualTreeHelper to get at the resolved View associated with the ViewModel at runtime:

        DependencyObject lObj = VisualTreeHelper.GetChild(this.WindowContent, 0);
        if (lObj != null && lObj is FrameworkElement)
        {
            lWindowContentMinHeight = ((FrameworkElement)lObj).MinHeight;
            lWindowContentMinWidth = ((FrameworkElement)lObj).MinWidth;
        }

I put this code in a OnActivated() override in the code-behind of the ModalDialogView (in OnInitialized the View can't be resolved yet).

The only remaining issue is to correct these minimums so that the window width and button panel height is taken into account.

UPDATE

Below is the code I use in my generic modal dialog. It solves the following additional problems:

  • It centers on the owner window correctly
  • It doesn't do anything if the content doesn't have MinWidth and MinHeight set

    private bool _MinSizeSet = false;
    
    public ModalDialogView(object pDataContext)
        : this()
    {
        this.DataContext = pDataContext;
        this.LayoutUpdated += new EventHandler(ModalDialogView_LayoutUpdated);
    }
    
    void ModalDialogView_LayoutUpdated(object sender, EventArgs e)
    {
        if (System.Windows.Media.VisualTreeHelper.GetChildrenCount(this.WindowContent) > 0)
            SetInitialAndMinimumSize();
    }
    
    private void SetInitialAndMinimumSize()
    {
        FrameworkElement lElement = VisualTreeHelper.GetChild(this.WindowContent, 0) as FrameworkElement;
        if (!_MinSizeSet && lElement != null)
        {
            if (lElement.MinWidth != 0 && lElement.MinHeight != 0)
            {
                double lHeightDiff = this.ActualHeight - this.WindowContent.ActualHeight;
                double lWidthDiff = this.ActualWidth - this.WindowContent.ActualWidth;
                this.MinHeight = lElement.MinHeight + lHeightDiff;
                this.MinWidth = lElement.MinWidth + lWidthDiff;
                this.SizeToContent = SizeToContent.Manual;
                this.Height = this.MinHeight;
                this.Width = this.MinWidth;
                this.Left = this.Owner.Left + (this.Owner.ActualWidth - this.ActualWidth) / 2;
                this.Top = this.Owner.Top + (this.Owner.ActualHeight - this.ActualHeight) / 2;
            }
            _MinSizeSet = true;
        }
    }
    
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜