I'm writing a PowerShell script that uses WPF to create a small GUI. I want to add detection for when text in a ComboBox is changed, using the TextBoxBase.TextChanged event.
Here are a few things I've tried:
#Build the GUI; the next line has to NOT be indented
[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="Export Readable Prefs" WindowStartupLocation="CenterScreen"
Width="600" Height="200" ShowInTaskbar="True">
<DockPanel Margin="5">
<ComboBox Grid.Row="0" x:Name="ComboNewTemplate" IsEditable="true" />
</DockPanel>
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$Window = [Windows.Markup.XamlReader]::Load($reader)
$comboNewTemplate = $Window.FindName("ComboNewTemplate")
# this works
$comboNewTemplate.Add_SelectionChanged({Write-Host $_.AddedItems[0]})
# this doesn't
$comboNewTemplate.Add_TextBoxBase_TextChanged({Write-Host "text changed"})
# this doesn't, presumably because it hasn't been created yet
$textBox = $comboNewTemplate.Template.FindName("PART_EditableTextBox", $comboNewTemplate)
$textBox.Add_TextChanged({Write-Host "Text changed"})
# this doesn't; not even sure if this makes sense, it's out of my depth
function qwe(){"text changed"}
$func = qwe;
[System.Runtime.InteropServices.Marshal]::StructureToPtr($func, $intptr, $true)
$comboNewTemplate.AddHandler([System.Windows.Controls.Primitives.TextBoxBase]::TextChangedEvent, `
[System.Windows.RoutedEventHandler]::new($o1, $intptr))
$Window.ShowDialog()
You can do it like this:
$comboNewTemplate.AddHandler(
[System.Windows.Controls.Primitives.TextBoxBase]::TextChangedEvent,
[System.Windows.RoutedEventHandler]{ Write-Host "text changed" })
Related
I've ran into an issue while using WPF. When I open the window, I want it to open up on top of all other programs but I don't want it to remain always on top, just the initial opening. I know setting topmost to true will open up on top (which I have in the Xaml), but I can't seem to find a way to change it to false after it has opened.
This is a simple test function with a WPF window.
function foo{
#Load Assembly and Library
Add-Type -AssemblyName PresentationFramework
$inputXaml = #"
<Window x:Class="SharepointCreateOpportunity.completeWindow"
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:SharepointCreateOpportunity"
mc:Ignorable="d"
Title="Window Title" Height="250" MinHeight="250" MaxHeight="250" Width="500" MinWidth="500" MaxWidth="500" Topmost="True" WindowStartupLocation="CenterScreen" Background="Black" >
<Grid>
<Button Name="oKBtn" Content="OK" Margin="0,0,20,20" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="72" Height="23"/>
</Grid>
</Window>
"#
#Gets rid of elements from the Xaml so it can be converted
$inputXamlClean = $inputXaml -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace 'x:Class=".*?"','' -replace 'd:DesignHeight="\d*?"','' -replace 'd:DesignWidth="\d*?"',''
[xml]$xaml = $inputXamlClean
#Creates the Window
$XMLReader = (New-Object System.Xml.XmlNodeReader $xaml)
$Window = [Windows.Markup.XamlReader]::Load($XMLReader)
#Creates variables for all the elements on the window
$xaml.SelectNodes("//*[#Name]") | %{Set-Variable -Name ($_.Name) -Value $Window.FindName($_.Name)}
#OK Button Action
$okBtn.Add_Click({
$Window.Close()
})
#Show window
$Window.ShowDialog()
}
foo
If Topmost is not set in the XAML, the window will appear on top when the script is run (assuming there are no other windows with Topmost set) and will behave like a normal desktop window where focusing on other windows with the mouse or keyboard will cause the window to lose foreground position.
So for the window to be on top for "just the initial opening," getting rid of the Topmost property or setting it to false will work, again assuming there are no other windows with Topmost set. If there are in fact other windows vying for the topmost position, you could use SetForegroundWindow to put it temporarily to the top:
https://stackoverflow.com/a/12802050/4195823
I was following along with the guide located here trying to make a GUI with PowerShell, and it all goes well except I have a DataGrid that needs to be populated in my GUI.
In my XML grid I have:
[xml]$form=#"
<Window
[...]
<Grid>
[...]
<DataGrid Name="CSVGrid" HorizontalAlignment="Left" Height="340" Margin="10,60,0,0" VerticalAlignment="Top" Width="765"/>
[...]
</Grid>
</Window>
"#
Now in the tutorial to create the form it uses the following:
$XMLReader = (New-Object System.Xml.XmlNodeReader $Form)
$XMLForm = [Windows.Markup.XamlReader]::Load($XMLReader)
But to get my DataGrid to work, I believe I need to define my "CSVGrid" DataGrid as "system.Windows.Forms.DataGridView" somewhere, but I'm not sure how to tie that together. Running it without defining this will spit out errors if I try to invoke any DataGrid properties, like setting column amounts or column names.
Any ideas?
The way POSHGUI implements their forms actually works perfectly for my purpose, but I prefer editing the WPF forms in Visual Studio. If need be, I can rebuild the form in POSHGUI but hopefully there's a way to tie this together here so I can continue to use the VS GUI for editing the form's GUI.
Edit: It should be noted there's not just the data grid on the form, in case that wasn't clear.
Edit 2: As an extra bit of info, the way POSHGUI formats the controls is like so:
#the form itself
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '400,400'
$Form.text = "Form"
$Form.TopMost = $false
#a datagrid
$DataGridView1 = New-Object system.Windows.Forms.DataGridView
$DataGridView1.width = 382
$DataGridView1.height = 335
$DataGridView1.location = New-Object System.Drawing.Point(8,55)
#a button
$Button1 = New-Object system.Windows.Forms.Button
$Button1.text = "My button"
$Button1.width = 126
$Button1.height = 30
$Button1.location = New-Object System.Drawing.Point(156,13)
$Button1.Font = 'Microsoft Sans Serif,10'
It then ties them together with:
$Form.controls.AddRange(#($DataGridView1,$Button1))
So that happily defines the DataGrid variable as a "system.Windows.Forms.DataGridView", &c, whereas the method of putting the entire XML into a $variable and passing that into a "System.Xml.XmlNodeReader" doesn't make the distinction I don't believe, which is why I'm unable to call any DataGrid properties.
But again, I'd rather create the GUI in Visual Studio if I can...
Edit 3: If it helps at all, checking the intellisense dropdown, various DataGrid properties are there, but not ColumnCount for example:
So maybe it's working as intended? But at the same time, if my DataGrid variable is defined explicitly as a system.Windows.Forms.DataGridView, like in the POSHGUI example, then setting ColumnCount works flawlessly...
Before we get too far into it, you can't use a DataGridView in WPF (which is what I'll be showing you here). You can, however, use a DataGrid instead which is pretty much the same thing (and wayyyy shorter and easier in PowerShell than Windows Forms, which is what POSHGUI uses (awesome tool though it is).
If you're still interested though, here's a super basic walkthrough of how you could do this. First, to define the XAML
$inputXML = #"
<Window x:Class="WpfApp2.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:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<DataGrid Name="Datagrid" AutoGenerateColumns="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="180" />
<DataGridTextColumn Header="Type" Binding="{Binding Type}" Width="233"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
"#
Note that we are defining which columns from our input object we wanna display. Haven't found a great way to automatically create them yet.
Next, load the form (using the method from my walkthrough on the topic here)
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch [System.Management.Automation.MethodInvocationException] {
Write-Warning "We ran into a problem with the XAML code. Check the syntax for this control..."
write-host $error[0].Exception.Message -ForegroundColor Red
if ($error[0].Exception.Message -like "*button*"){
write-warning "Ensure your <button in the `$inputXML does NOT have a Click=ButtonClick property. PS can't handle this`n`n`n`n"}
}
catch{#if it broke some other way <span class="wp-smiley wp-emoji wp-emoji-bigsmile" title=":D">:D</span>
Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."
}
#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
$xaml.SelectNodes("//*[#Name]") | %{Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name)}
Now, to add some items to this DataGridView. The above code also gives us a variable titled $WPFGridView in our session. We can add child items to our DataGridView by calling the .AddChild() method of that variable and feeding it items that have at least the same properties as we defined in our DataGrid earlier.
$WPFDatagrid.AddChild([pscustomobject]#{Name='Stephen';Type=123})
$WPFDatagrid.AddChild([pscustomobject]#{Name='Geralt';Type=234})
Then, to display our GUI, we call the $Form's ShowDialog() method like so, and then the bottom should greet us.
$Form.ShowDialog()
Full code sample is available here. If you want to learn more about using WPF GUI elements like this, I have a full walkthrough available here.
I modified it a bit:
is a function (allows for multiple windows)
returns an array of the elements
loads the presentation framework (supports x:Bind as Binding)
you can create any WPF form with visual studio and load it (mostly, do not forget any extra classes used to be defined within the XAML and maybe load its type in posh)
A more advanced version: supporting click handler
function LoadXamlForm
{
Param
(
[Parameter(Mandatory=$true)] $xamlFile
)
Add-Type -AssemblyName PresentationFramework
$inputXML = Get-Content -Path $xamlFile
# https://stackoverflow.com/a/52416973/1644202
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window' -replace "x:Bind", "Binding"
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $XAML)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch [System.Management.Automation.MethodInvocationException] {
Write-Warning "We ran into a problem with the XAML code. Check the syntax for this control..."
write-host $error[0].Exception.Message -ForegroundColor Red
if ($error[0].Exception.Message -like "*button*"){
write-warning "Ensure your <button in the `$inputXML does NOT have a Click=ButtonClick property. PS can't handle this`n`n`n`n"}
}
catch{#if it broke some other way <span class="wp-smiley wp-emoji wp-emoji-bigsmile" title=":D">:D</span>
Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."
}
#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
$Elements = #{}
$xaml.SelectNodes("//*[#Name]") | %{ $Elements[$_.Name] = $Form.FindName($_.Name) }
return $Form, $Elements
}
$Form,$Elements = LoadXamlForm .\gui.xaml
$Elements.lvApps.AddChild([pscustomobject]#{Name='Ben';Description="sdsd 343"})
$Form.ShowDialog() | out-null
just any xaml - i know this is no datagrid - but gives you a use case nonetheless
<Window x:Class="WpfApp.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:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListView SelectionMode="Multiple" x:Name="lvApps" Height="371" VerticalAlignment="Top">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="64" AutomationProperties.Name="{Binding Name}">
<Ellipse Height="48" Width="48" VerticalAlignment="Center">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding ButtonImage}"/>
</Ellipse.Fill>
</Ellipse>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" Margin="12,0,0,0">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
I have a textbox that has an image linked as it's background.
I'd like to use the base64 version of this image.
I used a very simple windows -form- to ensure the code for enacting the base64 is working correctly, it did.
The part I'm having issue with is linking it in xaml in a wpf style gui.
<TextBox Name="OutTBox" Grid.Column="0" Grid.ColumnSpan="7" Grid.Row="4" Grid.RowSpan="6" Margin="20,5,20,20" Foreground="#FF8CFF8C" IsReadOnly="True" >
<TextBox.Background>
<ImageBrush ImageSource="C:\background.jpg" Stretch="UniformToFill"/>
</TextBox.Background>
</TextBox>
So here is the base64 language I used for the windows form:
Add-Type -AssemblyName PresentationFramework
# Setup the XAML
[xml]$script:xaml = '<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="base64 image demo" Height="350" Width="650" Background="Black">
<Grid>
<Image Name="thisistheimage" Stretch="UniformToFill" />
</Grid>
</Window>'
# Create the form and set variables
$script:form = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml))
$xaml.SelectNodes("//*[#Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $form.FindName($_.Name) -Scope Script }
# here's the base64 string
$base64 = "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"
# Create a streaming image by streaming the base64 string to a bitmap streamsource
$bitmap = New-Object System.Windows.Media.Imaging.BitmapImage
$bitmap.BeginInit()
$bitmap.StreamSource = [System.IO.MemoryStream][System.Convert]::FromBase64String($base64)
$bitmap.EndInit()
# Freeze() prevents memory leaks.
$bitmap.Freeze()
# Set source here. Take note in the XAML as to where the variable name was taken.
$thisistheimage.source = $bitmap
# Show form
$null = $form.ShowDialog()
I'd give you my actual image but it's over 5k lines long. It only takes a fraction of a second to load.
To be clear the base64 will load in the Xaml. I removed the textbox from those grid coords and replaced it with the base64 and it loads fine. just can't seem to work the two together.
Thanks!
I've never used powershell, but it should be as simple as this:
$brush = New-Object System.Windows.Media.ImageBrush
$brush.ImageSource = $bitmap
$thetextbox.Background = $brush
I have a combo box on a Windows form created using XAML. I need to pass a selected combo box value to a parameter in my script. I want the code to only run when I make the selection (e.g. like a button click event, if this is possible).
I have tried using different method types after $cboUseCase. at the start of the code. Right now this code is trying to run when the Window is loading, I need it to run only when a selection is made. Thank you for your help.
$cboUseCase.({$configSelect = ($cboUseCase.SelectedItem.toString())
&$global:UCM.setConfigSelection -selection $configSelect})
Not sure I really understand your question. Here is a runnable example showing how to "trap" a selection change in a combo box.
Maybe it can give you a track to follow:
[System.Reflection.Assembly]::LoadWithPartialName('PresentationFramework') | Out-Null
[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"
SizeToContent = "WidthAndHeight" ShowInTaskbar = "True" Background = "lightgray">
<StackPanel>
<ComboBox x:Name="ComboBox1">
<ComboBoxItem>Item 1</ComboBoxItem>
<ComboBoxItem>Item 2</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$Window = [Windows.Markup.XamlReader]::Load($reader)
$ComboBox1 = $Window.FindName("ComboBox1")
$ComboBox1.add_SelectionChanged( {
param($sender, $args)
$selected = $sender.SelectedItem.Content
Write-Host "Selected: $selected"
} )
$Window.Showdialog() | Out-Null
I have some XAML I'm importing into a PowerShell script. It contains a DataGrid which displays the result of a PowerShell cmdlet. I've added an 'Edit' button to each row using a DataGridTemplateColumn. Now, I'd like to add an event handler to each button. I can do it in code:
$adUsersList_Results = $activeDirectory_Users_ListControl.FindName('ResultsDataGrid')
$dataTemplate = New-Object 'Windows.DataTemplate'
$buttonElement = New-Object 'Windows.FrameworkElementFactory' ([Windows.Controls.Button])
$buttonElement.SetValue([Windows.Controls.Button]::ContentProperty, "Edit")
$buttonElement.AddHandler([Windows.Controls.Button]::ClickEvent, [Windows.RoutedEventHandler]{
PARAM (
[Object]$sender,
[Windows.RoutedEventArgs]$e
)
Write-Host "Clickety-click!"
Write-Host $sender.DataContext
})
$dataTemplate.VisualTree = $buttonElement
$dataGridTemplateColumn = New-Object 'Windows.Controls.DataGridTemplateColumn'
$dataGridTemplateColumn.Header = 'Poo'
$dataGridTemplateColumn.CellTemplate = $dataTemplate
$adUsersList_Results.Columns.Add($dataGridTemplateColumn)
but it's a bit unwieldy. The XAML looks like this:
<DataGrid Grid.Row="1"
x:Name="ResultsDataGrid"
IsReadOnly="True"
HorizontalAlignment="Stretch"
Margin="3"
VerticalAlignment="Stretch">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Edit" Width="60" x:Name="ADUserListButton"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I've tried using FindName('ADUserListButton') but it doesn't work. Is there a way to keep all of the visual stuff in XAML and just do the event handler in the PowerShell?
Aside: I'm aware of Show-UI. I'm actually doing the same thing in Show-UI and in PowerShell & XAML before deciding which is the best fit for us.
I'm also aware that you can do editing in-grid but I don't think it's a great user-experience for this type of data.
I'm not exactly sure but could it be because the XAML button you list doesn't have the handler connection to it? i.e.
<Button Content="Edit" Width="60" x:Name="ADUserListButton" Click="ADUserListButton_Click"/>
I have not done that with powershell but if it was in the .cs code-behind file of a usercontrol for instance you could try GetTemplateChild("your control name").
Below is an example of calling button inside data-grid using Powershell, hope this helps.
Add-Type -AssemblyName PresentationFramework
Function Check-Event($ev,$co,$da){
$comp=$co.trim()
$re = Get-EventLog Application -ComputerName "$comp" -InstanceId $ev -After $da
$res.Text += "There are "+$re.count+" events pf EventID $ev on Computer $Comp after the time $da ch"
}
[Xml]$Form = #"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid HorizontalAlignment="Left" Height="151" Margin="112,35,0,0" VerticalAlignment="Top" Width="279"/>
<Button Name="ADUserListButton" Content="Edit" HorizontalAlignment="Left" Margin="140,85,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox Name="Result" HorizontalAlignment="Left" Height="23" Margin="140,124,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="Hello World"/>
</Grid>
</Window>
"#
$NR=(New-Object System.Xml.XmlNodeReader $Form)
$Win=[Windows.Markup.XamlReader]::Load( $NR )
$Start = $Win.FindName("ADUserListButton")
$res = $Win.FindName("Result")
$Start.Add_Click({
$event=$res.text
If($event -eq "") {
[System.Windows.MessageBox]::Show("Please make sure all values are entered", "Missing Values")}
Else{Get-WMIObject -class Win32_ComputerSystem | select username -OutVariable a
$name=$a.username
[System.Windows.MessageBox]::Show("User name is $name", "Hello")
}
})
What I have done with my grid clicks where lots of data is listed, rather than creating code for each cell, you can create a click handler on the datagrid that gets the selected row or cell and does something with it.
$adUsersList_Results = $activeDirectory_Users_ListControl.FindName('ResultsDataGrid')
$adUsersList.Add_Click({
$sender = $args[0]
$e = $args[1]
$prop = $sender.SelectedItem.<#[Some property of the row]#>
#do something with $prop....
})
Don't know if this is what you are looking for, and I know it is a little bit late, but it might help someone else out there...