XAML form + Cancel button response - xaml

I am working on my first form in Powershell and am using XAML (built on the code from https://foxdeploy.com/2015/04/10/part-i-creating-powershell-guis-in-minutes-using-visual-studio-a-new-hope/).
The form works great so now I'm working on data validation. I am trying to make all of the fields mandatory through a While loop, but I can't break out of it. How would I take the code below and make it understand when someone clicks the Cancel button, that it should exit the loop? I tried checking $WPFcancelButton.IsPressed, but that doesn't seem to be getting updated.
Thanks.
Function Get-HubNameFields {
$inputXML = #"
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="Naming Tool" Height="350" Width="525">
<Grid Margin="0,0,-8,0" HorizontalAlignment="Left" Width="525">
<TextBlock x:Name="textBlock" Margin="10,10,145.907,0" TextWrapping="Wrap" Text="Define the parameters of a name" VerticalAlignment="Top" Height="17.945"/>
<Label x:Name="custLongNameLabel" Content="Customer Long Name" HorizontalAlignment="Left" Margin="10,32.945,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="custLongNameTxt" Height="21.96" Margin="141.003,36.945,224.239,0" TextWrapping="Wrap" VerticalAlignment="Top" ToolTip="Full name of the customer."/>
<Label x:Name="custShortNameLabel" Content="Customer Short Name" HorizontalAlignment="Left" Margin="10,59.905,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="custShortNameTxt" Height="21.96" Margin="141.003,63.905,224.239,0" TextWrapping="Wrap" VerticalAlignment="Top" ToolTip="Abreviation of the customer's name."/>
<Label x:Name="siteLongNameLabel" Content="Site Long Name" HorizontalAlignment="Left" Margin="10,86.865,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="siteLongNameTxt" Height="21.96" Margin="141.003,90.865,224.239,0" TextWrapping="Wrap" VerticalAlignment="Top" ToolTip="Full name of the site."/>
<Label x:Name="siteShortNameLabel" Content="Site Short Name" HorizontalAlignment="Left" Margin="10,113.785,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="siteShortNameTxt" Height="21.96" Margin="141.003,117.825,224.239,0" TextWrapping="Wrap" VerticalAlignment="Top" ToolTip="Abbreviation of the site's name."/>
<Label x:Name="hubNumberLabel" Content="Hub Number" HorizontalAlignment="Left" Margin="10,140.825,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="hubNumberTxt" Height="21.96" Margin="141.003,144.785,224.239,0" TextWrapping="Wrap" VerticalAlignment="Top" ToolTip="Number of the Hub."/>
<RadioButton x:Name="radioButton" Content="Data Center Hub" HorizontalAlignment="Left" Margin="10,0,0,122.611" VerticalAlignment="Bottom"/>
<RadioButton x:Name="radioButton1" Content="Office/Other" HorizontalAlignment="Left" Margin="10,0,0,102.651" VerticalAlignment="Bottom"/>
<Button x:Name="okButton" Content="OK" HorizontalAlignment="Left" Margin="18.928,0,0,10" VerticalAlignment="Bottom" Width="50" IsDefault="True"/>
<Button x:Name="cancelButton" Content="Cancel" HorizontalAlignment="Left" Margin="80.317,0,0,10" VerticalAlignment="Bottom" Width="50" IsCancel="True"/>
</Grid>
</Window>
"#
$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 {
Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .Net is installed."
}
#This line takes the XAML data, adds "WPF" to the front of each XML node name, and creates a global variable.
$xaml.SelectNodes("//*[#Name]") | Foreach {Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name) -Scope Global}
<#Only need this function and its call if you don't know the name of the variables that the function generates from the XML.
Function Get-FormVariables {
If ($global:ReadmeDisplay -ne $true) {
Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true
}
Write-host "Found the following interactable elements from our form" -ForegroundColor Cyan
Get-Variable WPF*
}
Get-FormVariables#>
#Specify what the OK button should do, when clicked.
$WPFokButton.Add_Click({$form.Close()})
#Now that the form is built, show it, surpressing other messages.
$form.ShowDialog() | Out-Null
}
#Initialize some local variables.
$hubType = $null
$TextInfo = (Get-Culture).TextInfo
While ((($customerLongName.Length -eq 0) -or ($customerShortName.Length -eq 0) -or ($siteLongName.Length -eq 0) -or ($siteShortName.Length -eq 0) -or ($hubType -eq $null)) -or ($WPFcancelButton.IsPressed -like "false*")) {
Write-Host "the cancel button value is $($WPFcancelButton.ispressed)"
Get-HubNameFields
$customerLongName = $WPFcustLongNameTxt.Text
$customerLongName = $TextInfo.ToTitleCase($customerLongName.ToLower())
$customerLongName = $customerLongName -replace '\s',''
$customerShortName = ($WPFcustShortNameTxt.Text).ToLower()
$customerShortName = $customerShortName -replace '\s',''
$siteLongName = $WPFsiteLongNameTxt.Text
$siteLongName = $TextInfo.ToTitleCase($siteLongName.ToLower())
$siteLongName = $siteLongName -replace '\s',''
$siteShortName = ($WPFsiteShortNameTxt.Text).ToLower()
$siteShortName = $siteShortName -replace '\s',''
If ($WPFradioButton.IsChecked -eq $true) {
$hubType = 'dh'
}
If ($WPFradioButton1.IsChecked -eq $true) {
$hubType = 'ch'
}
}

