Custom Expression to Define Width and Height in WPF - c#

I'm new in WPF so this is a very dummy question.
In Visual Studio -> Properties when I select a StackPanel (for example), I have the property Width. In this property I can click in the little square on the right and a menu is open. One of the option in the menu is "Custom Expression"
So here is my question:
Is possible to define Width and Height base in a Mathmatic expression?
<StackPanel Width="{Parent.Width - 100}">
</StackPanel>
Or something like that?
EDIT
I'm asking this because i'm intend to create a StackPanel that need to have a width 100 pixels lower than the Window. When window size was changed the StackPanel need to change to corresponding to this rule.

By default you cannot, and you have to use converters. Of course, especially since you are new in WPF, writing converters over and over for every simple operation like that might feel painful to you. So there are some custom markup extensions to reduce that pain. For example: https://quickconverter.codeplex.com/ (but there are others). With them it looks like that:
<Window x:Class="WpfApplication2.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:qc="http://QuickConverter.CodePlex.com/"
mc:Ignorable="d"
Title="MainWindow" Height="500" Width="500" x:Name="self">
<Grid x:Name="LayoutRoot">
<Rectangle Fill="Red"
Width="{qc:Binding '$P-100', P={Binding ElementName=self, Path=ActualWidth}}"
Height="{qc:Binding '$P-100', P={Binding ElementName=self, Path=ActualHeight}}" />
</Grid>
</Window>
Here we bound width and height of a rectangle to parent "self" element dimensions minus 100, without use of explicit converters.

You can do this with a binding to the parent element's width/height. However, instead of doing that, why not use the dynamic layout and just define your child container with a margin - in your example 50px - so that its width would be 100px less than the parent container.
So the answer to the theoretical question of "Can I set a calculated value of a property based on another element?" is yes, use a binding with a converter that performs the necessary calculation.
To the more important question of "Is there a simpler way to do create a responsive layout that takes the parent container into account?" the answer is also yes, use container composition with margins, padding and alignment to get the desired effect.

Related

How do you get XAML elements to scale to fit their containers?

I understand that there are a variety of ways to size child elements according to parent elements. If you're using a grid for example, you can use row and column definitions and you get lots of freedom regarding automatic sizes or fixed sizes or "star" sizes. However, if the child elements themselves have a fixed width and height then it won't matter if the parent tells the child to fill all available space. The child element will remain the same size.
I have a window that was designed to always display its contents at the same pixel dimensions no matter what size the window is resized to. Rather than go and change every single child element in every XAML page so that it doesn't have a fixed size, I'd like to get the main Grid to just scale to fit the window. So far the only way to get elements with fixed dimensions to display at different sizes is to use Transform scaling, either with a RenderTransform or a LayoutTransform. But if I go that route, I'll have to code the scaling in C# to respond to resizing events rather than have it happen automatically. Is there some native builtin way to do this in XAML? This feels like the kind of thing I should be able to do with some special property, or perhaps a ContentControl or ContentPresenter.
I've seen Resize WPF Window and contents depening on screen resolution but it's asking about conventional resizing and not scaling fixed elements. I've also seen How to make all controls resize accordingly proportionally when window is maximized? and that has the same problem though the second answer at least talks about handling resizing events.
Here's a simplified example of a fixed-dimension child element not resizing as desired:
<Window x:Class="WpfTest.Window1"
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"
mc:Ignorable="d"
Title="Window1" Height="200" Width="300" Background="LightBlue">
<Grid>
<Frame Background="Blue" Width="200" Height="100">
</Frame>
</Grid>
</Window>
Actual results:
Desired results:
As you can see, what I'm looking for is a sort of letterboxing effect, meaning I want the aspect ratio to be maintained. However, I haven't found a way to get automatic scaling even without worrying about the aspect ratio, so I thought I'd consider the letterboxing as a sort of second phase that I'd worry about later.
The control you are looking for is a Viewbox. It grows to fill its container (you can set the stretch style for the letterboxing) and scales all its contents accordingly. Just make it the root element of your application (or whatever you want stretched):
<Viewbox>
<Grid> //Or whatever
<OtherStuff>
</Grid>
</Viewbox>
Note that because the viewbox is scaling its contents traditional Grid behavior and similar will stop working since the size of the content never actually changes.
Another option is to use a MultiValueConverter to set the height and width.
You could give the Converter the ActualWidth and ActualHeight of the root container als parameters and let it calculate the needed aspect ratio.
A tutorial which describes the MultiValueConverter:
http://www.wpftricks.com/2017/05/wpf-multivalueconverter.html

