MinWidth, MaxWidth, MinHeight, MaxHeight don't have effect for <UserControl> - c#

I'm learning to create WPF application with Caliburn Micro framework.
Following the tutorial on the homepage: Basic Configuration, I removed the default generated <Window> xaml, instead, I have <UserControl> xaml and bootstrap it via my AppBoostrapper.
Here is the MainView.xaml:
<UserControl x:Class="SmartRenamer.Views.MainView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
MinHeight="300"
MinWidth="300"
MaxHeight="500"
MaxWidth="1000">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu IsMainMenu="True" Grid.Row="0">
<MenuItem Header="_File">
<MenuItem Header="_Open Folder..." x:Name="OpenFolder"></MenuItem>
</MenuItem>
<MenuItem Header="_About" />
</Menu>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Grid.Row="1" MaxHeight="500" MaxWidth="1000">
<StackPanel>
<DataGrid x:Name="FilesList">
</DataGrid>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
The problem is I want to set the MinWidth, MaxWidth, MinHeight, MaxHeight for my application, but it seems that those configuration in the MainWindow.xaml isn't working.
Here is the two screenshots, where the window is still can be re-sized out of the defined range:
What am I wrong here?

The width and height properties of an UserControl is set by the container that holds that control. I.e. the DesignWidth and DesignHeigth that are used in the design-time are set in the UserControl but in runtime it uses the values set by the container.
I am not experienced in Caliburn Micro but it seems like you can define the design properties in the bootstrapper:
var settings = new Dictionary<string, object>
{
{ "Height" , 300},
{ "Width" , 300},
};
DisplayRootViewFor<ViewModel>(settings);

Related

Bind visibility of a LayoutAnchorable to a checkable MenuItem

C#, WPF. I would like to show/hide AvalonDock panels using checkable menu items. Although I could do this using _Click events I believe it would be good practice to use binding instead and that it should be possible to achieve this entirely using XAML.
I suspect that the answer should be along the lines of this one and have based my attempt on one of the answers given there.
This code compiles and runs, but there is no link between the menu being checked and the anchorable pane being visible. The key line is this:
<MenuItem Header="Panel" Name="PanelVisible" IsCheckable="True" IsChecked="{Binding Path=testAnchorable.IsVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
How can I get this working?
<Window x:Class="TestAvalon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dock="http://schemas.xceed.com/wpf/xaml/avalondock"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Menu Height="18" HorizontalAlignment="Stretch" Name="menu1" VerticalAlignment="Top" Grid.Row="0">
<MenuItem Header="View">
<MenuItem Header="Panel" Name="PanelVisible" IsCheckable="True" IsChecked="{Binding Path=testAnchorable.IsVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
</MenuItem>
</Menu>
<dock:DockingManager x:Name = "Dockman" DataContext = "{Binding DockManagerViewModel}"
DocumentsSource = "{Binding Documents}" DockPanel.Dock = "Left" Grid.Row = "1" >
<dock:LayoutRoot x:Name = "_layoutRoot" >
<dock:LayoutPanel x:Name = "_layoutPanel" >
<dock:LayoutAnchorablePane DockWidth="400">
<dock:LayoutAnchorable x:Name ="testAnchorable" Title = "TEST PANE" IsSelected = "True">
<TextBlock Name="tb" Text="*****"/>
</dock:LayoutAnchorable >
</dock:LayoutAnchorablePane >
</dock:LayoutPanel >
</dock:LayoutRoot >
</dock:DockingManager>
</Grid>
</Grid>
This question now has a solution here:
Binding an AvalonDock LayoutAnchorable IsVisible property
(There are two answers given there and I think they both do the job.)

How can I keep a menu submenu item open?

