Powershell WPF checkbox binding - wpf

I have a MenuItem Checkbox in my main window as well as in another two windows:
<MenuItem x:Name = 'FileMenu' Header = '_File'>
<MenuItem x:Name = 'EnableAutostart' Header = '_Enable Autostart' IsChecked="{Binding AutoStart, Mode= TwoWay}" IsCheckable="true" ToolTip = 'Enables the autostart.' InputGestureText ='Ctrl+S'></MenuItem>
I use it to define whether or not the script automatically starts on user logon (a function checks for the scheduled activity and sets the checkbox accordingly) and when clicked it enables or disables it.
Now what if I want to keep all the 3 different windows checkboxes synced?
I read a lot about binding but can't really get it working, I tried to set the binding on a bool "Autostart" and to set it true before showing the window but it does nothing at all.
How can I define a bool in my code and make it so that, whenever I change that bool, it reflects on all the menuitems checkboxes bound to it? (even if the other windows are yet to be created/shown)
I read about needing to make it a property... can I just make a class, set a property to it called something like "AutoStart" and it would work?

Thank you #bluuf, you kind of gave me a hint.
Anyway comes out i actually achieved to do a databind previously in my many tests but as you said, the INotifyPropertyChanged is not so easy to handle in powershell, or maybe it is?
Good guy Trevor Jones (link at bottom) explained an easy way and i did the last steps to understand it and apply it to my code. Thank you Trevor.
He basically explains that this one collection:
System.Collections.ObjectModel.ObservableCollection[Object]
Has an already implemented iNotifyPropertyChanged that works well in powershell, without adding c# classes.
You just create that collection, add your bool to it, and point the binding.source to it.
Trevor's article, actually read it, worth your time:
https://smsagent.blog/2017/02/03/powershell-deepdive-wpf-data-binding-and-inotifypropertychanged/
P.S. Trevor also points to this article which explains how to implement the c# class (and more), if anyone is interested:
https://www.ephingadmin.com/better-know-a-powershell-ui-50-shades-of-bindings-part-1/

Related

How to use a control equivalent to the WinForms DataGridView in WPF

I've been creating an inspection form using WPF and I need a place where users can type an unknown amount of comments (hence why I'm not using textboxes). In my WinForms version of this application, I used a DataGridView and I could enter in as much information as I wanted to. I'm looking to do the same with a DataGrid or an equivalent control in WPF.
WinForms Example
I need to be able to do the same thing in WPF but I can't seem to add any rows in the DataGrid. On top of that, when I try to check CanUserAddRows it unchecks it immediatly.
So I checked out Vincent Sigal's blog post about this issue. He mentions something interesting:
... but beware of CanUserAddRows and CanUserDeleteRows as they can appear a little magical. Their values are coerced based on other properties such as DataGrid.IsReadOnly, DataGrid.IsEnabled, IEditableCollectionView.CanAddNew, and IEditableCollectionView.CanRemove. So this is another thing to watch out for when editing. If you run into a situation where you set CanUserAddRows or CanUserDeleteRows to true but it is changed to false automatically, check that the conditions below are met.
I verified this and my DataGrid is not read-only and it is enabled. Although, I have no idea where to find the IEditableCollectionView.CanAddNew and IEditableCollectionView.CanRemove ...
I don't think my situation should require a binding event on the DataGrid since the user is supposed to enter his comments directly into the DataGrid ... Is what I'm trying to do even possible? Perhaps I should use a different control?
I have to admit that I stopped reading through your question after the first paragraph, so please forgive me if I have understood you wrong... but if you just want to enter multi line text into a TextBox in WPF, you can do it by setting a couple of properties on it:
<TextBox TextWrapping="Wrap" AcceptsReturn="True" />
For a DataGrid, you can set these properties in the DataGridTextColumn.ElementStyle and/or DataGridTextColumn.EditingElementStyle as the WPF DataGridTextColumn multi-line input post shows quite nicely.
Please let me know if I did misunderstand you.
UPDATE >>>
Ok, so I came back to read the rest of your question... answering without reading the question can be risky business on this site. It's just as well that I did too, as I see you also want to know how to use the DataGrid.
I have to start by saying... take a deep breath... WPF is very different to WinForms... very different. In WPF we manipulate data rather than UI objects, so to add a new row actually means adding a new item to a collection. You can find a complete working example on the DataGrid Class page on MSDN.
Please also view the WPF DataGrid Control page on WPF Tutorial.NET for more examples. WPF has a lot to take in for new comers and can be quite bewildering, but it's well worth the trouble when you get into it.

