Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Window Properties in ViewModel

Tags:

mvvm

wpf

xaml

I'm building a WPF application in which I have a need to get the width, height and locations of the window from my view model. I'm using the following XAML:

<Window x:Class="ScreenCapture.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"
        mc:Ignorable="d"
        Height="{Binding Height, Mode=OneWayToSource, FallbackValue=300}"
        Width="{Binding Width, Mode=OneWayToSource, FallbackValue=300}"
        Title="MVVM Light Application"
        Top="{Binding Top, Mode=OneWayToSource}"
        Left="{Binding Left, Mode=OneWayToSource}"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="13*" />
            <ColumnDefinition Width="265*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="25" />
        </Grid.RowDefinitions>
        <TextBlock FontSize="36"
                   FontWeight="Bold"
                   Foreground="Purple"
                   Text="{Binding Welcome}"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   TextWrapping="Wrap" Grid.Column="1" Margin="19,70,32,70" />
        <Button Grid.Row="1" Content="Capture" Grid.ColumnSpan="2" Command="{Binding Capture}" />
    </Grid>
</Window>

In my view model, the values for the Top, Left work fine, but, the Width and Height properties are both NaN. I have properties like this for each of the attributes I'm binding on:

private double height;

public double Height
{
    set
    {
        height = value;
    }
}

Any idea why the values are coming back NaN? More importantly, what can I do to get the values I'm looking for?

EDIT: I realize this is a bit off, but I need to capture a screenshot of the application from the view model. The view model contains additional properties that I didn't paste, but are necessary in order to implement the desired functionality. For the curious, below is my method for capturing the screen:

private void CaptureScreen()
{
    int x = Convert.ToInt32(left);
    int y = Convert.ToInt32(top);
    int w = Convert.ToInt32(width);
    int h = Convert.ToInt32(height);
    Bitmap image = new Bitmap(w, h);
    Graphics graphics = Graphics.FromImage(image);

    graphics.CopyFromScreen(x, y, x, y, new Size(w, h), CopyPixelOperation.SourceCopy);

    // Do something with the image
}
like image 406
senfo Avatar asked Feb 03 '23 13:02

senfo


2 Answers

As mzabsky said, you need to use ActualWidth and ActualHeight. The problem here is that they are readonly and you can't do a OneWayToSource Binding on a readonly Dependency Property.

However, there are workarounds.
See the following question: Pushing read-only GUI properties back into ViewModel

The attached behavior provided by Kent Boogaart lets you do this

<Window ...
        SizeObserver.Observe="True"
        SizeObserver.ObservedWidth="{Binding Width, Mode=OneWayToSource}"
        SizeObserver.ObservedHeight="{Binding Height, Mode=OneWayToSource}">

or you can try the solution I made for this called PushBinding which can be used to push readonly DP's to the viewmodel. In your case the usage would look like this

<Window ...>
    <pb:PushBindingManager.PushBindings> 
        <pb:PushBinding TargetProperty="ActualHeight" Path="Height"/> 
        <pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>
    </pb:PushBindingManager.PushBindings> 
</Window> 

You can download a demo project using PushBinding here if you're interested: https://www.dropbox.com/s/eqkmsp0q7hb568z/PushBindingInStyleDemo.zip?dl=0

like image 128
Fredrik Hedblad Avatar answered Feb 06 '23 09:02

Fredrik Hedblad


You are supposed to use ActualWidth and ActualHeight as binding targets for one way to source binding, not Height and Width - those are desired size, not actual size. Width and Height is NaN unless you specifically set them to some value.

Of course, another question is that this doesn't seem like proper use of view model.

like image 33
Matěj Zábský Avatar answered Feb 06 '23 11:02

Matěj Zábský