WPF Grid в Powershell режут по высоте - PullRequest
2 голосов
/ 30 января 2020

Я хочу нарисовать некоторую информацию с помощью Powershell на фоновом изображении. Я использую форму WPF для написания этой информации, для лучшего форматирования / оформления. Проблема в том, что DataGrid обрезают по высоте, когда мне приходится получать sh информацию, которую я не понимаю. Я попытался с MaxHeight и другими другими свойствами, но не смог это исправить.

Add-Type -AssemblyName PresentationFramework, System.Drawing

[void][System.Reflection.Assembly]::LoadWithPartialName('PresentationFramework') 
[xml]$xaml = @' 
<Window 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:WpfApp1" SizeToContent="WidthAndHeight"
        Name="window" Height="Auto" Width="Auto" Background="Blue" WindowStyle="ToolWindow">
    <Window.Resources>
        <Style TargetType="Grid">
            <Setter Property="ShowGridLines" Value="True"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Width" Value="Auto"/>
            <Setter Property="Height" Value="Auto"/>
        </Style>
        <Style TargetType="TableCell">
            <Setter Property="LineHeight" Value="Auto"/>
            <Setter Property="BorderThickness" Value="1"/>
        </Style>
        <Style TargetType="RowDefinition" >
            <Setter Property="Height" Value="Auto"/>
        </Style>
        <Style TargetType="TableColumn">
            <Setter Property="Width" Value="Auto"/>
        </Style>
        <Style TargetType="TextBlock" >
            <Setter Property="FontFamily" Value="Consolas" />
            <Setter Property="FontSize" Value="20" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="Margin" Value="0" />
            <Setter Property="Padding" Value="0" />
        </Style>
        <Style TargetType="DataGrid">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="GridLinesVisibility" Value="All"/>
            <Setter Property="HeadersVisibility"  Value="None"/>
        </Style>
        <Style TargetType="DataGridRow">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Height" Value="Auto"/>
        </Style>
        <Style TargetType="DataGridCell">
            <Setter Property="Height" Value="Auto"/>
            <Setter Property="Foreground" Value="White" />
            <Setter Property="FocusVisualStyle" Value="{x:Null}" />
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="FontFamily" Value="Consolas" />
            <Setter Property="FontSize" Value="20" />
        </Style>
    </Window.Resources>
    <Grid Name="Grid1" >
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,0,20" FontSize="30"><TextBlock FontSize="30" Foreground="#FFCBCBCB">This</TextBlock> is my Header!</TextBlock>
        <DataGrid Grid.Row="1" Grid.Column="0" Name="DG1" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="Auto" CanUserResize="False" CanUserReorder="False" />
                <DataGridTextColumn Header="Spacer" Binding="{Binding Spacer}" Width="50" CanUserResize="False" CanUserReorder="False" />
                <DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="Auto" CanUserResize="False" CanUserReorder="False" />
            </DataGrid.Columns>
        </DataGrid>
        <TextBlock Grid.Row="2" Grid.Column="0" Padding="0,50,0,0">This is my Footer</TextBlock>
    </Grid>
</Window>
'@

# Read XAML 
$reader=(New-Object System.Xml.XmlNodeReader $xaml)

try{
    $WpfApp1=[Windows.Markup.XamlReader]::Load( $reader )
    }
catch{
    Write-Error "Unable to parse XML, with error: $($Error[0])`n Ensure that there are NO SelectionChanged or TextChanged properties (PowerShell cannot process them)"
    throw
}

# Store Form Objects In PowerShell 
$xaml.SelectNodes("//*[@Name]") | %{"trying item $($_.Name)";
    try {Set-Variable -Name "WPF_$($_.Name)" -Value $WpfApp1.FindName($_.Name) -ErrorAction Stop}
    catch{throw}
}

# Fülle Grid
for ($i=1; $i -le 60; $i++) {
    $WPF_DG1.AddChild([pscustomobject]@{Name='Test';Value=$i})   
}

$WPF_window.AllowsTransparency = $True
$WPF_window.Opacity = 0
$WPF_window.ShowInTaskbar = $False
$WPF_window.ShowActivated = $False
$WPF_window.WindowStyle = 'None'

$WpfApp1.Add_ContentRendered({
    $WpfApp1.Close()
})
$WpfApp1.ShowDialog() | out-null

[int]$infoHeight = $WPF_Grid1.ActualHeight
[int]$infoWidth = $WPF_Grid1.ActualWidth

[string]::Format("WPF_Grid1 Größe: {0}x{1}", $infoWidth, $infoHeight) | Write-Host

# Speichere WPF-Grid in Bitmap
$rBmp = New-Object Windows.Media.Imaging.RenderTargetBitmap($infoWidth, $infoHeight, 96, 96, ([Windows.Media.PixelFormats]::Pbgra32))
$rBmp.Render($WPF_Grid1)

