Feed XML into XAML/PowerShell WPF Form - wpf

I had a question along a similar topic last week which ultimatly is the same issue but in that scenario I managed to get round this with a PowerShell array on static data thanks to someone on the forum suggesting.
This time round I cant use static so I am somewhat back to my root problem.
I have created a WPF XAML form in Visual Studio and am taking this back to Powershell as my remit with the customer is 'low-code'. The item in question is loading an xml file into the form to populate a list box. Reason for a list box is cleanliness of changing the colour of the background.
Now in VS this works find with a Data Provider but for reasons I cannot find an answer to, this just simply will not work when taken back to PowerShell so I have looked for alternate way.
So I have a simple XML as below:
<?xml version="1.0"?>
<Configuration>
<AllowedAutoStart>Application 1</AllowedAutoStart>
<DenyRemoveAutoStart>Application 2</DenyRemoveAutoStart>
</Configuration>
I want to feed this into my PowerShell/XAML Hybrid Script and simply bind the contents to the appropriate list box (below code is just starting with allowed apps)
I have tried a few different ideas from across the forum before posting but none quite get there. Below is the code I have at present, it doesnt work but doesnt produce any errors either :-)
Appreciate any guidance.
# Load Assembly
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName WindowsBase
#Declare XAML Code
[xml]$AppGeneratorWindow = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="App Config Generator" Height="350" Width="600" WindowStartupLocation="CenterScreen" Top="5" ResizeMode="NoResize">
<Window.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FFAA3D3D" Offset="1"/>
</LinearGradientBrush>
</Window.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="115*"/>
<ColumnDefinition Width="132*"/>
<ColumnDefinition Width="543*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="381*"/>
<RowDefinition Height="241*"/>
</Grid.RowDefinitions>
<Label Name="AllProgramsLabel" Content="All Programs" HorizontalAlignment="Left" Margin="28.333,20,0,0" VerticalAlignment="Top" Foreground="#FFFEFBFB" FontSize="14" FontWeight="Bold" RenderTransformOrigin="2.696,-3.142" Grid.Column="1" Grid.ColumnSpan="2"/>
<Button Name="AddButton" Content="Add >>" HorizontalAlignment="Left" Margin="34,83,0,0" VerticalAlignment="Top" Width="166" FontWeight="Bold" FontSize="14" Height="28" BorderBrush="#FF070606" Background="#FF933838" Foreground="#FFFCFAFA" Grid.Column="3" RenderTransformOrigin="0.416,-0.906"/>
<Label Name="WindowsStartupLabel" Content="Windows Startup" HorizontalAlignment="Left" Margin="236,20,0,0" VerticalAlignment="Top" Foreground="#FFFEFBFB" FontSize="14" FontWeight="Bold" RenderTransformOrigin="2.696,-3.142" Grid.Column="3"/>
<Button Name="RemoveButton" Content="<< Remove" HorizontalAlignment="Left" Margin="34,169,0,0" VerticalAlignment="Top" Width="166" FontWeight="Bold" FontSize="14" Height="28" BorderBrush="#FF070606" Background="#FF933838" Foreground="#FFFCFAFA" Grid.Column="3" Grid.RowSpan="2" RenderTransformOrigin="0.51,-0.503"/>
<ListBox Name="AllProgramsListBox" Grid.ColumnSpan="2" Grid.Column="1" HorizontalAlignment="Left" Height="132" Margin="28,65,0,0" Background="#FFAA3D3D" VerticalAlignment="Top" Width="123" Grid.RowSpan="2"/>
<ListBox Name="StartupListBox" Grid.Column="3" HorizontalAlignment="Left" Height="132" Margin="237,65,0,0" Background="#FFAA3D3D" VerticalAlignment="Top" Width="123" Grid.RowSpan="2"/>
</Grid>
</Window>
"#
#List Boxes
$AllProgramsListBox = $window.FindName("AllProgramsListBox")
$ConfigurationFile = "$env:ProgramData\WindowsStartupTool\AutoStartConfig.XML"
[xml]$ConfigFile = Get-Content $ConfigurationFile
foreach ($entry in $ConfigFile.Configuration.AllowedAutoStart.add)
{
write-host $entry
$AllProgramsListBox.Items.Add($($entry))
}
#Declare & Create the form
$reader=(New-Object System.Xml.XmlNodeReader $AppGeneratorWindow)
$window = [Windows.Markup.XamlReader]::Load($reader)
##########################################
#Launch the User Interface #
[void]$window.ShowDialog() #
##########################################
This is launched from PowerShell which is where I have to get it to work from in some capacity.
Thanks in advance