I added an event handler, to set a variable, and broke the loop based on that.
$WPFcancelButton.Add_Click({Set-Variable -Name UserCancelled -Value $true -Scope Global})

Related

How to bind properties for a custom user control properly in avalonia ui

I am trying to display a text on a custome user control. I want that text to be passed via a mainview
this is the code I have:
MainView.axaml
<cc:Slot Grid.Row="0" Grid.Column="1" Dot="Number one"/>
<cc:Slot Grid.Row="0" Grid.Column="2" Dot="Number two"/>
This is my custom user control:
Slot.axaml
<UserControl xmlns="https://github.com/avaloniaui"
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:controls="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:cc="clr-namespace:Diagnostica.CustomControls;assembly=Diagnostica.CustomControls"
x:Class="Diagnostica.CustomControls.OmniSlot">
<Button>
<TextBlock Text="{Binding Dot}"/>
</Button>
</Grid>
</Button>
</UserControl>
and its .cs file"
Slot.axaml.cs
public string Dot
{
get => GetValue(DotProperty);
set => SetValue(DotProperty, value);
}
public static readonly StyledProperty<string> DotProperty =
AvaloniaProperty.Register<Slot, string>(nameof(Dot), defaultValue: "Black");
what i get like this is a disabled box. How can this get fixed?
View:
<Rectangle Stroke="{TemplateBinding DotColor}" StrokeThickness="2" Width="20" Height="20" Fill="{TemplateBinding DotColorBrush}" VerticalAlignment="Top" HorizontalAlignment="Right"/>
ViewModel:
public static readonly StyledProperty<string> DotColorProperty = AvaloniaProperty.Register<OmniSlotControl, string>(nameof(DotColor), "Red");
public string DotColor
{
get => GetValue(DotColorProperty);
set
{
SetValue(DotColorProperty, value);
DotColorBrush = Avalonia.Media.Brush.Parse(value);
}
}

How can I find node within XAML with SelectNodes?

