How to perform data binding of WPF/XAML using PowerShell - wpf

I have several PowerShell modules I've developed using WPF/XAML and one of them uses an example I found and used to bind a DataGrid ItemSource property to a variable called "resultsData":
<DataGrid Name="gridResults" ItemsSource="{DynamicResource resultsData}"/>
Then in the Window.Resources section of my XAML file there is a reference made to the data binding value:
<Window.Resources>
<x:Array x:Key="resultsData" Type="sys:Object"/>
</Window.Resources>
Finally, in PowerShell I can update the DataGrid's property as follows:
$uiHash.Window.Resources["resultsData"] = $uiHash.resultsHash
This works really well and I'm trying to replicate it in another project where I'm simply trying to bind the text property of a TextBlock using the Windows.Resources section in my XAML file. The problem is I have no idea what to put in that section to make it work.
I've tried using the same <x:Array> tag but it's obviously not an array. I've tried <x:Code> and <x:Null> and a multitude of other options which all result in a failure to load the window along with Visual Studio's visual designer barfing...
Could someone help me understand what to put in the Windows.Resources section to ensure I can reference these properties in PowerShell through the Window.Resources object?

The Text property of a TextBlock can be set to or bind to a string which is defined like this in XAML:
<sys:String x:Key="textResource">some text...</sys:String>
...where sys is mapped to the System namespace:
xmlns:sys="clr-namespace:System;assembly=mscorlib"

Related

How to have test data on Visual Studio 11 when using WPF and data binding?

I have a tab control with a data template that renders data based on the template and the data on the source it is bound to.
However, this instantly makes UI development harder as I don't see anything in Visual Studio 11, because all data comes when the application is running. Is there some way to add test data that only appears while working with the UI?
This tutorial from MSDN was perfect: http://msdn.microsoft.com/en-us/library/ee823176.aspx
Basically:
Create a file DesignData/FooData/Foo.xaml with content such as:
<local:Foo xmlns:local="clr-namespace:YourProject"
SomeProperty="Sample" AnotherProperty="Bar" />
Note that Foo must be a class that exists under the namespace YourProject with the properties you just used.
Then select the file from the Solution Explorer and set the Build Action to Design Data.
Add a namespace to your MainWindow.xaml code:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
along with the other namespaces you have.
Then add this to your top-level Grid for instance:
d:DataContext="{d:DesignData Source=./DesignData/FooData/Foo.xaml}"
Now elements below that Grid element (under the influence of DataContext) can have the property:
<TabControl ItemsSource="{Binding Mode=OneWay}">...
In my case I used a tab control and my data context was a collection DesignData/FooData/FooCollection.xaml:
<local:FooCollection xmlns:local="clr-namespace:YourProject">
<local:Foo Prop1="Sample" Prop2="test" />
...
</local:FooCollection>

How do I break a large XAML file into sub-XAML files and maintain communication between the parent and child objects?

I'm new to WPF. I'm attempting to modify the project VisualStudioLikePanes from the book WPF 4 Unleashed. Because the panes are hidden by default until I run the project, I decided that it would be nice to place the pane I'm working on into a separate xaml file so that I can see the changes I make to the pane without needing to launch the executable.
So, based on some posts I read here on StackOverflow a few days ago, I added a new UserControl to the sample project and plopped the content of the pane in question into that. Here is what the UserControl attributes look like in the 'child' XAML file:
<UserControl x:Class="Sample.SettingsPanel"
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"
mc:Ignorable="d">
To include this control into the parent, I added the xmlns:sp namespace to the 'parent' XAML file:
<Window
Title="MainWindow"
x:Uid="Window_1" x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sp="clr-namespace:Sample"
x:Name="window">
I then 'included' the control via this:
<sp:SettingsPanel Visibility="Collapsed" x:Name="layer1" x:FieldModifier="private" />
I immediately found that in the code-behind file for the 'parent' XAML file, all of the code which made reference to any of the elements now contained in the 'child' XAML file were now unrecognized. So, I then removed (or commented out) all references to names and objects which were now contained within the 'child' XAML file and ever since then have been jumping through hoops to wire things back up.
For example, I want one TextBox in the 'child' XAML file to reflect what is in a TextBox in the 'parent' XAML file. I believe that the following binding would work, but, of course, I can't place this into the 'child' XAML, because it doesn't 'know' about the parent's 'test' element any longer.
<TextBox Text="{Binding ElementName=test, Path=Text}" />
I'm sure I've broken up the 'parent' XAML file incorrectly. I can't imagine that everytime somebody wants to break some segment of XAML out to another file they must rework all of their code behind and set up special communication hacks to let elements continue to communicate.
I did look at a variety of posts (e.g. Binding two UserControls to the same DataContext, or ViewModel? and What is the easiest way to break up large XAML files in my application?), but they didn't address my particular question.
Thanks,
Matt
When you split out your elements to a UserControl you can still access them by x:Name field value you provided. However, since you are new to WPF I would start looking into the MVVM pattern before you develop any "bad habits". It specifically addresses your concerns.

How to supply a design time value for silverlight textblock that is bound to viewmodel property?