You're very close. All you really have to do is move the part where you read the config file and do the foreach ($entry.. to below the creation of the window.
As the code is now, you're trying to use variable $window where it is not yet defined.
Directly below the XAML code put:
#Declare & Create the form
$reader = New-Object System.Xml.XmlNodeReader $AppGeneratorWindow
$window = [Windows.Markup.XamlReader]::Load($reader)
#List Boxes
$AllProgramsListBox = $window.FindName("AllProgramsListBox")
$ConfigurationFile = "$env:ProgramData\WindowsStartupTool\AutoStartConfig.XML"
[xml]$ConfigFile = Get-Content $ConfigurationFile -Raw
foreach ($entry in $ConfigFile.Configuration.AllowedAutoStart) {
Write-Host $entry
$AllProgramsListBox.Items.Add($entry)
}
##########################################
#Launch the User Interface #
[void]$window.ShowDialog() #
##########################################

Related

how to update the UI when binding datagrid to nested objects in powershell

I'm early days learning how to build a UI using PowerShell and WPF, and I'm stumped on how to connect an object to a DataGrid so that the UI automatically updates when items in the object change.
This is the WPF:
$Xaml = #"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Width="800" Height="300" Name="khsdeflpnonyb">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="Update" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="updateButton"/>
<Button Content="Update Async" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="updateButtonASync"/>
<Button Content="Refresh" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="refreshButton"/>
</StackPanel>
<DataGrid Grid.Row="1" Name="observableDataGrid" IsReadOnly="True" Margin="6" ItemsSource="{Binding serverList}" SelectedItem="{Binding selectedServer}">
</DataGrid>
</Grid>
</Window>
"#
I am using an 'observable' collection as the type, which i'm creating during the window OnLoad:
function OnLoad
{
$results = New-Object 'System.Collections.ObjectModel.ObservableCollection[System.Object]'
$results.Add([PSCustomObject]#{
"ServerInstance" = "MyServer"
"targetAccount" = "svcAccount"
"isEverythingDone" = $false
"Status" = ""
})
$observableDataGrid.itemsSource = $results
}
On pressing the "Update" button, i'm expecting the status to update in the UI:
function UpdateButton
{
# $State is the Data Context.
# selectedServer is bound to the observable DataGrid "selectedItem" property.
$State.selectedServer.Status = (Get-Random | Out-String)
# If I uncomment the following line it works
#$observableDataGrid.Items.Refresh()
# However, I understand it should be possible to change objects
# inside the "state" (Data Context - $State - the model) without calling
# Refresh and have them reflected in the UI (the 'view').
# This latter approach is preferred as I think this should then also work
# using PoshGUI's Async method.
}
function UpdateButtonAsync
{
Async {
$State.selectedServer.Status = (Get-Random | Out-String)
}
}
(The 'Async' function is from https://poshgui.com)
I can force the datagrid to update using the code below, but this isn't helpful in the asynchonous case because in poshgui this runspace only has access to the state and datacontext.
function Refresh
{
$observableDataGrid.Items.Refresh()
}
I also understand forcing a refresh is the 'wrong' way to do it.
I think the issue may be that PSCustomObject does not implement the iNotifyPropertyChanged interface, if that is the case can someone help guide how this might be done?
The full code is available on this gist.
Edit: an update that attempts to implement the INotifyPropertyChange interface is available on this gist, unfortunately this still does not allow me to update the model (DataContext) and have it reflect in the view (the grid).

How to use a user inputted value from a textbox in a variable (Powershell)

I'm having the hardest time getting a value from a text box to use in another function. If I step through the script, I can see that the value is assigned to the text box, but am not able to assign it to another variable.
Here is the relevant code:
#region XMLCode
[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:PayrollApp"
Title="Payroll Application" Height="450" Width="300" Margin="0,0,0,0">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="1" Content="Computer Name:"/>
<TextBox Grid.Row="1" Name="txtComputerName" Margin="120,5,5,5" />
<Label Grid.Row="2" Content="Site ID:"/>
<TextBox Grid.Row="2" Name="txtSiteID" Margin="120,5,5,5"/>
<Label Grid.Row="3" Content="Payroll ID:"/>
<TextBox Grid.Row="3" Name="txtPayrollID" Margin="120,5,5,5"/>
<Label Grid.Row="4" Content="Email From Address:"/>
<TextBox Grid.Row="4" Name="txtFromAddress" Margin="120,5,5,5"/>
<Separator Grid.Row="5" Margin="5"/>
<TabControl Grid.Row="6" Margin="5">
<TabItem Header="Daily Payroll">
<StackPanel Background="LightGray">
<TextBlock FontSize="12" Margin="5" TextWrapping="Wrap">
Use this form to re-run the Daily Payroll file.
</TextBlock>
<TextBlock TextWrapping="Wrap" FontSize="12" Margin="5,0">
Enter the dates (YYYYMMDD) needed in the boxes below and press "Send"
</TextBlock>
<TextBox Name="txtDaily1" Margin="5,10,5,5"/>
<TextBox Name="txtDaily2" Margin="5"/>
<TextBox Name="txtDaily3" Margin="5"/>
<TextBox Name="txtDaily4" Margin="5"/>
<TextBox Name="txtDaily5" Margin="5"/>
<Button Name="btnDailySend" Margin="5" Width="75" Background="BurlyWood">Send</Button>
</StackPanel>
</TabItem>
<TabItem Header="Weekly Payroll">
<StackPanel Background="LightGray">
<TextBlock FontSize="12" Margin="5" TextWrapping="Wrap">
Use this form to re-run the Weekly Payroll file.
</TextBlock>
<TextBlock TextWrapping="Wrap" FontSize="12" Margin="5,0">
Enter the date of the payroll period (Wednesday) (YYYYMMDD) and press "Send"
</TextBlock>
<TextBox Name="txtWeekly" Margin="5"/>
<Button Name="btnWeeklySend" Margin="5,10" Width="75" Background="BurlyWood">Send</Button>
</StackPanel>
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>
"#
#endregion
#region LoadWindow
#Read the XAML file
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try {
$window = [Windows.Markup.XamlReader]::Load($reader)
}
catch {
ThrowError -ErrorObj $_
}
# Create variables based on form control names
# Variable will be named as 'var_<control name>'
$xaml.SelectNodes("//*[#Name]") | ForEach-Object {
#"trying item $($_.Name)"
try {
Set-Variable -Name "var_$($_.Name)" -Value $window.FindName($_.Name) -ErrorAction Stop
}
catch {
ThrowError $_
}
}
# Get-Variable var_*
#endregion
#region EventsAndMethods
$window.Add_Loaded({
# Get the site information
GetSiteInformation
# Populate the text boxes
$var_txtComputerName.Text = $computer
$var_txtPayrollID.Text = $global:payid
$var_txtSiteID.Text = $global:SiteNum
$var_txtFromAddress.Text = $script:from
# Get the number of daily text boxes
$global:numDailyTextBox = (Get-Variable -Name "var_txtDaily*").Count
})
$var_btnDailySend.Add_Click({
# Email contents
$body = "PeopleSoft Team,`r`nHere are the time punch files that need to be uploaded to PeopleSoft.`r`nThanks."
$sub = "cctime Files for $sitename $payrollid"
$timefiles = #()
# Run the Payroll
$dailyTextBox = #(Get-Variable -Name "var_txtDaily*")
foreach ($textBox in $dailyTextBox) {
if ([string]::IsNullOrEmpty($textBox.Text)) {
continue
}
$date = $textBox.Text
RunDailyPayroll -day $date
LogInfo "Moving time file to C:\TA"
Move-Item -Path "$script:filepath\$script:dailyfile" -Destination $scriptPath -Force -Verbose
}
LogInfo "Sending email"
Send-MailMessage -To $emailTo -From $script:from -SmtpServer $server -Subject $sub -Body $body -Attachments "$scriptPath\$script:dailyfile" -Verbose
LogInfo "Email sent"
[Microsoft.VisualBasic.Interaction]::MsgBox("Email sent!", "OkOnly", "Email sent")
})
The issue is in the $var_btnDailySend.Add_Click event. There are 5 text boxes where the user will enter data into 1 or more of them. I then want to use that value in the RunDailyPayroll function. But I cannot assign that value to another variable. When stepping through, the value is: System.Windows.Controls.Text::<value entered>. How can I convert that to a string of just the <value entered>? And I've tried $date = $textBox.Text.ToString(), which just throws an error.
Thanks.
You should be able to extract the text with
$TextBox.Value.Text

How to render Window custom Title using XAML?

I have a Windows Forms Application that shows application Name on most application Forms as shown below. For application name 'VScodePrint 2015' I used a bitmap. To support high resolution screens I had to make a number of copies of this image to support different DPI settings.
I have just started redesigning my application using WPF to avoid having to set different images based on the DPI setting without using images.
I have created a WPF window but not sure how to render the application name like the Windows Forms version above.
Can some please show me how to render the application as per Windows Form version using XAML?
System.IO.Path.GetFileName(Assembly.GetEntryAssembly().GetName().Name);
Set a label or whatever control's content equal to that, and you will get the name as you are wanting.
I have managed to create a usercontrol that renders Window title for my windows. I am novice using WPF so may this not be the best XAML but here it is:
<UserControl x:Class="WindowTitle"
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:WpfApplication2"
mc:Ignorable="d" Height="109.986" Width="404.929">
<RowDefinition Height="80"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="DarkGray" BorderThickness="1" CornerRadius="10,10,0,0 " Background="#FF61238B" Margin="0,0,0,1">
<StackPanel Width="Auto" Height="Auto">
<StackPanel Height="Auto" Margin="0,0,0,0" HorizontalAlignment="Center" >
<Label x:Name="lblYear" Content="2015" FontSize="12" BorderBrush="White" Foreground="White" HorizontalContentAlignment="Right" Padding="0,0,0,0" VerticalAlignment="Bottom" FontFamily="Global User Interface" Margin="0,5,0,0"/>
<Label x:Name="lblProductName" Content="VScodePrint" FontSize="48" BorderBrush="White" Foreground="White" HorizontalContentAlignment="Right" Padding="0,0,0,0" VerticalAlignment="Top" FontFamily="Global User Interface" Margin="0,-5,0,0"/>
</StackPanel>
</StackPanel>
</Border>
<Label x:Name="lblVersion" Content="Version 14.0.20 Rev 1510" Grid.Row="1" VerticalAlignment="Center" Height="37" HorizontalContentAlignment="Center" Margin="0,0,0.429,0" FontFamily="Segoe UI Semibold">
<Label.Background>
<SolidColorBrush Color="#FFDBCBE3"/>
</Label.Background>
</Label>
Below is the above Window Title usercontrol in action:

PowerShell XAML - Get textbox text into variable

I am writing an application in which I need to have a dialog box for user input. The problem I am having is getting the value from a textbox into a variable after the user clicks on the button.
[xml]$XAML_ConnectDialog = #"
<Window Name="Form_ConnectDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Connect" Height="176" Width="328" ResizeMode="NoResize" ShowInTaskbar="False">
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FFB4B4B4" Offset="1"/>
<GradientStop Color="White" Offset="0.603"/>
</LinearGradientBrush>
</Grid.Background>
<TextBlock TextWrapping="Wrap" Text="Enter the hostname or IP address of the remote host to connect to." Margin="10,0,10,91"/>
<Label Content="Connect To:" HorizontalAlignment="Left" Height="27" VerticalAlignment="Top" Width="76" Margin="10,47,0,0"/>
<Button Name="Btn_ConnectDialog_Connect" Content="Connect" Height="20" Margin="194,88,26,20" IsDefault="True"/>
<TextBox Name="Txt_ConnectDialog_Input" HorizontalAlignment="Left" Height="23" Margin="91,51,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="208"/>
</Grid>
</Window>
"#
$XML_Node_Reader_ConnectDialog = (New-Object System.Xml.XmlNodeReader $XAML_ConnectDialog)
$ConnectDialog = [Windows.Markup.XamlReader]::Load($XML_Node_Reader_ConnectDialog)
$Btn_ConnectDialog_Connect = $ConnectDialog.FindName('Btn_ConnectDialog_Connect')
$Txt_ConnectDialog_Input = $ConnectDialog.FindName('Txt_ConnectDialog_Input')
$Btn_ConnectDialog_Connect.Add_Click({
$ConnectDialog.Hide()
$var = $Txt_ConnectDialog_Input.Text.ToString()
})
write-host $var
$ConnectDialog.ShowDialog() | Out-Null
Any help is appreciated.
Thanks
You're using Write-Host $var BEFORE you run the GUI. And since the GUI is used to define the variable in the first place, your Write-Host command will never return anything.
$var is not defined before your click-eventhandler. The eventhandler is a function, so the variable will be created in a local scope that only exists inside the function, and then deleted after the function/eventhandler is done. I've fixed this by specifying the eventhandler to store the value in the variable $var in the script scope, so it will be available until the script is finished.
Fixed script:
[xml]$XAML_ConnectDialog = #"
<Window Name="Form_ConnectDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Connect" Height="176" Width="328" ResizeMode="NoResize" ShowInTaskbar="False">
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FFB4B4B4" Offset="1"/>
<GradientStop Color="White" Offset="0.603"/>
</LinearGradientBrush>
</Grid.Background>
<TextBlock TextWrapping="Wrap" Text="Enter the hostname or IP address of the remote host to connect to." Margin="10,0,10,91"/>
<Label Content="Connect To:" HorizontalAlignment="Left" Height="27" VerticalAlignment="Top" Width="76" Margin="10,47,0,0"/>
<Button Name="Btn_ConnectDialog_Connect" Content="Connect" Height="20" Margin="194,88,26,20" IsDefault="True"/>
<TextBox Name="Txt_ConnectDialog_Input" HorizontalAlignment="Left" Height="23" Margin="91,51,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="208"/>
</Grid>
</Window>
"#
$XML_Node_Reader_ConnectDialog = (New-Object System.Xml.XmlNodeReader $XAML_ConnectDialog)
$ConnectDialog = [Windows.Markup.XamlReader]::Load($XML_Node_Reader_ConnectDialog)
$Btn_ConnectDialog_Connect = $ConnectDialog.FindName('Btn_ConnectDialog_Connect')
$Txt_ConnectDialog_Input = $ConnectDialog.FindName('Txt_ConnectDialog_Input')
$Btn_ConnectDialog_Connect.Add_Click({
$ConnectDialog.Hide()
$script:var = $Txt_ConnectDialog_Input.Text.ToString()
})
$ConnectDialog.ShowDialog() | Out-Null
write-host $var

wp7 popup blocking textbox in popup

I have a popup that opens on the MainPage with a couple of textboxes. When ever you focus on the lower textbox the keyboard obscures it from view. Usually the textboxes slide into view. i don't know why that is not happening here.
please help!
<UserControl x:Class="Controls.EditControl"
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:SampleData="clr-namespace:SampleData"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="800" Width="480"
d:DataContext="{d:DesignData ../SampleData/sampleEditPopup.xaml}">
<Grid x:Name="LayoutRoot" Background="#FF000000" Opacity="0.995">
<StackPanel Margin="0,20,0,0" Orientation="Horizontal" VerticalAlignment="Top">
<TextBlock TextWrapping="Wrap" Text="Name" HorizontalAlignment="Left" Height="26" Margin="15,10,0,10" Width="110" TextAlignment="Right"/>
<TextBox x:Name="tb_name"
TextWrapping="Wrap"
Width="340" Height="75"
Margin="10,13,15,12"
InputScope="Text" MaxLength="1000"
Text="{Binding Title, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,150,0,0" VerticalAlignment="Top">
<TextBlock TextWrapping="Wrap" Text="Description" HorizontalAlignment="Left" Height="26" Margin="15,40,0,10" Width="110" VerticalAlignment="Top" TextAlignment="Right"/>
<TextBox x:Name="tb_description"
TextWrapping="Wrap"
Width="340" Height="254"
Margin="10,13,15,12"
InputScope="Text" MaxLength="1000"
Text="{Binding Description, Mode=TwoWay}"/>
</StackPanel>
</Grid>
and here is the code to open it:
EditControl ec = new EditControl();
ec.Title = cm.Title;
ec.Description = cm.Description;
//sets appbar icons for accepting values
setEditIcons();
Popup edit = new Popup() { Child = ec, Tag = this };
edit.Closed += new EventHandler(edit_Closed);
edit.IsOpen = true;
from a UX perspective I'd heavily recommend against having any partial popup/overlay that has more than 1 or 2 buttons. It's just not done in WP7. If you have a form you'd like folks to fill out move it to its own page. Either by letting the user navigate to that page, or by introducing a new transient page (that cannot be navigated back into) prior to the current page.
You'll have more problems than just the on-screen keyboard in with form overlays. You'll need to change the AppBar to have "V" and "X" buttons for any data entry, you'll need to manage focus not slipping back into under the overlay/popup, you'll need to make sure the "back" button closes the popup, etc.
IMO The best approach is a simple and consistent UX.

Resources