C
C#2y ago
Turwaith

✅ WPF Window is too big when Height and Width are bound to a property

I have a simple WPF MVVM application where I want the code to be able to response to window size changes, so I bound Height and Width of the window to respective C# properties. Now the designer shows the window in the correct size, but when I run the app, the window becomes a lot wider. The properties are never set except at their declaration. When I replace the height and width bindings with fixed values in the xaml, it works. How do I get this working using those bindings?
29 Replies
Anton
Anton2y ago
show us your code
Turwaith
TurwaithOP2y ago
This is the xaml file
<Window x:Class="HexagonGenerator.GUI.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:local="clr-namespace:HexagonGenerator.GUI"
mc:Ignorable="d"
Title="MainWindow" Height="{Binding WindowHeight}" Width="{Binding WindowWidth}" ResizeMode="NoResize">

<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>


<Grid>

<ItemsControl ItemsSource="{Binding CanvasHexagons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">

</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

</ItemsControl>

</Grid>
</Window>
<Window x:Class="HexagonGenerator.GUI.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:local="clr-namespace:HexagonGenerator.GUI"
mc:Ignorable="d"
Title="MainWindow" Height="{Binding WindowHeight}" Width="{Binding WindowWidth}" ResizeMode="NoResize">

<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>


<Grid>

<ItemsControl ItemsSource="{Binding CanvasHexagons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">

</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

</ItemsControl>