How to use BindingSource in WPF?

How to declare a BindingSource in VB using WPF? I can't use a command like BindingSource.CancelEdit() like I used to when using Windows Form instead of WPF...
You could use a BindingGroup for that: set a BindingGroup on an element in XAML which contains all the controls that edit your object. By default, this will set the UpdateSourceTrigger on these controls to Explicit, which means that you will have to call BindingGroup.UpdateSources in order to actually change the properties of the object which is currently edited. So, you would do that in a Submit command or something similar.
If you want to cancel the edit, you can do that using BindingGroup.CancelEdit. This will throw away the cached values in the controls and reset them to the values of the bound properties.
I think this is a lot easier than implementing IEditableObject or a Memento...
The short answer is not good news - the isn't an equivalent method. Instead your approach needs to be a little different. One approach would be to implement the IEditableObject on your underlying class (or wrap it in an editable class). The second would be to implement Undo/Redo functionality. I think you will find searching for the terms bolded above and/or the memento pattern you will find lots of good examples, below is one.
Cancelling an update with WPF Binding

How to create databinding over two xaml files?

I am trying to come to a working understanding of how databinding works, but even after several tutorials I only have a basic understanding of how databinding works. Thus this question might seem fundamental to those more familiar with silverlight. Even if it is trivial, please point me to some tutorial that deals with this problem. All that I could find simply solved this via adding the data binding on a parent page.xaml (that i must not use in my case).
For the sake of this example let us assume, that we have 5 files:
starter.cs
button1.xaml + codeBehind
button2.xaml + codeBehind
The two buttons are generated in code in the starter(.cs) file, and then added to some MapLayer
button1 my_button1 = new button1();
button2 my_button1 = new button2();
someLayer.Children.Add(my_button1);
someLayer.Children.Add(my_button2);
My aim is to connect the two buttons, so that they always display the same "text" (i.e. my_button1.content==my_button2.content = true;). Thus when something changes my_button1.content this change should be propagated to the other button (two way binding).
At the moment my button1.xaml looks like this:
<Grid x:Name="LayoutRoot">
<Button x:Name="x_button1" Margin="0,0,0,0" Content="{Binding ElementName=x_button2, Path=Content}" ClickMode="Press" Click="button1_Click"/>
</Grid>
But everthing that i get out of that is a button with no content at all, it is just blank as the binding silently fails.
How could I create the databinding in the context I described? Preferably in code and not XAML ;)
Thanks in advance
The chunk of documentation you need to read is this: XAML Namescopes
Your button1 xaml has a binding looking for an element with the name "x_button2". However in a real application there can be many controls which in turn have nested controls. All of these controls have all manner of UI elements some of which may have names.
It would be impossible to get anything done if all names throughout the entire application had be unique. Yet that would need to be true if it were for your button1 to be able to hunt down the existence of another control somewhere in the visual tree outside of that which it actually knows (its own xaml).
Hence each loaded Xaml document exists in its own "namescope" and the search for other elements with other names is limited to that "namescope".
The are various solutions to this problem depending on what you real requirements are as opposed to the simplified problem in your question.
Typically you give each of your controls a DependencyProperty to which the inner button Content property binds. In "MapLayer" as call it, could then bind the propert on one of your button controls to the other.

Cannot see named Silverlight control in code

