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.
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 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;
}
}
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}"
.../>