Change default time of auto-hide timer of ScrollViewer scrollbars

When a ScrollViewer has scrollbars showing, and the cursor is not moved for around 3 seconds, the scrollbars auto hide.
Is there a way to set that time to more or less than the default time?
EDIT
Reproduce so:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer Height="500" Width="500">
<Grid Background="Blue" Height="1000" Width="1000">
</Grid>
</ScrollViewer>
</Grid>
Move the cursor over the ScrollViewer to show the scrollbar. Leave the cursor motionless for 3 seconds to see the scrollbar disappear. I want to change those 3 seconds to 1.
EDIT 2
Follow-up question - Why does this ScrollViewer's ScrollBars appear twice? .
I suppose I need to start breaking the habit of doing quickie answers in comments anyway so;
Carrying from the original comments above. The control style templates for Scrollbar have embedded ThemeAnimation's for FadeIn/FadeOut nested in various states in the VisualStateManager portion.
Being that they're animations inheriting in order of;
Object -> DependencyObject -> Timeline
...they do support Dependency Properties such as BeginTime and Duration that allows us to alter the default behavior of their action. So to remedy your scenario you have the options of either removing them entirely from their respective states within the VisualStateManager or you can alter the properties to better suit your needs of your own timeline requirements.
Doing this is just a matter of extracting the control template using either VS or Blend and either applying changes explicitly to a copy of the template or overriding the default globally.
Glad you found your remedy. :)

Make full screen wpf app look the same on all resolutions

I want to make a full screen WPF app that looks the same on all machines with different screen resoltion. I created my MainWindow.xaml with a 800*480 px resoultion. I made a menu on the top of the window like this:
<Grid Height="480" Width="800">
<Menu FontSize="25" Margin="0,0,0,442" >
<MenuItem Header="File" />
</Menu>
</Grid>
But when I started the app in Debug Mode, the menu was in the center of the screen. I guess it was because my screen resoultion is 1366*768 px.
So what should I do to make my program look the same on different resoultions in full screnn mode?
UPDATE: I want it to be like Photoshop for example. Photoshop looks almost the same on different resoultions. Images:
http://i.stack.imgur.com/W1SL6.png
http://i.stack.imgur.com/7KYxX.png
UPDATE : I just want to know what these values should be to make the program work like I want it to:
Height of Window,
Width of Window,
Height of Grid,
Width of Grid,
Sorry bros, I'm such a beginner :\
Another method is to use ViewBox:
<Viewbox StretchDirection="Both" Stretch="Uniform" />
For example:
<Window
Height="480"
Width="800">
<Viewbox StretchDirection="Both" Stretch="Uniform">
<Grid Height="480" Width="800">
</Grid>
</ViewBox>
</Window>
Now when you resize your window, all elements resize too.
It's not really going to be possible to make an application look exactly the same in every resolution. One of the problems with this is text - it's difficult to scale text in the same sense as you can a button, or a ListBox, or whatever.
But, one of the things you can do to make it so that your application looks substantially similar is to use relative positioning and sizing rather than absolute, as you are now.
I've rarely found it's useful or successful to use margins like the one you have above, where the Menu is offset by 400-some pixels. Typically, this ends up making your design look good only at the exact size at which you designed them. If you want this at the top of the control, you could do the following:
<Menu ... VerticalAlignment="Top" ...>
This would always have this menu aligned to the top of your Window. Likewise, if you wanted the menu to take up the same amount of relative vertical space in the window regardless of the absolute size of the window, you could use the Grid.RowDefinitions property:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="90*"/>
</Grid.RowDefinitions>
<Menu Grid.Row=0 />
</Grid>
This way, the Menu occupies the entire top row, and will consume 10% of the vertical space in the window regardless of resizing. There are some edge cases, obviously, particularly when controls get resized to the point where the text they contain cannot be seen anymore - if these are concerns you should use MinHeight and MinWidth on your Window or a specific control in order to provide a floor at which the control in question doesn't shrink anymore.
Note that, if you don't explicitly set the size of the Grid, it fills the entirety of its parent container by default - the entirety of the Window in this case. If you want your application to look the same, you can't give the parent Grid an absolute size like 800x480.