# Konvertiere Bitmap 
$ms = New-Object System.IO.MemoryStream
$enc = New-Object System.Windows.Media.Imaging.BmpBitmapEncoder
$enc.Frames.Add([Windows.Media.Imaging.BitmapFrame]::Create($rBmp))
$enc.Save($ms)
$infoImg = [System.Drawing.Image]::FromStream($ms)
$infoImg.MakeTransparent()

[string]::Format("infoImg Größe: {0}x{1}", $infoImg.width, $infoImg.height) | Write-Host

# Lese Quell-Bild
$srcImg = [System.Drawing.Image]::FromFile($Env:WinDir + "\Web\Screen\img100.jpg")
[string]::Format("srcImg Größe: {0}x{1}", $srcImg.width, $srcImg.height) | Write-Host

# Erstelle ein Bitmap in das gezeichnet wird
$dstBmp = New-Object System.Drawing.Bitmap(([int]($srcImg.width)),([int]($srcImg.height)))

# Erstelle Graphics Objekt
$gUnit = [Drawing.GraphicsUnit]::Pixel
$gImg = [System.Drawing.Graphics]::FromImage($dstBmp)

$gImg.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality
$gImg.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
$gImg.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$gImg.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality

# Zeichne das Quell-Bild in unser gImg
$srcRect = New-Object Drawing.Rectangle(0, 0, $srcImg.Width, $srcImg.Height)
$gImg.DrawImage($srcImg, $srcRect, 0, 0, $srcImg.Width, $srcImg.Height, $gUnit)

# get scale ratio
$xpos = 150
$ypos = 150
$ratio = 0.1
while($($infoImg.Height*$ratio) -le $(($srcImg.Height-$ypos)*0.75))
{
    $ratio += 0.1
    #[string]::Format("if ({0} -le {1})", $($infoImg.Height*$ratio), $($srcImg.Height*0.75)) | Write-Host
}
[string]::Format("infoRect: X={0} Y={1} RATIO={2}", $xpos, $ypos, $ratio) | Write-Host

# Zeichne das Info-Bild in unser gImg
$infoRect = New-Object Drawing.Rectangle($xpos, $ypos, $($infoImg.Width*$ratio), $($infoImg.Height*$ratio))
$gImg.DrawImage($infoImg, $infoRect, 0, 0, $infoImg.Width, $infoImg.Height, $gUnit)

# Aufräumen
Remove-Item –Path "$($Env:Temp)\Test-*.jpg" -Force

# Neue Ausgabedatei erstellen
$dstFile = "$($Env:Temp)\Test-$(get-date -Format yyyy-MM-dd-HH-mm).jpg"
$dstBmp.save($dstFile, [System.Drawing.Imaging.ImageFormat]::Jpeg)

Я добавил полный рабочий тестовый код (на win 10 - из-за фонового изображения вы можете изменить также на другое изображение) , который показывает проблему.

Проверьте полученный тест - *. jpg в% Temp% - мы должны увидеть нижний колонтитул сетки. Когда мы изменяем значение l oop на максимум 30, все работает ... но мне нужно иногда отображать больше информации.

Надеюсь, кто-то может указать, что вызывает проблему. На net не нашел ничего идентичного и работал над ним часами ....

1 Ответ

1 голос
/ 02 февраля 2020

В WPF, когда ваше приложение визуализируется, фактическая высота устанавливается равной максимуму границ вашего монитора. Это имеет смысл, поскольку в обычное время вы не хотите, чтобы окно было больше, чем ваш монитор.

Снимок, который вы делаете из своего окна, учитывает только визуализированную часть, в которой отсутствуют некоторые элементы в вашем случае.

Чтобы обойти это, вы хотите, чтобы окно go настолько большой, насколько захочется. Поскольку вы не знаете высоту окна, здесь вы можете установить произвольное значение MinHeight, чтобы убедиться, что ваше окно охватывает все.

Поскольку оно не будет отображаться на экране и нам все равно, если окно выходит за границы, мы будем использовать 3000 здесь.

Оттуда мы будем использовать ваш Add-ContentRendered скрипт-блок и вычислить фактическую высоту нашей сетки (заголовок) + Датагрид + нижний колонтитул).

Затем мы сбросим атрибут MinHeight и Height нашего окна на этот размер, поэтому наш снимок не содержит пустого пространства.

Вот уязвимая часть вашего кода и как это выглядит с модификацией

# Arbitrary value to make sure all of our content will be captured
$WPF_window.MinHeight = 3000

$WpfApp1.Add_ContentRendered( {
        $MinHeight = ($WPF_Grid1.RowDefinitions.ActualHeight | Measure-Object -Sum) |
        Select -ExpandProperty Sum
        $WPF_window.MinHeight = $MinHeight
        $WPF_window.Height = $MinHeight
        $WpfApp1.Close()
    })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...