wpf - How to use Path, ElementName with markup extension - wpf

I am using this markup extension
<DataGridTextColumn Header="Something"
Binding="{controls:SwitchBinding Something, Yes, No}" />
It all works fine, except that now I need to specify Path and Element Name for the Binding.(maybe even 'mode')
I have unsuccessfully tried:
Binding="{controls:SwitchBinding {Binding Path=SelectedItem.SystemDefined, ElementName=dgrdStatementBlocks}, Yes, No}"
Can somebody please point me to the correct way of doing this?
Thanks.

Why would you do this??
Binding="{controls:SwitchBinding {Binding Path=SelectedItem.SystemDefined, ElementName=dgrdStatementBlocks}, Yes, No}
Try the following:
Binding="{controls:SwitchBinding Path=SelectedItem.SystemDefined, ElementName=dgrdStatementBlocks, ValueIfTrue=Yes, ValueIfFalse=No}
Edit:
I tried this in a sample WPF(.Net4) (not Silverlight) application. And the following worked:
<CheckBox Name="CheckBox1"
IsChecked="True" />
<TextBlock Name="TextBlock1"
Text="{local:SwitchBinding ElementName=CheckBox1, Path=IsChecked, ValueIfTrue=Yes, ValueIfFalse=No}" />

Related

Resources as nodes in XAML

Is there any way to use a XAML resource as a node instead of an attribute? Something like this?
<Window.Resources>
<Button x:Key="TestButton" x:Shared="False" Content="..." />
</Window.Resources>
<my:ButtonBar x:Name="ButtonBar1">
<my:ButtonBar.Buttons>
{StaticResource TestButton}
</my:ButtonBar.Buttons>
<my:ButtonBar>
<my:ButtonBar x:Name="ButtonBar2">
<my:ButtonBar.Buttons>
{StaticResource TestButton}
</my:ButtonBar.Buttons>
<my:ButtonBar>
Obviously this is just an example and obviously this won't work.
But how could I make this work?
This should work:
<my:ButtonBar x:Name="ButtonBar1">
<my:ButtonBar.Buttons>
<StaticResource ResourceKey="TestButton" />
</my:ButtonBar.Buttons>
<my:ButtonBar>

WPF Binding up and down the Visual Tree

From a control in a WPF XAML view, I need to access the properties of another control that I can reach in the Visual Tree only when walking up to a common parent control and then down from there.
As an example:
<PageUserControl>
<Grid>
<TextBlock Text="Some example text" />
</Grid>
<TextBlock Text="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType=PageUserControl, Path=??? I want to access the TextBlock}" />
</PageUserControl>
I want to access the text property of the first text block from the second text block (this is just an example).
What I would need is a way to combine relative sources, first one to go up the visual tree and find the PageUserControl, second one to go down the visual tree from there and find the grid and then finally a third one to find the text block within the grid.
Am I missing something here or is it just not possible?
I cannot add control IDs or something like this, it has to work with control types only.
I was thinking about something like a relative source that takes a XPath syntax, but it seems as if this was meant for another purpose (binding XML documents).
Maybe another idea?
Thank you!
I found a solution for my problem. It is possible using this approach:
<PageUserControl>
<Grid>
<TextBlock Text="Some example text" />
</Grid>
<TextBlock Text="{Binding Path=Children[0].Children[0].Text,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PageUserControl}}" />
</PageUserControl>
While not very flexible, it is good enough for me.

Path.Data styling works only on first instance of styled object

