I have two text boxes. I would like to mirror the first text box to the second text box, but if you manually update the second box after the text has been mirrored, it should stay as that regardless of if you update the first text box again.
<TextBox x:Name="TextBoxUserLogonNameUPN" HorizontalAlignment="Left" Height="23" Margin="10,41,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="300"/>
<TextBox x:Name="TextBoxUserLogonNameSamAccountName" HorizontalAlignment="Left" Height="23" Margin="326,100,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="310" Text="{Binding Path=Text, ElementName=TextBoxUserLogonNameUPN, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
I have tried the above but with Mode=OneWay in the Binding. If I update the first text box a second time, after manually updating the second, it wipes what was in the second and mirrors again.
I am using WPF with PowerShell. I am happy to manage this by the Powershell if it can't be done in Xaml.
Assuming that textbox1 losing focus is the event that should copy textbox1 text to textbox2, this code should work for you. All the action is in the function textBox1_LostFocus. The first time through, simply set the textbox2Tagproperty to a value that you test for second and subsequent times through
Note: The form has two labels and two text boxes
WpfWindow1.xaml.ps1 is the entry point for this program
WpfWindow1.xaml.ps1
function Add-ControlVariables {
New-Variable -Name 'textBox1' -Value $window.FindName('textBox1') -Scope 1 -Force
New-Variable -Name 'textBox2' -Value $window.FindName('textBox2') -Scope 1 -Force
}
function Load-Xaml {
[xml]$xaml = Get-Content -Path $PSScriptRoot\WpfWindow1.xaml
$manager = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xaml.NameTable
$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
$xaml.SelectNodes("//*[#x:Name='textBox1']", $manager)[0].RemoveAttribute('TextChanged')
$xaml.SelectNodes("//*[#x:Name='textBox2']", $manager)[0].RemoveAttribute('TextChanged')
$xaml.SelectNodes("//*[#x:Name='textBox1']", $manager)[0].RemoveAttribute('LostFocus')
$xamlReader = New-Object System.Xml.XmlNodeReader $xaml
[Windows.Markup.XamlReader]::Load($xamlReader)
}
function Set-EventHandlers {
$textBox1.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox1_TextChanged($sender,$e)
})
$textBox2.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
$textBox1.add_LostFocus({
param([System.Object]$sender,[System.Windows.RoutedEventArgs]$e)
textBox1_LostFocus($sender,$e)
})
}
$window = Load-Xaml
Add-ControlVariables
Set-EventHandlers
function textBox1_TextChanged
{
param($sender, $e)
#do stuff you want to do when textBox1.Text changes
}
function textBox2_TextChanged
{
param($sender, $e)
#do stuff you want to do when textBox2.Text changes
}
function textBox1_LostFocus
{
param($sender, $e)
if ($textBox2.Tag -ne "mirrored")
{
#turn off textBox2 TextChanged event so that code in textBox2_TextChanged is not executed
$textBox2.remove_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
$textBox2.Text = $sender.Text
$textBox2.Tag = "mirrored"
#turn textBox2 TextChanged event back on
$textBox2.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
}
}
$window.ShowDialog()
WpfWindow1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="29" Margin="79,45,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="132" TextChanged="textBox1_TextChanged" LostFocus="textBox1_LostFocus"/>
<TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="29" Margin="298,45,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="105" TextChanged="textBox2_TextChanged"/>
<Label Content="Text1:" HorizontalAlignment="Left" Height="25" Margin="32,45,0,0" VerticalAlignment="Top" Width="63"/>
<Label Content="Text2:" HorizontalAlignment="Left" Height="25" Margin="242,45,0,0" VerticalAlignment="Top" Width="56"/>
</Grid>
</Window>
Related
I'm trying to get a list of users searching by a surname property and list them in the ListView.
Here's XAML code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="Find users with SamAccountName"
Width="525"
Background="#FF262626"
ResizeMode="NoResize"
SizeToContent="Height">
<StackPanel Margin="5,5,5,5" Orientation="Vertical">
<Grid
Name="Grid"
Width="400"
Height="200"
Background="#313130">
<Label
Name="Label"
Content="Select employee"
FontSize="12"
Foreground="White" />
<ListView
Name="ListView"
Margin="0,25,0,0"
Background="Transparent"
BorderBrush="Transparent"
Foreground="White"
IsHitTestVisible="False"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn
Width="100"
DisplayMemberBinding="{Binding Path=Logon}"
Header="Logon" />
<GridViewColumn
Width="150"
DisplayMemberBinding="{Binding Path=FirstName}"
Header="First name" />
<GridViewColumn
Width="150"
DisplayMemberBinding="{Binding Path=LastName}"
Header="Last name" />
</GridView>
</ListView.View>
</ListView>
</Grid>
<StackPanel HorizontalAlignment="Right">
<Button Width="50" Content="SAVE" />
</StackPanel>
</StackPanel>
And it looks like this:
XAML look
I believe I cannot do it without data-binding and I saw a lot of posts about them but I couldn't understand it completely.
For now in powershell I have:
Add-Type -AssemblyName PresentationFramework
$employees = Get-ADUser -Filter {Surname -like "surname"}
$itemSource = #()
ForEach ($employee in ($employees | Sort-Object SamAccountName)) {
$itemSource += [PSCustomObject]# {
Logon = $employee.Name
FirstName = $employee.GivenName
LastName = $employee.Surname
}
$columnOrder = 'Logon', 'FirstName', 'LastName'
[XML]$Form = Get-Content "xmlPath"
$NR = (New-Object System.Xml.XmlNodeReader $Form)
$Win = [Windows.Markup.XamlReader]::Load($NR)
$Win.ShowDialog()
Now, the ForEach is working perfectly fine and returning exactly what I need but cannot find any way to put it into ViewList.
Then I'll need to save the selected user into a variable that I'll display later in the textbox.
Sorry if it's a stupid/easy question but I just started learning PowerShell to help me automate my work.
In the loaded form, you have to specify the ListView's ItemsSource
in PowerShell, you can do it like this
Add-Type -AssemblyName PresentationFramework
$employees = Get-ADUser -Filter {Surname -like "surname"}
$itemSource = #()
ForEach ($employee in $($employees | Sort-Object SamAccountName)) {
$itemSource += [PSCustomObject]#{
Logon = $employee.Name
FirstName = $employee.GivenName
LastName = $employee.Surname
}
}
[XML]$Form = (Get-Content "C:\temp\test.xaml")
$NR = (New-Object System.Xml.XmlNodeReader $Form)
$Win = [Windows.Markup.XamlReader]::Load($NR)
# this part
($win.FindName("ListView")).ItemsSource = $itemSource
$Win.ShowDialog()
I'm having trouble updating my WPF-Window-Forms.
Basically, I want to trigger different content in my "Console-TextBox" depending on the current connected Network-SSID.
[xml]$xaml = Get-Content -Path $PSScriptRoot\Pattern.xaml
$manager = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xaml.NameTable
$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
$xamlReader = New-Object System.Xml.XmlNodeReader $xaml
[Windows.Markup.XamlReader]::Load($xamlReader)
}
$window = Load-Xaml
$textbox = $window.FindName("textbox")
$textbox_console = $window.FindName("textbox_console")
Get-EventSubscriber | Unregister-Event
Register-EngineEvent -SourceIdentifier 'MyEvent' -Action {$textbox_console.Text += "ManualInput"}
$networkChange = [System.Net.NetworkInformation.NetworkChange];
Register-ObjectEvent -InputObject $networkChange -EventName NetworkAddressChanged -SourceIdentifier NetworkChanged -Action {
$textbox_console.Text += "`nNetworkChanged"
}
$textbox.Add_TextChanged({
New-Event -SourceIdentifier 'MyEvent'
})
$window.ShowDialog() | Out-Null
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Pattern" Width="600" Height="400" WindowStyle="None" ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<StackPanel>
<TextBox x:Name="textbox" HorizontalAlignment="Left" Height="70" Margin="124,104,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="262"/>
<TextBox x:Name="textbox_console" HorizontalAlignment="Left" Height="70" Margin="124,104,0,0" TextWrapping="Wrap" Text="console" VerticalAlignment="Top" Width="262"/>
</StackPanel>
</Window>
I'm new to Event Handling and not sure whether this issue is caused by Thread/Process-handling or wrong EventHandling...
Maybe somebody could point out some hint and tell me, how to use the NetworkChange-Event to update the text of the textbox?
I am doing a GUI in Visual Studuio for a script I made for Powershell and I need to use radio buttons to add variables to make this script works, like for example, the script works with 5 printer brands, so the user needs to select one of this to progress. Then, for each brand you have inside the models. At the end, will execute the code to create a print queue on a selected server, which includes the variables held on the radio buttons below:
$maker - brand of the device.
$model - model of the device.
$modelfull - full model name for comment purposes.
$driver - print driver to assign to the print queue.
How can I add those variables to each radio button? I.e. I have two models, Deskjet 3050 and Deskjet 3045, how can I convert those models into a variable once user select the radio button and press Next on the window?
Below you can see example of the code from Visual Studio where is the frame with the radio buttons:
<Page x:Class="Print_Queue_Configuration_Tool.Maker_2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Print_Queue_Configuration_Tool"
mc:Ignorable="d"
d:DesignHeight="570" d:DesignWidth="754"
Title="Maker_2">
<Grid x:Name="Maker_2_Grid">
<Button x:Name="Maker_2_ButtonBack" Content="Back" HorizontalAlignment="Left" Margin="360,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonNext" Content="Next" HorizontalAlignment="Left" Margin="485,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonCancel" Content="Cancel" HorizontalAlignment="Left" Margin="610,525,0,0" VerticalAlignment="Top" Width="120" Height="35" IsCancel="True"/>
<Image x:Name="Maker_2_ImageLogo" HorizontalAlignment="Left" Height="44.264" Margin="480.157,30.312,0,0" VerticalAlignment="Top" Width="273.843" Source="logo.png" RenderTransformOrigin="0.5,0.5"/>
<TextBlock x:Name="Maker_2_TextMaker_2" HorizontalAlignment="Left" Margin="70,140,0,0" TextWrapping="Wrap" Text="Please select the maker of the device:" VerticalAlignment="Top"/>
<RadioButton x:Name="Maker_2_RadioMaker1" Content="Canon" VerticalAlignment="Center" Margin="272.25,220.25,351.75,333.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
<RadioButton x:Name="Maker_2_RadioMaker2" Content="Epson" VerticalAlignment="Center" Margin="272.25,260.25,351.75,293.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
</Grid>
</Page>
Here you can see how I have assigned the variables to each button, but of course it's not working:
$wpf.Maker_2_RadioMaker1.add_Checked({
$maker = 'Canon'
})
$wpf.Maker_2_RadioMaker2.add_Checked({
$maker = 'Epson'
})
Thank you!!
PS: I am new in this so I am still learning. Please be polite, remember that you were in my position once :)
Here your Page is working... I had to adapt the xml a bit.
Note the FindName to Address the Radiobuttons
[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="Maker_2" Height="770" Width="800">
<Grid x:Name="Maker_2_Grid">
<Button x:Name="Maker_2_ButtonBack" Content="Back" HorizontalAlignment="Left" Margin="360,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonNext" Content="Next" HorizontalAlignment="Left" Margin="485,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonCancel" Content="Cancel" HorizontalAlignment="Left" Margin="610,525,0,0" VerticalAlignment="Top" Width="120" Height="35" IsCancel="True"/>
<Image x:Name="Maker_2_ImageLogo" HorizontalAlignment="Left" Height="44.264" Margin="480.157,30.312,0,0" VerticalAlignment="Top" Width="273.843" Source="logo.png" RenderTransformOrigin="0.5,0.5"/>
<TextBlock x:Name="Maker_2_TextMaker_2" HorizontalAlignment="Left" Margin="70,140,0,0" TextWrapping="Wrap" Text="Please select the maker of the device:" VerticalAlignment="Top"/>
<RadioButton x:Name="Maker_2_RadioMaker1" Content="Canon" VerticalAlignment="Center" Margin="272.25,220.25,351.75,333.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
<RadioButton x:Name="Maker_2_RadioMaker2" Content="Epson" VerticalAlignment="Center" Margin="272.25,260.25,351.75,293.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
</Grid>
</Window>
"#
function Check-Radios
{
if($this.Name -eq "Maker_2_RadioMaker1") {Write-Host "Canon"}
if($this.Name -eq "Maker_2_RadioMaker2") {Write-Host "Epson"}
}
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$window.FindName("Maker_2_RadioMaker1").add_Checked({Check-Radios})
$window.FindName("Maker_2_RadioMaker2").add_Checked({Check-Radios})
$window.ShowDialog()
Now it's working as requested. In Function Check-Radios you can set your variables depending on choosen Radiobutton
This example meets your requirements that when you press "Next" the correct selection of the radio button is displayed. This should take you further.
[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="Maker_2" Height="770" Width="800">
<Grid x:Name="Maker_2_Grid">
<Button x:Name="Maker_2_ButtonBack" Content="Back" HorizontalAlignment="Left" Margin="360,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonNext" Content="Next" HorizontalAlignment="Left" Margin="485,525,0,0" VerticalAlignment="Top" Width="120" Height="35"/>
<Button x:Name="Maker_2_ButtonCancel" Content="Cancel" HorizontalAlignment="Left" Margin="610,525,0,0" VerticalAlignment="Top" Width="120" Height="35" IsCancel="True"/>
<Image x:Name="Maker_2_ImageLogo" HorizontalAlignment="Left" Height="44.264" Margin="480.157,30.312,0,0" VerticalAlignment="Top" Width="273.843" Source="logo.png" RenderTransformOrigin="0.5,0.5"/>
<TextBlock x:Name="Maker_2_TextMaker_2" HorizontalAlignment="Left" Margin="70,140,0,0" TextWrapping="Wrap" Text="Please select the maker of the device:" VerticalAlignment="Top"/>
<RadioButton x:Name="Maker_2_RadioMaker1" Content="Canon" VerticalAlignment="Center" Margin="272.25,220.25,351.75,333.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
<RadioButton x:Name="Maker_2_RadioMaker2" Content="Epson" VerticalAlignment="Center" Margin="272.25,260.25,351.75,293.75" Height="16" Width="130" GroupName="Makers_2" FontWeight="Bold"/>
</Grid>
</Window>
"#
function Check-Radios
{
$Global:radioSelected = $this;
}
$radioSelected = $null
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$window.FindName("Maker_2_RadioMaker1").add_Checked({Check-Radios})
$window.FindName("Maker_2_RadioMaker2").add_Checked({Check-Radios})
$window.FindName("Maker_2_ButtonNext").add_Click({Write-Host "You have selected: $($radioSelected.Content)"});
$window.ShowDialog()
EDIT:
here an example for an object that holds your printerdata
$printerList = [System.Collections.ArrayList]::new()
$printerList.Add([pscustomobject]#{Maker = "Canon";Model = "Pixma";ModelFull="Pixma0815";driver = "driverxyz1"})
$printerList.Add([pscustomobject]#{Maker = "Epson";Model = "Workforce";ModelFull="Workforce2020";driver = "driverxyz2"})
You can simply rewrite your "next button ClickMethod" like this...
$window.FindName("Maker_2_ButtonNext").add_Click({ Write-Host $($printerList | where Maker -eq $($radioSelected.Content)) });
it will give you the printers with selected maker
With Navigationwindow and pages you can now go to the page depending in selected printer.
Best Regards
Unfortunately, importing wpf as xaml for powershell is for me not entirely functional
I designed an example for you in which all elements were created in the code and also realized that you first select the manufacturer (radio buttons) and on the next page the model or full model, both are listed as an example. But you actually only need the combo with the full model.
here it is with Powershell
using namespace System.Windows
using namespace System.Windows.Controls
using namespace System.Windows.Navigation
[System.Reflection.Assembly]::LoadWithPartialName("PresentationFramework")
[System.Reflection.Assembly]::LoadWithPartialName("PresentationCore")
[System.Reflection.Assembly]::LoadWithPartialName("WindowsBase")
function Check-Radios
{
$Global:selectedMaker = $this.Content
}
$printerList = [System.Collections.ArrayList]::new()
$printerList.Add([pscustomobject]#{Maker = "Canon";Model = "Pixma";ModelFull="Pixma0815";driver = "driverxyz1"})
$printerList.Add([pscustomobject]#{Maker = "Canon";Model = "Pixma";ModelFull="Pixma1615";driver = "driverxyz1"})
$printerList.Add([pscustomobject]#{Maker = "Epson";Model = "Workforce";ModelFull="Workforce2020";driver = "driverxyz2"})
$selectedMaker = "Canon";
$navigationWindow = [NavigationWindow]::new()
$navigationPage1 = [Page]::new()
$navigationPage2 = [Page]::new()
#Page with printers
$printerLabel = [Label]::new()
$printerLabel.Content = ($printerList | where Maker -eq $selectedMaker | Select -First 1).Maker
$printerModelCombo = [ComboBox]::new()
$printerModelFullCombo = [ComboBox]::new()
$printerStackPanel = [StackPanel]::new()
$printerStackPanel.AddChild($printerLabel)
$printerStackPanel.AddChild($printerModelCombo)
$printerStackPanel.AddChild($printerModelFullCombo)
$navigationPage2.Content = $printerStackPanel
#Page with radiobuttons
$radioButton1 = [RadioButton]::new()
$radioButton1.Content ="Canon"
$radioButton1.Name = "RadioCanon"
$radioButton2 = [RadioButton]::new()
$radioButton2.Content ="Epson"
$radioButton2.Name = "RadioEpson"
$radioButton1.add_Checked({Check-Radios})
$radioButton2.add_Checked({Check-Radios})
$button1 = [Button]::new()
$button1.Content = "Next"
$button1.add_Click(
{
foreach($entry in ($printerList | where Maker -eq $selectedMaker))
{
# Model
if($printerModelCombo.Items.IsEmpty -or !$printerModelCombo.Items.Content.Contains($entry.Model))
{
$printerModelComboItem = [ComboBoxItem]::new()
$printerModelComboItem.Content = $entry.Model
$printerModelCombo.AddChild($printerModelComboItem)
}
# Model Full
$printerModelFullComboItem = [ComboBoxItem]::new()
$printerModelFullComboItem.Content = $entry.ModelFull
$printerModelFullCombo.AddChild($printerModelFullComboItem)
}
$printerModelCombo.SelectedIndex = 0
$printerModelFullCombo.SelectedIndex = 0
$navigationWindow.NavigationService.Content = $navigationPage2
})
$grid = [Grid]::new()
$gridRowDef1 = [RowDefinition]::new()
$gridRowDef2 = [RowDefinition]::new()
$gridRowDef1.Height ="4*"
$gridRowDef2.Height ="1*"
$grid.RowDefinitions.Add($gridRowDef1)
$grid.RowDefinitions.Add($gridRowDef2)
$stackPanel = [StackPanel]::new()
$stackPanel.AddChild($radioButton1)
$stackPanel.AddChild($radioButton2)
$grid.AddChild($stackPanel)
$grid.AddChild($button1)
[Grid]::SetRow($stackPanel,0)
[Grid]::SetRow($button1,1)
$navigationPage1.Content = $grid;
$navigationWindow.Title = "Navigation"
$navigationWindow.Width = 960
$navigationWindow.Height = 600
$navigationWindow.NavigationService.Content = $navigationPage1
$navigationWindow.ShowsNavigationUI = $false
$navigationWindow.ShowDialog()
In a WPF DataGrid via PowerShell, I would like the user to be able to copy the cells as follows: 1) if multiple cells and rows are selected selected then copy it with header. 2) If only a single cell is selected copy the cell content without the header. In the sample shown below, I've set ClipboardCopyMode="IncludeHeader" which enables to copy the selected cells/rows with header which satisfies first requirement indicated above. However, I'm looking for some ideas or quick samples for the second requirement shown above, that is to copy the content without header if only single cell is selected (from context menu or shortcut). I had tried mouse events but couldn't get it to work. Thanks in advance.
[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:Test"
Title="MainWindow" Height="425" Width="550">
<Grid>
<TextBox x:Name="tb_Search" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="149"/>
<Button x:Name="bt_Search" Content="Search" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" IsDefault="True" Height="22" Margin="165,10,0,0" />
<DataGrid x:Name="dg" Margin="10,45,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="100" Height="Auto" Width="Auto" ColumnWidth="Auto" AlternationCount="1" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell" Background="White" ClipboardCopyMode="IncludeHeader">
<DataGrid.ContextMenu>
<ContextMenu >
<MenuItem Command="{x:Static ApplicationCommands.Copy}" Header="Copy With Header"/>
<MenuItem Command="{x:Static ApplicationCommands.Save}" Header="Save"/>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($reader)
#Turn XAML into PowerShell objects
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'x:Name')]]") | ForEach-Object{
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("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")
$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")
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
#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
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
for ($i = 0; $i -lt $dg.Items.Count; $i++)
{
if ($dg.Items[$i].Row[$dg.Columns.DisplayIndex] -eq "$SearchValue")
{
[System.Windows.Forms.MessageBox]::Show("Keyword Found")
$dg.ScrollIntoView($dg.Items[$i]) #scroll to the row that contains the keyword searched
}
}
})
#Display Form
$Window.ShowDialog() | Out-Null
You could dynamically set the ClipboardCopyMode in the CanExcecute method of the ApplicationCommands.Copy command. This is how you would do this in C#:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
DataGrid dataGrid = (DataGrid)sender;
dataGrid.ClipboardCopyMode = dataGrid.SelectedCells.Count == 1 ?
DataGridClipboardCopyMode.ExcludeHeader : DataGridClipboardCopyMode.IncludeHeader;
}
XAML:
<DataGrid ... SelectionMode="Extended" SelectionUnit="Cell" ClipboardCopyMode="IncludeHeader">
<DataGrid.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.Copy}" CanExecute="CommandBinding_CanExecute"/>
</DataGrid.CommandBindings>
</DataGrid>
I have a configuration script in powershell that I am trying to marry with a WFP GUI. After a few failed forays with code and gui in the same thread I have been reading a number of pages about running the GUI in its own runspace. Below is the code that I have pieced together.
The form runs but I get this error related to the button click I am trying to use to hide/unhide grids.
You cannot call a method on a null-valued expression.
At C:\Projects\AVPC Setup\Working Files\MT Trial 3.ps1:218 char:18
+ $syncHash.fullConfig.Add_Click({
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
With the form running these variables are visible in the syncHash so I am not sure what I am missing.
$Global:syncHash = [hashtable]::Synchronized(#{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.Name = "Config GUI"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$psCmd = [PowerShell]::Create().AddScript({
[xml]$xaml = #"
<Window x:Class="psguiconfig.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:psguiconfig"
mc:Ignorable="d"
Title="Config" Height="175" Width="500">
<Grid x:Name="mainGrid" HorizontalAlignment="Left" Height="144" Margin="0,1,0,0" VerticalAlignment="Top" Width="490">
<Grid x:Name="choiceGrid" HorizontalAlignment="Left" Height="144" Margin="0,1,0,0" VerticalAlignment="Top" Width="490" Visibility="Visible">
<Label Content="Choose Config Type" HorizontalAlignment="Center" Height="26" Margin="0,0,0,60" VerticalAlignment="Center" FontWeight="SemiBold"/>
<Button x:Name="fullConfig" Content="Full" HorizontalAlignment="Center" Margin="0,45,250,0" VerticalAlignment="Center" Width="75"/>
<Button x:Name="stepConfig" Content="Step By Step" HorizontalAlignment="Center" Margin="0,45,0,0" VerticalAlignment="Center" Width="75"/>
<Button x:Name="upgradeConfig" Content="Upgrade" HorizontalAlignment="Center" Margin="250,45,0,0" VerticalAlignment="Center" Width="75" IsEnabled="False"/>
</Grid>
<Grid x:Name="fullGrid" HorizontalAlignment="Left" Height="144" Margin="0,1,0,0" VerticalAlignment="Top" Width="490" Visibility="Hidden">
<Label x:Name="fullLabel" Content="Full Config" HorizontalAlignment="Center" Height="26" Margin="0,0,0,60" VerticalAlignment="Center" FontWeight="SemiBold"/>
<ProgressBar x:Name="fullProgress" HorizontalAlignment="Center" Height="20" Margin="0,40,0,0" VerticalAlignment="Center" Width="400"/>
<Label x:Name="fullProgressLabel" Content="Tasking Stuffs" Foreground="#FFFFFF" HorizontalAlignment="Center" Height="20" Margin="45,82,245,42" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="7" Width="200"/>
<Label x:Name="fullProgressPercentageLabel" Content="0%" Foreground="#FFFFFF" HorizontalContentAlignment="Right" Height="20" Margin="419,82,45,42" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="7" Width="26"/>
</Grid>
</Grid>
</Window>
"#
$AttributesToRemove = #(
'x:Class',
'mc:Ignorable'
)
foreach ($Attrib in $AttributesToRemove) {
if ( $xaml.Window.GetAttribute($Attrib) ) {
$xaml.Window.RemoveAttribute($Attrib)
}
}
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
[xml]$XAML = $xaml
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'Name')]]") | %{
#Find all of the form types and add them as members to the synchash
$syncHash.Add($_.Name,$syncHash.Window.FindName($_.Name) )
}
$syncHash.Window.ShowDialog() | Out-Null
$syncHash.Error = $Error
})
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()
Function Update-Window {
Param (
$Control,
$Property,
$Value,
[switch]$AppendContent
)
If ($Property -eq "Close") {
$syncHash.Window.Dispatcher.invoke([action]{$syncHash.Window.Close()},"Normal")
Return
}
$syncHash.$Control.Dispatcher.Invoke([action]{
If ($PSBoundParameters['AppendContent']) { $syncHash.$Control.AppendText($Value) } Else { $syncHash.$Control.$Property = $Value }
}, "Normal")
}
$syncHash.fullConfig.Add_Click({
Update-Window -Control choiceGrid -Property Visibility -Value Hidden
Update-Window -Control fullGrid -Property Visibility -Value Visible
})