I have a bit of experience with PowerShell but not with WPF. The following code runs fine in PowerShell and launches a jpg file in a window:
Param (
[String]$FilePath = "C:\SplashScreen.jpg"
)
Add-Type -AssemblyName PresentationFramework
[XML]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window"
WindowStartupLocation = "CenterScreen"
WindowStyle = "None"
ResizeMode = "NoResize"
SizeToContent = "WidthAndHeight">
<Image Source="$FilePath" />
<!-- Button to close on Esc -->
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$window.Activate()
$window.ShowDialog()
The only thing I need to add is the closing of the dialog when the escape key is pressed. The following code does just that:
<Window.CommandBindings>
<CommandBinding Command="Close" Executed="OnCloseCmdExecuted" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Close" Key="Escape" />
</Window.InputBindings>
private void OnCloseCmdExecuted(object sender, ExecutedRoutedEventArgs e)
{
this.Close();
}
Or this one:
public MainWindow()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(HandleEsc);
}
private void HandleEsc(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
}
Wherever I put the code in the XML it never seems to work and throws error. How can this be added?
That was a fun challange :-)
Try this:
Param (
[String]$FilePath = "C:\temp\Export\mypic.png"
)
Add-Type -AssemblyName PresentationFramework
[XML]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window"
WindowStartupLocation = "CenterScreen"
WindowStyle = "None"
ResizeMode = "NoResize"
SizeToContent = "WidthAndHeight">
<Image Source="$FilePath" />
<!-- Button to close on Esc -->
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$code = {
[System.Windows.Input.KeyEventArgs]$e = $args[1]
if ($e.Key -eq 'ESC')
{
$window.Close()
}
}
$null = $window.add_KeyUp($code)
$window.Activate()
$window.ShowDialog()
I found the idea here
https://www.reddit.com/r/sysadmin/comments/1u3c98/powershell_winform_on_close_event_handler_example/
and
https://books.google.ch/books?id=Noh4DwAAQBAJ&pg=PT1183&lpg=PT1183&dq=powershell+add_keyup&source=bl&ots=2Q42772co0&sig=ACfU3U2diUwUvvmbWoou003XNaOBLjLzQQ&hl=de&sa=X&ved=2ahUKEwiTqOLx3KXlAhUECewKHfR3AT0Q6AEwAnoECAkQAQ#v=onepage&q=powershell%20add_keyup&f=false
Related
I want to execute WinAPI commands from Powershell, e.g. press button on the WPF form, the Start button hides and shows
Create this code in powershell 5
Add-Type -AssemblyName 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:local="clr-namespace:WinAPI"
Height="367" Width="264" Title="Hide Start button" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Grid>
<Button x:Name = "StartButton" Content="Start button" Margin="10,60,11,0" Height="25" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Grid.ColumnSpan="2">
</Button>
</Grid>
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$button = $Window.FindName("StartButton")
#--------------------------------------------------------------------------------
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string ClassName, string WindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string windowName);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
"#
$TaskbarHWnd = New-Object System.IntPtr
$StartButtonHWnd = New-Object System.IntPtr
[bool]$show = $true
$button.Add_Click({
$show = !($show)
$TaskbarHWnd = [Win32]::FindWindow("Shell_TrayWnd", $null); # get taskbar handle
write-host $TaskbarHWnd
$StartButtonHWnd = [Win32]::FindWindowEx($TaskbarHWnd, [IntPtr]::Zero, "Start", $null); # get start button handle - doesn't work
write-host $StartButtonHWnd
# hide Start button
$result = if ($show) {0} Else {5}
#if ($show) {$result = 0} Else {$result = 5}
write-host $result
[Win32]::ShowWindow($StartButtonHWnd, $result);
})
$window.ShowDialog() | Out-Null
Command below doesn't work.
$StartButtonHWnd = [Win32]::FindWindowEx($TaskbarHWnd, [IntPtr]::Zero, "Start", $null);
The $StartButtonHWnd value = 0.
Why doesn't FindWindowEx return a handle?
And second question. The $show = !($show) command also doesn't work
What am I doing wrong?
Thanks
In a WPF DataGrid via PowerShell, I have added a context menu and MenuItems from an Array. I would like to get the header value of clicked MenuItem to handle the click event further. I had tried add_Click event to the MenuItem object but it does return any value. I'm looking for some ideas to get the Header value in this scenario (or) if there is any different better approach to achieve this goal. Thanks in advance.
[xml]$inputXML=#"
<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:Test"
Title="MainWindow" Height="275" Width="375">
<Window.InputBindings>
<KeyBinding x:Name="keyTest" Modifiers="Control" Key="N" Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
<Grid>
<DataGrid x:Name="dg" Margin="5,5,0,0" Height="250" Width="350" ColumnWidth="Auto" AlternationCount="1" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell" Background="White" ClipboardCopyMode="IncludeHeader" >
<DataGrid.ContextMenu >
<ContextMenu x:Name="cxmenu" />
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
"#
[xml]$XAML = $inputXML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($reader)
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'x:Name')]]") | %{Set-Variable -Name "$($_.Name)" -Value $Window.FindName($_.Name)}
#sample data
$DataSet = New-Object System.Data.DataSet
$Table = $DataSet.Tables.Add("Table")
$Properties = #("Country","Capital","Population")
$Properties | foreach {
$Column = New-Object System.Data.DataColumn($_)
$Table.Columns.Add($Column)
}
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
#populate datagrid
$DataView = New-Object System.Data.DataView($Table)
$array = New-Object System.Collections.ArrayList
[void] $array.AddRange($DataView)
$dg.clear()
$dg.ItemsSource = $array
$dg.IsReadOnly = $true
#add MenuItem to context menu
$cxMenuitem = New-Object Windows.Controls.MenuItem
$header = ('Test1','Test2','Test3')
for ($i = 0; $i -le $header.Count -1; $i++)
{
$cxMenuitem.Header = [string]$header[$i]
$cxMenu.Items.Add($cxMenuitem.Header)
}
$cxMenuitem.Add_Click({
#Get the Header of the clicked MenuItem from Context Manu here for further handling
[System.Windows.MessageBox]::Show($cxMenu.Items)
})
#Display Form
$Window.ShowDialog() | Out-Null
You should be able to cast $args[0] to a MenuItem and access its Header property directly:
$cxMenuitem.Add_Click({
$sender = [System.Windows.Controls.MenuItem]$args[0]
# Use $sender.Header ...
})
I am limiting drag and drop actions to a WPF listbox control in Powershell to only allow text files to be dropped. I would like to use the System.Windows.DragDropEffects property to prevent the drop action on the DragEnter event as it also changes the mouse cursor providing user feedback for the denied drop action. I can still limit the action taken on the dropped file by validating the file extension on the Drop event. But I would prefer to prevent the drop action all together for smoother user interaction.
In debugging I've verified that the DragDropEffect property is being set correctly, however the event handler does not seem to reflect the change. I believe it might be a limitation trying to use the DragEventArgs Class to monitor the event through the Powershell pipeline.
Code for the WPF listbox DragEnter event is below. I noticed that the object passed in the $_ pipeline is of the System.Windows.DragEventArgs class.
$listbox.Add_DragEnter({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
if(([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
$_.Effects = [System.Windows.DragDropEffects]::All
Write-Host 'Dropfile is a .TXT'
}
else {
$_.Effects = [System.Windows.DragDropEffects]::None
Write-Host 'Dropfile is NOT a .TXT'
}
}
}
})
Setting DragDropEffect property using WinForms listbox works as expected. The mouse changes and the drop event is prevented. However here, the object passed in the $_ pipeline is of the System.Windows.Forms.DragEventArgs class.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object Windows.Forms.Form
$listbox = New-Object Windows.Forms.ListBox
$listbox.AllowDrop = $true
$listbox.Add_DragEnter({
$_.Effect = [Windows.Forms.DragDropEffects]::None
})
$form.Controls.Add($listbox)
$form.ShowDialog()
Full test code below for WPF:
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
[xml]$xaml = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Remote Execution Toolkit" Height="300" Width="300">
<Grid>
<ListBox x:Name="listBox" AllowDrop="True" Height="250" HorizontalAlignment="Center" Width="250">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}">
<TextBlock Text="{Binding}" TextAlignment="Left" Width="Auto" />
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
'#
# Load XAML Reader
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )
# Map XAML Controls
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach {
New-Variable -Name $_.Name -Value $Window.FindName($_.Name) -Force
}
# Drag Event to validate file extensions for drop effect
$listbox.Add_DragEnter({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
if(([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
$_.Effects = [System.Windows.DragDropEffects]::All
Write-Host 'Dropfile is a .TXT'
}
else {
$_.Effects = [System.Windows.DragDropEffects]::None
Write-Host 'Dropfile is NOT a .TXT'
}
}
}
})
$Window.ShowDialog()
Any thoughts or suggestions is appreciated!!
After tons of Google-Foo, running Snoop WPF to monitor events, and trial and error, I realized that I was simply subscribing to the wrong Drag Event. To achieve the result of continuously displaying the operation not allowed cursor, you must use the DragOver Event.
$listbox.Add_DragOver({
...
$_.Effects = [System.Windows.DragDropEffects]::None
...
})
Apparently, when using WPF code in Powershell, the DragEnter event only fires once allowing the cursor to change back, whereas the DragOver event continuously fires while the mouse is over the control maintaining display of the operation not allowed cursor.
Hope this is able to save another fellow developer down the road save some time.
This worked for me by adding $_.Handled = $true after changing the $_.Effects.
This was taken from here: https://stackoverflow.com/a/44321363/8262102
# Drag and drop UI example to a list box.
Add-Type -AssemblyName PresentationFramework, System.Drawing, System.Windows.Forms, WindowsFormsIntegration
[xml]$xaml = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test Drop Form" Height="300" Width="500">
<Grid>
<ListBox x:Name="listBox" AllowDrop="True" Height="250" HorizontalAlignment="Center" Width="475">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}">
<TextBlock Text="{Binding}" TextAlignment="Left" Width="Auto" />
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
'#
# Load XAML Reader
$reader = New-Object System.Xml.XmlNodeReader $xaml
$Form = [Windows.Markup.XamlReader]::Load($reader)
# Map XAML Controls
$formNamedNodes = $xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'Name')]]") | Sort
$formNamedNodes | ForEach-Object {
Set-Variable -Name $_.Name -Value $Form.FindName($_.Name) # Set the variable names to the same as that of the controls.
}
# Drop event to add the files to the list box.
$listbox.Add_Drop({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
if (([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
Write-Host "Dropped file extension: $filename is .TXT"
$listBox.Items.Add($filename)
}
else {
Write-Host "Dropped file extension: $filename is NOT .TXT"
}
}
}
})
# The DragOver event is there to handle changing the dropped effects.
$listbox.Add_DragOver({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
if (([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
$_.Effects = [System.Windows.DragDropEffects]::All
Write-Host "$filename is a .TXT"
}
else {
$_.Effects = [System.Windows.DragDropEffects]::None
Write-Host "$filename is NOT a .TXT"
}
$_.Handled = $true # This is there to handle the effect. This needs to be below $_.Effect.
}
}
})
$Form.WindowStartupLocation = "CenterScreen"
$Form.ShowDialog()
I used ISE-Sterioids template to create a simple 3 field WPF form that asks for three things:
- ID
- Email
- Reference
I have it sucessfully working with these fields when using the OK and Cancel buttons, but I would like to capter "Enter" to submit the form and "Escape" to cancel the form, but I am having difficulty adding the events.
I have tried similar code to the technet article here; but as this isn't using WPF I think I am missing something
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{$x=$objTextBox.Text;$objForm.Close()}})
My code here:
#region XAML window definition
# Right-click XAML and choose WPF/Edit... to edit WPF Design
# in your favorite WPF editing tool
# Default Form Values
$123 = 'ID'
$toEmail = 'email address'
$ref = "ref"
$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" mc:Ignorable="d"
MinWidth="200"
Width ="400"
SizeToContent="Height"
Title="Proofing script"
Topmost="True">
<Grid Margin="10,2,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- <TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="5">Please enter your details:</TextBlock> -->
<TextBlock Grid.Column="0" Grid.Row="1" Margin="5"><Run Text="Number:"/></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="2" Margin="5"><Run Text="To Email :"/></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="3" Margin="5"><Run Text="Salesforce Ref:"/></TextBlock>
<TextBox x:Name="TxtName" Grid.Column="1" Grid.Row="1" Margin="5"/>
<TextBox x:Name="TxtEmail" Grid.Column="1" Grid.Row="2" Margin="5"/>
<TextBox x:Name="ref" Grid.Column="1" Grid.Row="3" Margin="5"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,5,0,0" Grid.Row="4" Grid.ColumnSpan="2">
<Button x:Name="ButOk" MinWidth="80" Height="22" Margin="5" Content="OK" />
<Button x:Name="ButCancel" MinWidth="80" Height="22" Margin="5" Content="Cancel" IsCancel="True" />
</StackPanel>
</Grid>
</Window>
'#
#endregion
#region Code Behind
function Convert-XAMLtoWindow
{
param
(
[Parameter(Mandatory)]
[string]
$XAML,
[string[]]
$NamedElement=$null,
[switch]
$PassThru
)
Add-Type -AssemblyName PresentationFramework
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
$result = [Windows.Markup.XAMLReader]::Load($reader)
foreach($Name in $NamedElement)
{
$result | Add-Member NoteProperty -Name $Name -Value $result.FindName($Name) -Force
}
if ($PassThru)
{
$result
}
else
{
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
}
function Show-WPFWindow
{
param
(
[Parameter(Mandatory)]
[Windows.Window]
$Window
)
$result = $null
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
#endregion Code Behind
#region Convert XAML to Window
$window = Convert-XAMLtoWindow -XAML $xaml -NamedElement 'ButCancel', 'ButOk', 'ref', 'TxtEmail', 'TxtName' -PassThru
#endregion
#region Define Event Handlers
# Right-Click XAML Text and choose WPF/Attach Events to
# add more handlers
$window.ButCancel.add_Click(
{
$window.DialogResult = $false
}
)
$window.ButOk.add_Click(
{
$window.DialogResult = $true
}
)
#endregion Event Handlers
#region Manipulate Window Content
#$window.TxtName.Text = $env:username
$window.ref.Text = $ref
$window.TxtName.Text = $123
$window.TxtEmail.Text = $toEmail
$null = $window.TxtName.Focus()
#endregion
# Show Window
$result = Show-WPFWindow -Window $window
If i use ISE Steroids to add an event I get similar to this
$window.ButOk.add_KeyDown{
# remove param() block if access to event information is not required
param
(
[Parameter(Mandatory)][Object]$sender,
[Parameter(Mandatory)][Windows.Input.KeyEventArgs]$e
)
# add event code here
}
Working with key down events can be a bit tricky since these are depending on the current UIFocus, therefor your button does not act on any keydown event since it is not in the current focus scope when you´re just editing the Textboxes. Since you only plan on using this simple form, I would suggest adding an event handler to your window that handles this. So your code behind section should look something like this:
$window.add_KeyDown{
param
(
[Parameter(Mandatory)][Object]$sender,
[Parameter(Mandatory)][Windows.Input.KeyEventArgs]$e
)
if($e.Key == $Key.Return)
{
$window.DialogResult = $true
}
if($e.Key -eq $Key.Escape)
{
$window.DialogResult = $false
}
}
The accepted answer didn't work for me yet but it helped me a lot so I'm answering here.
I made a simple form with https://poshgui.com/Editor adding the code in the answer and got the error message:
System.Management.Automation.RuntimeException: Unable to find type [Windows.Input.KeyEventArgs].
My TextBox element has got the focus, so I created the event for it:
TextBoxSearchInput.Add_KeyDown{
param (
[Parameter(Mandatory)][Object]$sender,
[Parameter(Mandatory)][System.Windows.Forms.KeyEventArgs]$e
)
if($e.Key -eq $Key.Return){
$FormOkButton.PerformClick()
}
if($e.Key -eq $Key.Escape){
$Form.close()
}
}
There may be a better way than "PerformClick" but for now it works.
I know this thread here is old but I was also sucessfull with this:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# Build Form
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Any Name"
$Form.Size = New-Object System.Drawing.Size(700,150) #use any size
$Form.StartPosition = "CenterScreen" # I prefer this
$Form.Topmost = $true
$form.KeyPreview = $true #This is the important part
$form.Add_KeyDown{
param (
[Parameter(Mandatory)][Object]$sender,
[Parameter(Mandatory)][System.Windows.Forms.KeyEventArgs]$e
)
if($_.KeyCode -eq "Escape"){
$Form.close()
}
}
I am trying to make the background of a text box an image in Powershell.
Im using the xaml converter from http://blogs.technet.com/b/heyscriptingguy/archive/2014/08/01/i-39-ve-got-a-powershell-secret-adding-a-gui-to-scripts.aspx
to load a xaml form:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UAT" Height="300" Width="300">
<Grid>
<Button Name="btnGo" Content="Go" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="207,240,0,0"/>
<TextBox Name="txtOut" HorizontalAlignment="Left" Height="233" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="272" Margin="10,0,0,0"/>
</Grid>
</Window>
The .ps1 file:
Add-Type –assemblyName PresentationFramework
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName WindowsBase
.\loadDialog.ps1 -XamlPath '.\UAT.xaml' 2>> Errors.txt
$txtOut.text = ""
$btnGo.add_Click({
$txtOut.text = ""
$image = New-Object System.Windows.Media.Brush
$image = ".\bg1.png" #.Source
$txtOut.background = $image
})
$xamGUI.ShowDialog() | out-null 2>> Errors.txt
I get an error:
New-Object : Constructor not found. Cannot find an appropriate constructor for type System.Windows.Media.Brush.
At UAT.ps1:40 char:24
+ $image = New-Object <<<< System.Windows.Media.Brush
+ CategoryInfo : ObjectNotFound: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand
Exception setting "Background": "Cannot convert value ".\bg1.png" to type "System.Windows.Media.Brush". Error: "Token is not valid.""
At UAT.ps1:44 char:13
+ $txtOut. <<<< background = $image
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
I'm already loading:
PresentationFramework,
PresentationCore,
WindowsBase
What am I missing?
Is there a better way to do this?
Here is an example that works for me. It's a bit convoluted, but that's WPF, for me anyway.
You have to define a uri (path to image). Based on that you load a BitmapImage and use this to create an ImageBrush. This can in turn be set as the background of your text box.
Add-Type –assemblyName WindowsBase
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName PresentationFramework
[xml]$xaml = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UAT" Height="300" Width="300">
<Grid>
<Button Name="btnGo" Content="Go" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="207,240,0,0"/>
<TextBox Name="txtOut" HorizontalAlignment="Left" Height="233" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="272" Margin="10,0,0,0"/>
</Grid>
</Window>
'#
$reader=(New-Object Xml.XmlNodeReader $xaml)
$MainForm=[Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[#Name]") | %{Set-Variable -Name ($_.Name) -Value $MainForm.FindName($_.Name) -Scope Global}
$btnGo.add_Click({
$txtOut.text = ""
$uri = new-object system.uri("d:\documents\MAP - Discovery.png")
$imagesource = new-object System.Windows.Media.Imaging.BitmapImage $uri
$imagebrush = new-object System.Windows.Media.ImageBrush $imagesource
$txtOut.background = $imagebrush
})
$MainForm.ShowDialog() | out-null