A have a ListBox of items, every ListBoxItem contains an icon in the form of a Path object, like so:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid ...>
...
<Path Margin="4" Style="{StaticResource ErrorIconPath}"
Stretch="Uniform" Width="26" Height="26"
RenderTransformOrigin="0.5,0.5" Grid.Column="1" Grid.Row="1"
UseLayoutRounding="False"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
The Path's style is contained in Appl.xaml (Application.Resources section) and is the following:
<Style x:Key="ErrorIconPath" TargetType="Path">
<Setter Property="Data" Value="F1M874.094,289.369L854.3,254.63C854.028,254.151 853.515,253.856 852.958,253.856 852.403,253.856 851.89,254.151 851.617,254.63L831.824,289.369C831.555,289.84 831.559,290.416 831.835,290.883 832.111,291.348 832.618,291.634 833.165,291.634L872.752,291.634C873.299,291.634 873.805,291.348 874.081,290.883 874.357,290.416 874.361,289.84 874.094,289.369 M855.653,287.189L850.264,287.189 850.264,282.745 855.653,282.745 855.653,287.189z M855.653,279.41L850.264,279.41 850.264,266.077 855.653,266.077 855.653,279.41z" />
</Style>
The trouble is that only the first item in the ListBox binds the Data property as expected, the other ones don't bind it at all (hence they appear as blank space, but match the size of the Path). Also when I use the style anywhere else (i.e. outside the ListBox), only the first instance that occurs will bind.
The weird thing is that if I define for example the Fill property in the Style instead of inline, it works just fine and doesn't exibit the same problems as the Path property.
My guess is that is has something to do with Data not being a primitive type, but I haven't found any fixes.
EDIT: Interestingly, when I bind the Data property directly to System.String resource, it works. I would still like to be able to define this property via a Style though.
EDIT 2: I've just came across the same issue in WPF, when setting Path to a Content of a Button via a Style that is used across more buttons. The path shows up in just one buttons, the others are blank.
Path.Fill is a DependencyProperty, while Path.Data isn't. Instead do:
<DataTemplate>
<Grid ...>
...
<ContentPresenter Content="{StaticResource MyPath}"/>
</Grid>
</DataTemplate>
ContentPresenter.Content is a DependencyProperty so this should work:
<Path x:Key="MyPath" Margin="4" Style="{StaticResource ErrorIconPath}"
Stretch="Uniform" Width="26" Height="26" VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5" Grid.Column="1" Grid.Row="1"
UseLayoutRounding="False" HorizontalAlignment="Center"
Data="F1M874.094,289.369L854.3,254.63C854.028,254.151 853.515,253.856 852.958,253.856 852.403,253.856 851.89,254.151 851.617,254.63L831.824,289.369C831.555,289.84 831.559,290.416 831.835,290.883 832.111,291.348 832.618,291.634 833.165,291.634L872.752,291.634C873.299,291.634 873.805,291.348 874.081,290.883 874.357,290.416 874.361,289.84 874.094,289.369 M855.653,287.189L850.264,287.189 850.264,282.745 855.653,282.745 855.653,287.189z M855.653,279.41L850.264,279.41 850.264,266.077 855.653,266.077 855.653,279.41z"/>
I am guessing that Geometry cannot be shared. Have you tried setting the x:Shared= "false" to:
<Style x:Key="ErrorIconPath" TargetType="Path">
I've experienced the same behavior in Silverlight and asked a similar question here on StackOverflow.com
( https://stackoverflow.com/q/13426198/1796930), but as I'm writing this, it's been 1 month and I've yet to get even a single answer.
However, as you mentioned in your first edit, I too was able to perform a workaround by creating a resource with my geometry data as a string and then binding the Data property of the Path objects to the string resource resource.
I also had to create two instances of the Path objects that were identical other than each one using a different resource (i.e. two different icons) and then binding the visibility of each to a property in my ViewModel to display the appropriate one.
I am very sure that you did not forgot the stroke here in Path style
<Setter Property="Stroke" Value="Red"/>
I have tested you code on my machine , it worked fine if above line added in style
My first tought was your Path would be broken or not valid. But then I saw you are using the Syncfusion Metro Studio. I tried it with exactly the same code you have and it worked very well. In a Data Template of 5 Items or as a single Path Item.
Have you tried to set the Fill statically to Red or something?
Also maybe try this for the Style definition
<Style x:Key="ErrorIconPath" TargetType="{x:Type Path}">
Third suggestion would be to move the style definition from the App to your Page or even to your Control itself.
To be sure there will be no default styles applied, try
OverridesDefaultStyle="True"
Hope this helps :)

Best Practice for Inline binding with XAML and text Text="Some text {Some binding} some more text}"

I'm wondering if there is special syntax to bind text concatenated with existing text.
Something like this.
<TextBlock Grid.Row="0" Name="tbGroupMembershipCaption"
Text="The following users have access to export to '{Binding TargetName}'."/>
Clearly, this doesn't work.
What is the best practice?
Using SL4.
Use StringFormat on the Binding.
WPF: {Binding SomeProp, StringFormat={}Head text {0} Tail text}
WPF/SL: {Binding SomeProp, StringFormat='{}Head text {0} Tail text'}
WPF/SL Alt.: {Binding SomeProp, StringFormat=Head text \{0\} Tail text}
Text="{Binding TargetName, StringFormat=The following users have access to export to \{0\}}"
See http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.stringformat.aspx for more details.
Perhaps this:
Text="{Binding TargetName, StringFormat=The following users have access to export to '\{0\}'."
This is what worked for me. Close to the last one but that one would not work for me.
<TextBlock HorizontalAlignment="Right" Grid.Column="2" Grid.Row="1" Text="{Binding CreatedBy, StringFormat=By \{0\}}"/>

Binding with an escaped string format breaks VS IDE and intellisense

In Silverlight, I've got a hyperlinkbutton defined as the following:
<HyperlinkButton Content="{Binding FileName}" NavigateUri="{Binding MailLogAttachmentID, StringFormat=\/DownloadFile.aspx?objecttype\=proposalattachment&id\=\{0\}}" />
When I try to view the designer, instead of the XAML, I get a Unhandled Exception has occurred error (Index (zero based) must be greater than or equal to zero and less than the size of the argument list) and it gives me the option of reloading the designer. This also breaks any intellisense while developing in XAML. If I remove the NavigateUri StringFormat expression, all is well. The application compiles fine and the hyperlink button works as expected.
Is there another way I can get this functionality without breaking the designer?
This should do the trick, if you don't want a complicated escaped expression:
<HyperlinkButton DataContext="{StaticResource s}" Content="{Binding FileName}">
<HyperlinkButton.NavigateUri>
<Binding Path="MailLogAttachmentID"
StringFormat="/DownloadFile.aspx?objecttype=proposalattachment&id={0}" />
</HyperlinkButton.NavigateUri>
</HyperlinkButton>
In any case, the character that was generating the exception was the ampersand, so if you write it like this, it should work too:
<HyperlinkButton Content="{Binding FileName}"
NavigateUri="{Binding MailLogAttachmentID, StringFormat=/DownloadFile.aspx?objecttype\=proposalattachment&amp;id\={0}}" />

Resources