</Grid>
</Window>
and this is the view model:
internal class MainViewModel : BaseNotifier
{
private ObservableCollection<Shape> canvasHexagons;

public ObservableCollection<Shape> CanvasHexagons { get => canvasHexagons; set => SetProperty(ref canvasHexagons, value); }

public int WindowWidth { get; set; } = 700;
public int WindowHeight { get; set; } = 450;

public ObservableCollection<Hexagon> AllHexagons { get; set; }

public MainViewModel()
{
AllHexagons = new ObservableCollection<Hexagon>();
CanvasHexagons = new ObservableCollection<Shape>();

CreateTestHexagon(new Double2(WindowWidth / 2, WindowHeight / 2), 20);
DrawHexagonsToView();
}

private void CreateTestHexagon(Double2 center, double sideLength)
{
AllHexagons.Clear();
AllHexagons.Add(new Hexagon(center, sideLength));
}

private void DrawHexagonsToView()
{
CanvasHexagons.Clear();

foreach (var item in AllHexagons)
{
Polygon currentHexagon = new Polygon();

foreach (var point in item.Corners)
{
currentHexagon.Points.Add(new System.Windows.Point(point.X, point.Y));
}

currentHexagon.StrokeThickness = 2;
currentHexagon.Stroke = new SolidColorBrush(Colors.Black);
CanvasHexagons.Add(currentHexagon);
}
}
}
internal class MainViewModel : BaseNotifier
{
private ObservableCollection<Shape> canvasHexagons;

public ObservableCollection<Shape> CanvasHexagons { get => canvasHexagons; set => SetProperty(ref canvasHexagons, value); }

public int WindowWidth { get; set; } = 700;
public int WindowHeight { get; set; } = 450;

public ObservableCollection<Hexagon> AllHexagons { get; set; }

public MainViewModel()
{
AllHexagons = new ObservableCollection<Hexagon>();
CanvasHexagons = new ObservableCollection<Shape>();

CreateTestHexagon(new Double2(WindowWidth / 2, WindowHeight / 2), 20);
DrawHexagonsToView();
}

private void CreateTestHexagon(Double2 center, double sideLength)
{
AllHexagons.Clear();
AllHexagons.Add(new Hexagon(center, sideLength));
}

private void DrawHexagonsToView()
{
CanvasHexagons.Clear();

foreach (var item in AllHexagons)
{
Polygon currentHexagon = new Polygon();

foreach (var point in item.Corners)
{
currentHexagon.Points.Add(new System.Windows.Point(point.X, point.Y));
}

currentHexagon.StrokeThickness = 2;
currentHexagon.Stroke = new SolidColorBrush(Colors.Black);
CanvasHexagons.Add(currentHexagon);
}
}
}
Denis
Denis2y ago
If you are trying to draw shapes that scale based on the window size, I believe you can use a view box
Anton
Anton2y ago
I don't see the height and width being updated in your code
Turwaith
TurwaithOP2y ago
It does not yet. That's not the point/the promlen My problem is that when I run the program, my window is definitely not 700 by 450 pixels but a whole lot wider
Anton
Anton2y ago
"I have a simple WPF MVVM application where I want the code to be able to response to window size changes, so I bound Height and Width of the window to respective C# properties."
Turwaith
TurwaithOP2y ago
I wrote this as an explanation why I bound the window size to properties and didn't hard code it in the xaml
Anton
Anton2y ago
try setting the data context in the constructor that might be the issue
Turwaith
TurwaithOP2y ago
In the constructor? You mean within the Window-Tag in the xaml?
Anton
Anton2y ago
in the code behind before you initialize the component
Turwaith
TurwaithOP2y ago
alright, I gotta try this thx
Klarth
Klarth2y ago
I can't get it to work either as-is. What you can do instead is bind the min/max (but you need to account for the title bar height). eg.
MaxWidth="{Binding WindowWidth}"
MaxHeight="{Binding WindowHeight}"
MinWidth="{Binding WindowWidth}"
MinHeight="{Binding WindowHeight}"
MaxWidth="{Binding WindowWidth}"
MaxHeight="{Binding WindowHeight}"
MinWidth="{Binding WindowWidth}"
MinHeight="{Binding WindowHeight}"
Alternatively, you can try binding <Grid Width="{Binding WindowWidth}" Height="{Binding WindowHeight}"> and use SizeToContent="WidthAndHeight" It sometimes makes more sense to define the client size of the content instead of directly constricting the window.
Turwaith
TurwaithOP2y ago
That worked, thank you! I didn't think of that but in my case this definitely makes more sense
Klarth
Klarth2y ago
That's the approach I would use. Let the window resize itself based on content if it's relatively simple (and not a huge window). If the size can get bigger than the monitor, then it might not be a good fit.
Turwaith
TurwaithOP2y ago
Now I only need to get it responsive to window size changes. I need some event to listen to this since now the window size is not directly bound to some property
Klarth
Klarth2y ago
Yeah, there's an event for that on <Window>.
Turwaith
TurwaithOP2y ago
So I'd catch that event in the code behind and adjust the numbers in the view model accordingly?
Klarth
Klarth2y ago
Looking back, you had ResizeMode="NoResize" in the original. So how is it getting resized?
Turwaith
TurwaithOP2y ago
That's not gonna be there for much longer
Klarth
Klarth2y ago
Why? Something has to be in charge of defining the size.
Turwaith
TurwaithOP2y ago
I just set it to noresize when testing out different ways to solve my initial problem. It will be user resizable in the end
Klarth
Klarth2y ago
The solution will need redesigned then. I would try to avoid letting your VM control the actual window size if you can avoid that. At least through bindings.
Turwaith
TurwaithOP2y ago
The problem is, in the end I will have a grid of hexagons. And they need to be able to resize according to the view size. And since I calculate the hexagons all from scratch and use the view size and the amount of hexagons I want to calculate their size, I somehow need them to respond to view size changes
Klarth
Klarth2y ago
I would probably subscribe to the top-level Grid's SizeChanged event. In it, set the VM's width/height properties and bind the Canvas width/height to them. Alternatively, you could set them directly in code-behind. Your VM is already using some View concepts anyways (Shape and brushes). Alternatively, you could try a 100x100 canvas and use Viewbox to scale it to the entire window. I'm not sure if there are significant downsides, but I've used it to scale fonts well.
Turwaith
TurwaithOP2y ago
Alright I will try that when I get to it, thanks!
Klarth
Klarth2y ago
If you do that, then you don't even need to update your shapes when the screen resizes. Viewbox will take care of it automatically...might get weird stretching though if it's not the same aspect ratio.
Turwaith
TurwaithOP2y ago
I want the hexagons to keep their ratio though.... well I'm not there yet, I will try to solve this when I get there.... If it doesn't work, I will write it here or make a new post
Klarth
Klarth2y ago
Ok, then you'll need <Viewbox Stretch="Uniform"> or UniformToFill if you try Viewbox.
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server