I'm trying to create a somewhat complex menu item that would allow a user to create a new class. The problem into which I am running is that when I click on a numeric up-down ( from the xceed toolkit ) that the menu item closes, even with the property StaysOpenOnClick set to true.
Users will not like that.
To reproduce, create a WPF project and add the Extended WPF Toolkit through NuGet, then drop the following code into your mainwindow class :
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WhyDoesMyMenuItemCloseWhenClicked"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
x:Class="WhyDoesMyMenuItemCloseWhenClicked.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="21"/>
<RowDefinition />
</Grid.RowDefinitions>
<Menu FontWeight="Bold">
<MenuItem Header="_File">
<MenuItem StaysOpenOnClick="True">
<Grid Height="50" Width="50">
<xctk:IntegerUpDown/>
</Grid>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
When I click the text field of the integer up-down, the menu closes.
Why does that keep happening? How can I make it NOT happen?
I have figured out a solution. It is sort of a terribly hacky workaround, but it does the job quite well :
The change is that you create a MenuItem within the MenuItem. Then you define your control within the sub MenuItem's MenuItem.Header property, and set that MenuItem's StaysOpenOnClick property to true.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WhyDoesMyMenuItemCloseWhenClicked"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
x:Class="WhyDoesMyMenuItemCloseWhenClicked.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="21"/>
<RowDefinition />
</Grid.RowDefinitions>
<Menu FontWeight="Bold">
<MenuItem Header="_File" StaysOpenOnClick="True">
<MenuItem Header="_StaysOpenOnClick">
<MenuItem StaysOpenOnClick="True">
<MenuItem.Header>
<xctk:IntegerUpDown/>
</MenuItem.Header>
</MenuItem>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
you can make use of StaysOpenOnClick Property to achieve this

Dynamically reducing FontSize to avoid overflow

I have written a toy WPF application with a Button and an ItemsControl. Each time you click the Button, the string "AnotherWord" gets added to the ItemsControl. Now, the ItemsControl is displayed as horizontally oriented StackPanel with a fixed width (500 pixels). This means that when you click the button a certain number of times (actually six times), the newly added string gets clipped, like this:
"AnotherWord AnotherWord AnotherWord AnotherWord AnotherWord AnotherWo"
This happens when the FontSize is 13; if you lower it to 12.7 then there's room for the sixth occurence of "AnotherWord". My question is: Is there a way to make this adjustment at runtime so that you avoid the overflow?
EDIT:
In the context of the question, the fixed width of the StackPanel is obligatory - we cannot use more than the 500 pixels we have. Another requirement that the font must never become bigger than 13.
Here is all the code I wrote:
<!-- MainWindow.xaml -->
<Window x:Class="FontSize.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<DataTemplate x:Key="labelTemplate">
<Label FontSize="13" Content="AnotherWord"></Label>
</DataTemplate>
<ItemsPanelTemplate x:Key="panelTemplate">
<StackPanel Orientation="Horizontal" Width="500" Height="50" />
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding Path=MyStrings}" ItemTemplate="{StaticResource labelTemplate}"
ItemsPanel="{StaticResource panelTemplate}" />
<Button Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
// MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.Windows;
namespace FontSize
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
MyStrings = new ObservableCollection<string>();
}
public ObservableCollection<string> MyStrings
{
get { return (ObservableCollection<string>) GetValue(MyStringsProperty); }
set { SetValue(MyStringsProperty, value); }
}
private static readonly DependencyProperty MyStringsProperty =
DependencyProperty.Register("MyStrings", typeof (ObservableCollection<string>), typeof (Window));
private void Button_Click(object sender, RoutedEventArgs e)
{
MyStrings.Add("AnotherWord");
}
}
}
Put your ItemsControl in a Viewbox and play with the following properties:
MaxWidth
MaxHeight
Stretch
StretchDirection
Edit
And remove the Width & Height property of your StackPanel.
Edit 2
Try something like that:
<!-- MainWindow.xaml -->
<Window x:Class="FontSize.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<DataTemplate x:Key="labelTemplate">
<Label FontSize="13" Content="AnotherWord"></Label>
</DataTemplate>
<ItemsPanelTemplate x:Key="panelTemplate">
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" MaxWidth="500" Stretch="Uniform">
<ItemsControl
ItemsSource="{Binding Path=MyStrings}"
ItemTemplate="{StaticResource labelTemplate}"
ItemsPanel="{StaticResource panelTemplate}" />
</Viewbox>
<Button Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
Edit 3
Change the horizontal alignment of the Viewbox so it isn't stretched to fill the grid. I've put "Center", replace by whatever you want.
...
<Viewbox
HorizontalAlignment="Center"
StretchDirection="DownOnly"
Grid.Row="0"
MaxWidth="500"
Stretch="Uniform">
...

AvalonDock document binding