I have a TextBlock in my XAML that has its text bound to a property in my viewmodel.
<TextBlock x:Name="SomeText" Text="{Binding TheTextProperty}" />
This works fine, but at design time, there is no viewmodel so the property is unresolvable and the text is blank. This is hard to work with in the designer because it shows no visible text.
How can I specify some default text to use at design time?
Maybe you could try
<TextBlock x:Name="SomeText" Text="{Binding TheTextProperty, FallbackValue='Some other text'}" />
as documented here.
You can also use Design Time Data to provide a rich binding experience in your solution. Its a little hard to set up and get running, but here's the gist.
First, you create your DataContext in xaml. Add a new Xml document to your solution (the root is a good place) and give it an .xaml extension. Lets call this file "foo.xaml" for this example.
In this file, remove all of the XML and start creating an instance of your DataContext type. For example, if your DataContext was a string (very simple example) your file would look like the following:
<string xmlns="clr-namespace:System;assembly=mscorlib">LOL!</string>
You might have yours look like
<ViewModel xmlns="clr-namespace:MyNamespace">
<ViewModel.MyObservableCollection>
<MyModel Name="foo" />
<!-- etc -->
Set the Build Action on this file to DesignDataWithDesignTimeCreatableTypes:
Next, in your View, add the following namespaces and properties to the root of your Window/UserControl:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="{d:DesignData Source=foo.xaml}"
Source is relative to the current document. So, if your solution looked like
Views
MyUserControl.xaml
Data
foo.xaml
you would set the Source to ../Data/foo.xaml.
There are other ways to create a DesignData context depending on whether your ViewModel can be instantiated at design time, etc.
Another option is to use the DesignerProperties.GetIsInDesignMode function to determine if the control is hosted in VS/Blend and Generate a fake DataContext in that case. Laurent Bugnion provides a number of examples of how to create and use design-time data in this post

How to bind XmlDataProvider.Source to MVVM property

I've got a treeview bound to an XmlDataProvider following this example. The app I am working on is following the MVVM pattern and the Xml is from a file that the user will open.
When I try to bind the Source property of the XmlDataProvider like so
<XmlDataProvider Source="{Binding Path=XmlFilePath}"/>
I get a "Binding can only be applied to a DependencyProperty of a Dependency object." or somesuch.
So short of cobbling the binding together procedurally is there a way to declaratively bind the XmlDataProvider Source? If I try to forgo the data provider and bind the tree directly to an XmlNode property I get an error about using XPath binding only with Xml objects; which makes absolutely no sense to me but I'm sure it's trying to tell me something important.
The answer appears to be: you can't.
I was able to solve my underlying problem (binding a treeview to an Xml document) by removing the XmlDataProvider from the equation and binding the TreeView directly to a ViewModel property that returns an XmlNode.
What had been tripping me up was that I took the binding code that pointed at the XmlDataProvider and pointed it at my property, leaving the XPath argument in place.
<TreeView ItemsSource="{Binding Path=ProjectDocument XPath=.}">
This would result in a runtime error: System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='.'
Which was not the most helpful. What it was really trying to say is that you can't bind to an XmlNode property AND provide an XPath argument in the binding (because it's the XmlDataProvider that knows what to do with that??).
<TreeView ItemsSource="{Binding Path=ProjectDocument}">
actually that was rather tough problem for me, cause I needed the app to load treeview from temp file, and assuming application can have different locations, I can't set strict link in the XmlDataProvider Source property;
Add source as resource to the project
the solution I found is adding temp file (markup is created via XAML, see below) to the project with build action set to Content thus, application reloads it every time you call InitializeComponent() on the object containing XmlDataProvider and my treeview updates.
<XmlDataProvider x:Key="dshPreview"
Source="~tmpConstruct.xml"
XmlNamespaceManager="{StaticResource argNms}"
IsAsynchronous="true"/>
TreeView is bound like this:
<TreeView x:Name="PreviewTree"
ItemsSource="{Binding Source={StaticResource dshPreview},
XPath=/mns:engine/mns:ws}"
/>
Maybe this will help someone
I didn't find how to bind the source straight away, but you can change the XmlDataProvider source in the code behind as following:
var xdp = (XmlDataProvider)this.Resources["key-of-your-XmlDataProvider-in-resources"];
xdp.Source = new Uri("http://url-of-your-xml");
You can use that combined with an event handler to bind.

How to access a WPF control located in a ControlTemplate?

Usually, the WPF controls are declared in the .xaml files and not in the code behind (.xaml.cs files). However, sometimes I need to use some of those controls in code behind in order to manipulate them. How can I get the handle of such a control if it "resides" in the xaml file?
You can use the FindName() method of the ControlTemplate class.
// Finding the grid that is generated by the ControlTemplate of the Button
Grid gridInTemplate = (Grid)myButton1.Template.FindName("grid", myButton1);
I'm unsure about what you're asking, so I'll try and answer both instances that I'm interpreting as your question.
1)
If you want to declare an explicit control, and then edit it directly, all you have to do is set the name property like such:
<Canvas x:Name="myCanvas"/>
You can then access the canvas through the Name as such:
myCanvas.Background = Brushes.Blue;
2)
If you're looking to declare a generic control, and then use it multiple times, you can do it like this:
<Window>
<Window.Resources>
<Ellipse x:Key="myEllipse" Height="10" Width="10">
</Window.Resources>
</Window>
You can then access that predefined control using this syntax in code:
Ellipse tempEllipse = (Ellipse)FindResource("MyEllipse");
If you want to use the Resourse as a template for multiple controls, add x:Shared="false".

Resources