I'd like to find Button node within XAML in following PowerShell script. But I can't find it.
[xml]$xaml1 = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="640">
<Button Content="Button" HorizontalAlignment="Left" Margin="99,20,0,0" VerticalAlignment="Top" Width="60" Height="30"/>
</Window>
'#
$xaml1.SelectNodes("//Button") | ForEach {
$_.Name
}
# No OUTOUT from above code!
When I delete line 3 and 4, it works.
[xml]$xaml2 = #'
<Window
Title="MainWindow" Height="400" Width="640">
<Button Content="Button" HorizontalAlignment="Left" Margin="99,20,0,0" VerticalAlignment="Top" Width="60" Height="30"/>
</Window>
'#
$xaml2.SelectNodes("//Button") | ForEach {
$_.Name
}
# OUTPUT of above code:
Button
How can I find node within XAML with SelectNodes?
I found solution by checking property of each node.The following code works fine.
$xaml.SelectNodes("//*") | ? {$_.LocalName -eq "Button"} | % {
# action for each Button Node
}
The following is sample code using above.
[xml]$xaml = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300">
<StackPanel>
<Button x:Name="button0" Content="Button0"/>
<Button x:Name="button1" Content="Button1"/>
<Button x:Name="button2" Content="Button2"/>
<Button x:Name="button3" Content="Button3"/>
<Button x:Name="button4" Content="Button4"/>
<Button x:Name="button5" Content="Button5"/>
<ScrollViewer x:Name="scrollViewer" Height="150">
<TextBlock x:Name="msg" TextWrapping="Wrap"/>
</ScrollViewer>
</StackPanel>
</Window>
'#
$reader = New-Object System.Xml.XmlNodeReader $xaml
$frm = [System.Windows.Markup.XamlReader]::Load($reader)
$scrollViewer = $frm.FindName("scrollViewer")
$msg = $frm.FindName("msg")
$xaml.SelectNodes("//*") | ? {$_.LocalName -eq "Button"} | % {
$button = $frm.FindName($_.Name)
$button.add_Click({
$msg.Inlines.add($this.Content + " pushed`n")
$scrollViewer.ScrollToBottom()
})
}
$result = $frm.ShowDialog()
I'm sorry the followings are code:
[xml]$xaml1 = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="MainWindow" Height="400" Width="640">
<Button Content="Button" HorizontalAlignment="Left" Margin="99,20,0,0" VerticalAlignment="Top" Width="60" Height="30"/>
</Window>
'#
[System.Xml.XmlNamespaceManager] $nsmgr = $xaml1.NameTable;
$nsmgr.AddNamespace($null, 'http://schemas.microsoft.com/winfx/2006/xaml/presentation');
$xaml1.SelectSingleNode("//Button", $nsmgr)
Try this:
$xaml1.Window.Button
$xaml.SelectNodes("//*[#Name]") | ForEach-Object {Set-Variable -Name ($.Name) -Value $Form.FindName($.Name)}
Now you have the Controls as Variable...
if the Name of a Button is "button" you have a variable $button in Powershell.
add a click like this then...
$button.add_click({write-host "clicked!!"})

Binding an ExpanderView do a viewModel?

I made some ExpanderViews and hardcoded everything. That worked and looked nice so I wanted to clean up and only write one ExpanderView in xaml and load everything else with a binding.
As far as I understood I need a ListBox around the whole thing to make it more dynamic?
This is my code so far:
<ListBox ItemsSource="{Binding ContactDe}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}"
ItemsSource="{Binding LocationName}"
IsNonExpandable="False">
<toolkit:ExpanderView.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding LocationName}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" LineHeight="{StaticResource LongListSelectorGroupHeaderFontSize}" />
</DataTemplate>
</toolkit:ExpanderView.HeaderTemplate>
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<TextBlock Text="test" />
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Information}" />
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ContactViewModel-Class:
public class ContactDeViewModel : INotifyPropertyChanged
{
private string _locationName;
public string LocationName
{
get
{
return _locationName;
}
set
{
if (value != _locationName)
{
_locationName = value;
NotifyPropertyChanged("LocationName");
}
}
}
private List<string> _information;
public List<string> Information
{
get
{
return _information;
}
set
{
if (value != _information)
{
_information = value;
NotifyPropertyChanged("Information");
}
}
}
}
And this is where I fill the ContactViewModel:
this.ContactDe.Add(new ContactDeViewModel()
{
LocationName = "Stuttgart",
Information = new List<string>
{
"some text"
}
}
);
this.ContactDe.Add(new ContactDeViewModel()
{
LocationName = "Böblingen",
Information = new List<string>
{
"more text"
}
}
);
I made a SampleViewModel-File where I have:
<vm:MainViewModel.ContactDe>
<vm:ContactDeViewModel LocationName="Location 1" />
<vm:ContactDeViewModel LocationName="Location 2" />
</vm:MainViewModel.ContactDe>
In the preview-window it shows me 2 ExpanderViews with Location 1 and 2. But the same code doesn't work with the emulator or a real device. I don't really understand which Binding-Acces does what. It would already help me a lot if I could see a full example. I googled many tutorials but most only show 1 side, like a xaml without seing how the data is stored.
edit:
Now I edited the viewModel, so it's not a List<string> but a List<Info> with Info only containing string Text. So now I can say ItemsSource="{Binding Text}" which should be only 1 string at a time, right?
As stated in comment to #dellywheel's answer, that you set DataContext this way :
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
that set DataContext for use in design-time only, hence it doesn't work in run-time. To set DataContext with similar approach for use in run-time, you can try this way :
<ListBox ItemsSource="{Binding ContactDe}">
<ListBox.DataContext>
<vm:MainViewModel/>
</ListBox.DataContext>
........
........
</ListBox>
or this way to set DataContext in page level :
<phone:PhoneApplicationPage>
<phone:PhoneApplicationPage.DataContext>
<vm:MainViewModel/>
</phone:PhoneApplicationPage.DataContext>
........
........
</phone:PhoneApplicationPage>
Another suggestion, prefer ObservableCollection rather than List for use along with data binding. ObservableCollection automatically notify view to refresh whenever item added to or removed from collection.
You need to change your bindings slightly
<toolkit:ExpanderView Header="{Binding LocationName}"
ItemsSource="{Binding Information}"
IsNonExpandable="False">
<toolkit:ExpanderView.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontFamily="{StaticResource honeFontFamilySemiBold}" LineHeight="{StaticResource LongListSelectorGroupHeaderFontSize}" />
</DataTemplate>
</toolkit:ExpanderView.HeaderTemplate>
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<TextBlock Text="test" />
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
Hope that helps