I'm using AvalonDock (link) to create my application. I have a toolbar and a documentpane (VisualStudio like) and each new document contains a textbox. And now I'd like to add an Undo button to my toolbar which will undo changes on the textbox wich is placed on the selected document.It's completely same like it's in Visual Studio.
What I'd like to accomplish is answered here but with TabControl and Tabs.
MyCode:
<Window x:Class="_app.MainWindow"
xmlns:my="clr-namespace:_app"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
xmlns:osc="clr-namespace:OpenSourceControls;assembly=DockPanelSplitter"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<!--...Menu And Toolbars -->
<ToolBarPanel Grid.Row="1" Width="Auto" HorizontalAlignment="Stretch" >
<ToolBar>
<Button Command="Undo">Undo</Button>
</ToolBar>
</ToolBarPanel>
<ad:DockingManager x:Name="dockManager" Grid.Row="2">
<ad:ResizingPanel Orientation="Vertical">
<ad:ResizingPanel Orientation="Horizontal">
<ad:DockablePane ad:ResizingPanel.ResizeWidth="150">
<ad:DockableContent x:Name="inputContent" Title="Workspace">
<!-- some dockable windows -->
</ad:DockableContent>
</ad:DockablePane>
<!-- here are added the new Documents-->
<ad:DocumentPane Name="mainDocPane" ItemsSource="{Binding ..Don't know..}">
<ad:DocumentPane.ItemContainerStyle>
<Style TargetType="ad:DocumentContent">
<Setter Property="Content" Value="{Binding Content}"/>
</Style>
</ad:DocumentPane.ItemContainerStyle>
</ad:DocumentPane>
</ad:ResizingPanel>
</ad:ResizingPanel>
</ad:DockingManager>
</Grid>
I create new document windows like this:
private void NewDocument_Click(object sender, RoutedEventArgs e)
{
string title = "Document" + (dockManager.Documents.Count+1).ToString();
var doc = new Document() { Title = title };
doc.Show(dockManager);
doc.Activate();
}
And the document class looks like this:
public partial class Document : AvalonDock.DocumentContent
{
public Document()
{
InitializeComponent();
}
}
XAML:
<ad:DocumentContent x:Class="_ap.Document"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:osc="clr-namespace:OpenSourceControls;assembly=DockPanelSplitter"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock">
<DockPanel>
<TextBox Name="input" AcceptsReturn="True" />
</DockPanel>
So I'd like to apply the same mechanism from the link above on this code.
Thanks for any help.
See the ApplicaionCommands.Undo
Once you tie your Undo button to the in place command which comes with the .NET FW, when the TextBox has focus the undo will take place without you having to do anything.

How to make items in a DockPanel expand to fit all available space in WPF?

I have a StackPanel containing a StackPanel and some other items. The first StackPanel has a vertical orientation, the the inner one has a horizontal orientation. The inner one has a TreeView and a ListView, I would like them to expand and fit the width of the window, which I set by the window and allow the user to change. I would also like the outer StackPanel to fit the height of the window. How do I do this?
Edit:
I've converted to using a DockPanel, and I've set the DockPanel.Dock properties correctly in each of the elements, and have disabled LastChildFill in both of the dockpanels, the layout still does not stretch.
The Code:
<Window x:Class="Clippy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="600" MinHeight="400" MinWidth="600" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged">
<DockPanel Name="wrapperDockPanel" LastChildFill="False">
<Menu Height="22" Name="mainMenu" Width="Auto" DockPanel.Dock="Top" />
<ToolBar Height="26" Name="mainToolBar" Width="Auto" DockPanel.Dock="Top" />
<DockPanel Height="Auto" Name="contentDockPanel" DockPanel.Dock="Top" LastChildFill="False">
<TreeView Name="categoryTreeView" />
<ListView Name="clipListView" />
</DockPanel>
<StatusBar Height="23" Name="mainStatusBar" DockPanel.Dock="Top" />
</DockPanel>
</Window>
Use a DockPanel instead. StackPanel explicitly doesn't care about visible space, whereas DockPanel does all of it's size calculation based on available space.
Update:
In addition, in my experience, putting the body of the window into a View, and only having the View in the Window makes for a better Auto Size experience.
For some reason putting all of the children directly into the Window seems to not auto size very well.
Update 2:
I would remove the explicit DockPanel.Dock attribute from the element that you want to stretch (fill) the unused space.
This should do it - I set it up so that the TreeView and the ListView shared the main view 50/50; if you don't want that, set it to 'Auto' and '*' or something. Use "LastChildFill" to your advantage!
<Window x:Class="Clippy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="600" MinHeight="400" MinWidth="600" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged">
<DockPanel LastChildFill="True">
<Menu Width="Auto" DockPanel.Dock="Top" />
<ToolBar Width="Auto" DockPanel.Dock="Top" />
<StatusBar DockPanel.Dock="Bottom" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<TreeView Name="categoryTreeView" Grid.Row="0" />
<ListView Name="clipListView" Grid.Row="1" />
</Grid>
</DockPanel>
</Window>
Set width and height properties to "auto"

Categories