I'm trying to find a way to resize a LayoutPanel (DevExpress) based on the size of the user control that it contains. The user control is exposed using a ContentControl. Here's the relevant Code
This is the Layout panel and the coresponding view:
<dxd:LayoutPanel Caption="Search Criteria" CaptionImage="Images/Icons/DetailView.png">
<ContentControl Name="myContentControl" Content="{Binding Path=ProjectsSearchVM}"/>
</dxd:LayoutPanel>
The ProjectSearchVM is a property of the MainWindowViewModel, which is the DataContext for the code above. This property returns an object of type ProjectsSearchViewModel that is replaced by its corresponding View (containing a userControl) using a Resource File:
<DataTemplate DataType="{x:Type vm:ProjectSearchViewModel}">
<vw:ProjectSearchView />
</DataTemplate>
The problem is that my view is higher than the original size of the Layout Pannel. I'd like to bind the panel's MinSize to the size of my view (or the ContentControl containing it).
I tried this, but it doesn't work:
<dxd:LayoutPanel Caption="Search Criteria" CaptionImage="Images/Icons/DetailView.png">
<dxd:LayoutPanel.MinSize>
<Binding ElementName="myContentControl" Path="Size"/>
</dxd:LayoutPanel.MinSize>
<ContentControl Name="myContentControl" Content="{Binding Path=ProjectsSearchVM}" />
</dxd:LayoutPanel>
I'm still very new to WPF, so I'm sure the solution is simple.
Can anyone enlighten me?
The question was answered on the DevExpress site at this link:
http://www.devexpress.com/Support/Center/Question/Details/Q448884
For flyout, it involves overriding the control in the container, for example, if it's in a Border, something like this:
public class AutoSizeContainer : Border {
protected override void OnInitialized(EventArgs e) {
base.OnInitialized(e);
BaseLayoutItem item = DockLayoutManager.GetLayoutItem(this);
Child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
AutoHideGroup.SetAutoHideSize(item, new Size(Child.DesiredSize.Width + 6, Child.DesiredSize.Height + 6));
}
}
Making such an object the root object of the LayoutPanel in an AutoHide group, makes the flyout sizing correct.
I'm not familiar with DevExpress's LayoutPanel, but most standard WPF panels (Grid, StackPanel) "auto size" to contain their children. Are you setting hard Height and Width properties for the LayoutPanel (or does it only contain a Size property and not Height and Width like standard WPF controls)?
If you are forced to use hard Height/Width values, a common way to bind them would be like this:
<dxd:LayoutPanel ... Height="{Binding Height, ElementName=myContentControl}" Width="{Binding Width, ElementName=myContentControl}">
<ContentControl x:Name=myContentControl ... />
</dxd:LayoutPanel>
Normally, if you bind Heights and Widths you bind to ActualHeight or ActualWidth, but those properties do not exist on ContentControl. (Height and Width are only suggested values, so you may find that if the above binding is needed and works for you, you may need to tweak the values slightly with a value converter to account for margins or padding).
Related
I have a wpf Canvas in a grid in a UserControl named 'root' and I bind the Width and Height of the canvas as follows:
Width="{Binding ElementName=root, Path=ActualWidth}"
Height="{Binding ElementName=root, Path=ActualHeight}"
On the canvas all kinds of DrawingVisual are drawn.
In code behind I set the Width end Height of my Canvas equal to ContentBounds.Right and ContentBounds.Bottom so that every DrawingVisual that I add to the canvas will be visible.
This seems to work all right but I am confused about the binding mentioned.
This is a one-way binding from the usercontrol's actual size to the size of the canvas.
Does the setting of Width and Height in code behind overrule this binding?
When I remove the binding the canvas is displayed equally as well, but the control is also used in other places and situations and might be needed then.
Does the setting of Width and Height in code behind overrule this binding?
Yes. Programmatically setting the value of a target property that has a one-way binding applied to it will clear the binding.
I have a couple specific user controls to Show some Content, e.g. simple like Image, WebControl but also two complex specific custom controls drawing on a canvas.
Now I thought using the DataTemplateSelector to handle the different UserControls. I actully used this http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector as a reference.
I changed the code so the form loads the UserControls dynamically (according to the file extension) in the following collection:
ObservableCollection<string> _pathCollection = new ObservableCollection<string>();
The only difference to the reference is now I want to navigate back and forward to the next control by showing one control only at the time. Which control should I use instead of ListView?
<Grid>
<ListView ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding ElementName=This, Path=PathCollection}"
ItemTemplateSelector="{StaticResource imgStringTemplateSelector}">
</ListView>
</Grid>
How do I need to bind it to the template (equal to ItemTemplateSelector above)? WPF is still very new to me and I am learning.
Use a ContentControl. Bind your current item to the Content-property and the DataTemplateSelector to the ContentTemplateSelector-property.
<ContentControl Content="{Binding Path=CurrentItem, Mode=OneWay}", ContentTemplateSelector="{StaticResource imgStringTemplateSelector}" />
Your CurrentItem should be a DependencyProperty or a INotifyPropertyChanged-property of your DataContext. When you change your CurrentItem, the ContentControl will update the template automatically with help of your TemplateSelector.
I would like to be able to dynamically adjust the size of a content control.
Here's a simple example:
...
<Slider x:Name="width" Minimum="40" Value="100" Maximum="300"/>
...
<ContentPresenter Width="{Binding Value, ElementName=width}" Content="Some value">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<Grid MaxWidth="200" MinWidth="80">
<Rectangle Fill="Wheat" />
<TextBlock Text="{Binding}"/>
</Grid>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
Given this example, I would like to force the width of the content ContentPresenter to stay within the min and max width of its generated child (80 - 200 in this case).
Obviously with a simple example like this I could just change the range of the slider, but my real scenario is more complicated. I'm trying to restrict the size of a popup screen to its generated content. I can't set an explicit range on the popup because I have no idea what the content is going to be like before hand. The content has to be able to restrict itself.
Unfortunately MaxWidth and MinWidth on children are pretty much ignored. MinWidth results in cropping when the parent is set smaller. MaxWidth results in lots of empty space. It looks like I will have to set MaxWidth and MinWidth in the same place that I am dynamically updating the Width value.
My suggestion would be to replace the ContentPresenter with a custom panel (alternately, enclose a custom panel in the ContentPresenter if you cannot replace it) that doles out the exact size you want in the way that you want. It's fairly easy and simple to declare a class that derives from Panel and then override MeasureOverride and ArrangeOverride. In this case you could measure everything with the base MeasureOverride and then just assign the size you want as your available space. In ArrangeOverride just assign the direct child of your panel, to be the final size of the panel (rect = 0,0,width,height).
How do I access an element contained in a DataTemplate that is displayed through a ContentControl. I have a ContentControl which hosts a PresentationModel along the lines of:
<ContentControl x:Name="ContentContainer"
Content="{Binding}"
ContentTemplate="{Binding ContentControlTemplate, ElementName=this}"
Where "this" is the view (UserControl).
There's a DataGridControl I want to EndEdit on, so I tried this:
ContentPresenter presenter = VisualTreeHelper.GetChild(this. ContentContainer, 0) as ContentPresenter;
DataGridControl dg = this. ContentContainer.ContentTemplate.FindName("datagrid", presenter) as DataGridControl;
dg.EndEdit();
Problem is that the ContentControl has no children, maybe because of the way the content is bound?
I appreciate any help.
Well, you are casting the result of GetChild to a ContentPresenter. Depending on its Template, this may not be the case. I think its default template includes a Border, so your cast will return null. If you don't need it to do anything other than display the content, why not use ContentPresenter directly?
I have a DesignerCanvas (derived from canvas) that I can add UIElements to, then drag\drop\move\group and move them around.
On the toolbar I have a button that is bound to a group command.
<Button Margin="0,3,0,3" Padding="5" HorizontalContentAlignment="Left"
Command="{x:Static s:DesignerCanvas.Group}"
CommandTarget="{Binding ElementName=DesignerCanvas}">
The problem that I have is that I can have a control that also contains a DesignerCanvas. So there are nested canvas's, and I want the GroupCommand on the toolbar to apply to the canvas that is in focus. In the above binding it is binding only to the root canvas.
I suppose I could track the current canvas and expose it in the viewmodel for the binding, but I'd prefer to avoid tracking the activecanvas.
Any suggestions for a creative binding here?
Thanks,
jeff
Is GroupCommand a RoutedCommand? Assuming it is, I would expect that you would get the behavior you want by removing the CommandTarget property assignment.