Autostretch datagrid within a window?

I've created a datagrid and placed it in a spot in a WPF form.
Now what I'm trying to do is have the datagrid change its size keeping the same proportions as its original placement with the WPF window changing size (hopefully that makes sense).
I've tried setting autostretch to true but that hasn't helped.
Got my computer with Visual Studio in my office, so can't test it :) but shouldn't this work if you set the alignments to stretch?
datagridObj.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
datagridObj.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
Sure it makes sense, but it sounds like you don't really understand how the WPF layout system works, and unless you do it will be really painful going forward. The short story is, you need to have an appropriate container - I recommend Grid - and have your DataGrid placed in that container. Then you can set margins and so on for the DataGrid to place it however you like, and provided it has its Width and Height set to Auto, it will keep with its parent container.
Now if you have several other controls in the picture, of course it's a bit more involved, but I still recommend keeping with Grids and splitting them into however many rows and columns you require, then setting the appropriate values for their Height/Width respectively - you can make some columns fixed in width, or a multiple of other column, or leave them as Auto and they will take up the remainder of the space.
The topic is much more involved of course, but you can find a quick primer on MSDN: http://msdn.microsoft.com/en-us/library/ms745058.aspx
If you'll remember just one thing, it should be this: Grids represent fluid layouts in WPF, use them as much as possible as opposed to Canvases. Of course StackPanel and DockPanel etc. have their own specific uses.
P.S. The visual studio designer makes a bit of mess of things usually, by setting margins and so on to make the drag and drop more intuitive, you should pay close attention to the properties it modifies and see if you're not better off positioning things manually by modifying the XAML (you usually are) once you sketched the layout out.
just as example
<Window x:Class=""
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid Margin="162,57,141,54"/>
</Grid>
</Window>
by default a DataGrid is
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
so you only need a Margin like Arno Saxena told you

C# WPF Window Width, MaxWidth, MinWidth ignored

I have a WPF Window defined in XAML like this:
<Window x:Class="com.some.company.window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My Cool Window"
x:Name="CoolWindow"
Height="435"
Width="70"
MinWidth="70"
MaxWidth="70"
Left="{PropertyState Default=0}"
Top="{PropertyState Default=0}"
Initialized="InitializeWindow"
ResizeMode="NoResize"
Style="{DynamicResource DefaultWindow}">
.....
.....
</Window>
The problem is that when the Window is created and displayed on the screen - it is ALWAYS larger than the 70 pixels I specified in the width definition. The width is probably 80-90 pixels. My width attributes are ignored. None of the contents inside the Window are larger than 70 pixels either.
Even when I try to resize the window with the grips, it will not let me resize it below a specific width. Is there some reason WPF is not letting me set the width of the window smaller? Is there a hidden minimum width value for every window? and how would I get around this?
EDIT:
When I add WindowsStyle="None" into the Window attribute, the width is correctly set to 70 pixels. However, this is not the style I want for the Window.
Thanks
You have set MinWidth to 70 and therefore size of your Window cant be less than that. BTW because of control box it's width seems to have a minimum limit of 132.
If we set WindowStyle="none" to remove the title and control box, we can make the Window even smaller.
<Window x:Class="WpfApplicationUnleashed.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:WpfApplicationUnleashed"
Title="" WindowStyle="None" Width="70">
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
</Grid>
</Window>
EDIT
To make the Window width to 70, while the close button, Title text still visible and no-resize use this:
<Window x:Class="WpfApplicationUnleashed.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:WpfApplicationUnleashed"
Title="My Window" WindowStyle="ToolWindow" Width="70" ResizeMode="NoResize">
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
</Grid>
</Window>
Since 70 is a very small width, you cant have minimize and maximize button along with close button.
70 that you have specified is not in pixels. WPF works on points and it actually sizes window to pixels based on Screen DPI (Dots per Inch).
I was able to do what I wanted by adding WindowStyle="ToolWindow" and ResizeMode="NoResize". This allowed me to keep the titlebar and the close button, while allowing the window's width to be set at 70pt.

Categories

Resources