Get all controls id of silverlight page

I want to get all control's id of silverlight page.
So I want to iterate through all controls inside xaml page.
For this I have used following code:
private List<UIElement> GetElement(UIElement parent, Type targetType)
{
List<UIElement> items = new List<UIElement>();
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (child.GetType() == targetType)
{
items.Add(child);
}
}
}
return items;
}
and I call above function on my button click event as below.
List<UIElement> lsttexts = GetElement(LayoutRoot, typeof(System.Windows.Controls.SLFramework.UniTextBox));
List<UIElement> lstlabels = GetElement(LayoutRoot, typeof(TextBlock));
List<UIElement> lstbtn = GetElement(LayoutRoot, typeof(Button));
List<UIElement> lstcombo = GetElement(LayoutRoot, typeof(ComboBox));
List<UIElement> lstStackpanel = GetElement(LayoutRoot, typeof(StackPanel));
Demo Example of my page:
<TextBlock Text="Name : " Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
<StackPanel x:Name="stkpnl" Grid.Row="0" Grid.Column="1" Orientation="Vertical">
<StackPanel x:Name="childpanel1" Orientation="Horizontal">
<TextBlock x:Name="lbl1" Text="Name : " HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox x:Name="txt1" Text="=test1"></TextBox>
</StackPanel>
<StackPanel x:Name="childpanel11" Orientation="Horizontal">
<TextBlock x:Name="lbl11" Text="Name : " HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox x:Name="txt11" Text="=test11"></TextBox>
</StackPanel>
</StackPanel>
It get all textbol and textbox outside the satckpanel, listitem and tab control.
But I want to get all control of page includiing which are inside TabControl, statckpanel and Listitem.
Thanks

DataBind to Combobox In SilverLight 4 .0

I am trying to databind to the combobox. Data is coming from a database table which name is tbltest and table has 2 fileds id and name.
When I am trying to bind name to combox it display me tbltest:name in View. I am using domain services and MVVM to bind data.
Below is my code of ViewModel:
public ViewModel()
{
var query = context.GetTblTestsQuery();
var load = context.Load(query);
load.Completed += (s, ea) =>
{
ObsCompanyCollection = new ObservableCollection<tblTest>(context.tblTests);
};
}
private ObservableCollection<tblTest> _ObsCompanyCollection = new ObservableCollection<tblTest>();
public ObservableCollection<tblTest> ObsCompanyCollection
{
get
{
return _ObsCompanyCollection;
}
set
{
if (_ObsCompanyCollection != value)
{
_ObsCompanyCollection = value;
NotifyPropertyChanged("ObsCompanyCollection");
}
}
}
and Below is code of my XAml file:
<UserControl.Resources>
<my:ViewModel x:Key="ViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ViewModel}">
<ComboBox Height="23" HorizontalAlignment="Left" Margin="47,128,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" DisplayMemberPath="{Binding name,Mode=TwoWay}" ItemsSource="{Binding ObsCompanyCollection,Mode=TwoWay}" SelectedItem="{Binding tbldata.SelectCompanyId,Mode=TwoWay}" />
I dont know what is wrong with this code. I want only name to display in my combobox.
Thanks
try this
<ComboBox Height="23" HorizontalAlignment="Left" Margin="47,128,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" DisplayMemberPath="name" ItemsSource="{Binding ObsCompanyCollection,Mode=OneWay}"