Set form MinWidth and MinHeight based on child property

前端 未结 2 1304
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-25 09:20

I\'m writing an application in WPF using the MVVM pattern. In my application I\'ve got an IPopupWindowService which I use to create a popup dialog window.

相关标签:
2条回答
  • 2021-01-25 09:43

    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 讨论(0)
  • 2021-01-25 10:01

    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}"
    .../>
    
    0 讨论(0)
提交回复
热议问题