In my first few hours with Silverlight 3, as an avid WPF user, I am greatly disappointed at the many things it doesn't support. This seems like an odd issue to me and it's so generic that I cannot find anything online about it.
I have the following XAML:
<controls:TabControl x:Name="workspacesTabControl" Grid.Row="1"
Background="AntiqueWhite" ItemsSource="{Binding Workspaces, ElementName=_root}"/>
However, I cannot see the workspacesTabControl in code-behind. I thought maybe IntelliSense is just being mean and tried to go ahead and compile it anyway, but got an error:
Error 1 The name 'workspacesTabControl' does not exist in the current context
How do I access controls in code-behind?
EDIT: I realized I've pasted the wrong error - I have two controls inside the UserControl called workspacesTabControl and menuStrip. I cannot get to either one of them by their name in the code-behind.
Just in case, here is the XAML for the menuStrip:
<controls:TreeView Grid.ColumnSpan="2" Height="100" x:Name="menuStrip"
ItemContainerStyle="{StaticResource MenuStripStyle}"
ItemsSource="{Binding Menu, ElementName=_root}"/>
EDIT AGAIN:
I'm not sure if this is helpful, but I've taken a look at the InitializeComponent() code and here's what I saw:
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Windows.Application.LoadComponent(this, new System.Uri("/SapphireApplication;component/SapphireMain.xaml", System.UriKind.Relative));
}
It seems that it simply loads the XAML when it runs (not before or during compilation) so the menuStrip and workspacesTabControl names don't actually get registered anywhere (as they usually are in WPF/win Forms). Could that attribute be a problem? And where do I get rid of this requirement for all the future UserControls I make?
Check the properties in VS for the xaml file itself... make sure the Build Action is set to Page.
As ridiculous as it may sound, I have resorted to using FindName() method to access named items in code-behind:
this.FindName("workspacesTabControl") as TabControl
I realize that this is a ridiculous way but I am forced to use this for now. Please let me know if someone else has encountered this problem and have come up with a better solution!
When you first create a control, Visual Studio does not pick it up with intellisense. However, after you try to build the project, it should become availble. You can also just type the name in without intellisense and then build it. Haven't verified this, but I heard this was on the list of things to fix in SL4.
That being said, if you name a control inside of a datatemplate, that control is not directly accessible in code-behind. This is the same for WPF, though.
You should be able to see it in the codebehind, that part works the same as WPF, maybe if you fix the problem with the menuStrip, then visual studio will be able to build the xaml paty of the page and ull be able to access the tabcontrol
I've seen the same problem in my Silverlight development. Specific to my problem my named controls were nested inside other controls (i.e. a datagrid) and I was unable to access them in my code behind. Any named controls at the same nesting level or above the previously mentioned datagrid worked fine but anything inside it was lost into the abyss.
As already mentioned, it should just appear in Intellisense, however the fact that you're getting an error related to something else, i.e. "menuStrip" is probably interfering with Intellisense. Resolve that error and you'l probably find that you can access the "workspacesTabControl" control.
Are you possibly using some sample code or something where they've named a control "menuStrip" and you've renamed it?
Good luck
Check that you don't have any controls using the same class name as a namespace name. For example:
namespace Solution.ProjectName.workspacesTabControl
{
public class workspacesTabControl
{
...
}
}
This will also give you this error.
Good luck,
Mark

How do I Determine the Source of the SelectionChangedEvent

I have a question regarding a ComboBox in silverlight and it's selected item.
I would like to determine what triggered the SelectionChangedEvent, was it the user selecting a new item in the list or was it programatically set?
While ideally I would like to solve this using the CommandPattern (I am essentially using a modified RelayCommand (http://joshsmithonwpf.wordpress.com/2008/11/17/emulating-icommandsource-in-silverlight-2/). I am open to other suggestions.
I have also played around with the SelectionChangedEventArgs, which has an OriginalSource property, which upon first inspection may appear to help, however it is null (regardless of the manner in which the item was selected.)
Any ideas, other than setting an internal flag? :)
Thanks
Unfortunately this is a tough thing to determine, since the framework works pretty hard to simply bubble up any changes or user events in this situation as that selection changed event.
If you really need to, you could write a simple ComboBoxWrapper that is effectively the flag you're talking about - so you could derive from ComboBox, try overriding or hiding the CLR setter for SelectedItem, and then maintain state that way.
Any particular scenario in use here? There may be another way to approach a solution.

Resources