I have the following XAML:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Grid.Row" Value="{Binding Row, Mode=OneWay}" />
<Setter Property="Grid.Column" Value="{Binding Column, Mode=OneWay}" />
</Style>
</ListBox.ItemContainerStyle>
...
When the page loads, I'm getting the following XamlParseException:
Failed to assign to property 'System.Windows.Setter.Value'. [Line: 69 Position: 63]
InnerException:
NotSupportedException: Cannot set read-only property ''.
The line number in the error corresponds to the Grid.Row setter; if I put a hard-coded value instead of a binding, it works fine (but obviously it's not what I want).
What's going on? The inner exception message makes no sense; I'm not setting any read-only property, and I'm certainly not setting a property with no name!
I'm new to Windows Phone, but I'm pretty sure the same code would work fine in WPF... Is binding in a setter not supported on WP?
Your suspicions seem to be right - according to this article, WP doesn't support Binding in the Value of a Setter.
There is also a workaround given in the article, there has also been an update and another article. To be honest - I haven't played with those examples, but maybe they will help you somehow.
Related
I've created an ItemControl with a dataTemplate that contains a rectangle that will be colorized based of the ItemsSource. The date being fed to my application is a color hex code that does not contain the hash sign (#). Just a 6-character string. To get the color to show up correctly i need to format the 6-character string with the # in front of it. exp #A31F34
Here's the XAML
<DataTemplate x:Key="ColorSequenceSwatchPreviews">
<Rectangle Name="ColorSwatch" Height="20" Width="120" RadiusX="3" RadiusY="3" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,3,0,3">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill">
<Setter.Value>
<MultiBinding>
<MultiBinding.StringFormat><![CDATA[#{0}]]></MultiBinding.StringFormat>
<Binding Path="InnerXml" Mode="OneWay" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</Rectangle.Style>
</Rectangle>
I'm using a MultiBinding.StringFormat to format the string into a Hexcode properly, but am stumped as to why the fill of the rectangle is not colorizing.
I am able to get the rectangle to colorize if I do the MultiBinding with a TextBox, then bind the rectangle's fill property to the Text property of the textBox. However, I would much prefer binding directly from the rectangle's fill property like in my first example since it is cleaner.
<DataTemplate x:Key="ColorSequenceSwatchPreviews">
<StackPanel Orientation="Horizontal" Margin="0,3,0,3" VerticalAlignment="Center" HorizontalAlignment="Left">
<TextBox x:Name="Hexcode" Visibility="Collapsed">
<TextBox.Text>
<MultiBinding>
<MultiBinding.StringFormat><![CDATA[#{0}]]></MultiBinding.StringFormat>
<Binding Path="InnerXml" Mode="OneWay" />
</MultiBinding>
</TextBox.Text>
</TextBox>
<Rectangle Name="ColorSwatch" Height="20" Width="120" RadiusX="3" RadiusY="3" VerticalAlignment="Center" HorizontalAlignment="Left">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="{Binding ElementName=Hexcode,Path=,Mode=OneWay}" />
</Style>
</Rectangle.Style>
</Rectangle>
</StackPanel>
Is there a way to get the first example to work or am i stuck with using the code from the second example?
This can be achieved far more easily using a Converter. You don't even need MultiBinding for it. Simple Binding with a Converter should do it:
Here is the converter:
<ValueConversion(GetType(String), GetType(SolidColorBrush))>
Public Class HexToBrushConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
Return DirectCast(New BrushConverter().ConvertFrom("#" & value.ToString()), SolidColorBrush)
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
Return Nothing
End Function
End Class
All you need to do now is to create an object of the converter in your Resources section:
<local:HexToBrushConverter x:Key="HexToBrushConverter" />
(local is the namespace of your project where you define this converter class)
and then use it in the Fill property:
<Rectangle Fill="{Binding ElementName=Hexcode, Path=, Mode=OneWay, Converter={StaticResource HexToBrushConverter}}" />
My app had a series of buttons hardcoded to be a navigation menu, but I wanted to upgrade this to something more data-driven.
<Button Content="MyPage">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:NavigateToPageAction TargetPage="Namespace.MyPage"/>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Button>
But when I tried to put this behavior on a different XAML element (specifically a TextBlock as part of a data template) I got the following error.
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException'
occurred in NavMockUp.Windows.exe but was not handled in user code
WinRT information: Cannot add instance of type
'Microsoft.Xaml.Interactions.Core.EventTriggerBehavior' to a
collection of type 'Microsoft.Xaml.Interactivity.BehaviorCollection'
<TextBlock Text="Click for Page">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:NavigateToPageAction TargetPage="Namespace.MyPage"/>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</TextBlock>
Make sure you understand how EventTriggerBehaviors work
The error may be somewhat unhelpful, but this is being caused by the fact that a TextBlock element does not have an event called "Click" to attach to. Jerry Nixon has a good article on behaviors
To fix this simply replace the Click event with the Tapped event, because a TextBlock does have one of those.
<TextBlock Text="Click for Page">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:NavigateToPageAction TargetPage="Namespace.MyPage"/>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</TextBlock>
I'm making a ResourceDictionary of common styles that are used throughout my application and one of them is:
<Style x:Key="ME_BASE_AppbarButtonSaveStyle"
TargetType="AppBarButton">
<Setter Property="Label"
Value="Save" />
<Setter Property="ToolTipService.ToolTip"
Value="Save" />
<Setter Property="Icon">
<Setter.Value>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="" />
</Setter.Value>
</Setter>
</Style>
It's all ok if I apply the style only one AppbarButton on the Page, but if I want to have two buttons with the same style, I get the following error:
The parameter is incorrect
It's of ok (no error) if I remove the icon property out of the style...
But that's kind of missing the point...
Anyone experienced something similar? Perhaps...
Thank you for all the help.
Error HRESULT E_Fail has been returned from a call to a COM component.
This error will occurred when you use this style for the second AppBarButton. This error usually happens when a reference to a style or an event handler that does not exist or is not with the context of the XAML, you can see the exception information of your problem:
If you read this document: XAML resources must be shareable, you will find:
Custom types used as resources can't have the UIElement class in their inheritance, because a UIElement can never be shareable (it's always intended to represent exactly one UI element that exists at one position in the object graph of your runtime app).
Whether a Icon property of AppBarButton or a FontIcon derives from UIElement, so I guess this is the reason why can't this property be styled in the resource dictionary.
Besides, I will consider if this is a right direction to define the Icon property for each AppBarButton in the style, normally I'd like give each button a different icon as content.
But if you insist to do this, I can provide you a workaround method by defining the Content of the AppBarButton, this is the construction of your AppBarButton:
You use a FontIcon as the content of the AppBarButton, so we can modify your style like this:
<Style x:Key="ME_BASE_AppbarButtonSaveStyle" TargetType="AppBarButton">
<Setter Property="Label" Value="Save" />
<Setter Property="ToolTipService.ToolTip" Value="Save" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Given a style in a Page.Resource:
<Style x:Name="ItemTitle" TargetType="TextBlock">
<Setter Property="FontSize" Value="16"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
It is correctly applied to any regular TextBlock on the same page.
However, when I use a DataTemplate for an Item in a GridView on that page, this style does not apply.
<DataTemplate x:Key="Output" x:DataType="vm:Output">
<TextBlock Text="{x:Bind Text}"></TextBlock>
</DataTemplate>
It does work when I apply the style explicitly on the DataTemplate, e.g.:
<DataTemplate x:Key="Output" x:DataType="vm:Output">
<TextBlock Style="{StaticResource ItemTitle}" Text="{x:Bind Text}"></TextBlock>
</DataTemplate>
Does anyone know what's up?
It's expected and intentional. If it doesn't derive from Control (like DataTemplate) then it won't inherit an implicit style unless they're in the application resource dictionaries as global defaults.
Or more specifically;
Templates are viewed as an encapsulation boundary when looking up an implicit style for an element which is not a subtype of Control.
Hope this helps. Cheers.
Addendum:
If it's a situation where you have a lot of the same element nested in a Template you can just set it once and allow it to inherit to all the nested controls of the type like (in pseudo);
<Parent>
<Parent.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource ItemTitle}"/>
<Parent.Resources>
<!-- These will all inherit the Style resource now,
without explicit style setting individually. -->
<TextBlock/>
<TextBlock/>
<TextBlock/>
</Parent>
I'm trying to use the CommandBar class, but it isn't behaving.
Here is the XAML for my trivial test:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<CommandBar>
<AppBarButton Icon="NewWindow"></AppBarButton>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Secondary Button"></AppBarButton>
</CommandBar.SecondaryCommands>
</CommandBar>
</Grid>
However, when I press the ... overflow button on the CommandBar to expose the overflow menu, for whatever reason there is an ugly extra blank chin on the bottom of the overflow menu, making the whole thing look rather unprofessional. Here is a screenshot of the problem, with the blank space underneath the Secondary Button being the problematic part.
When testing on a first-party Universal Windows Platform app like the Edge browser, there is no such chin on the dropdown. For what it's worth, though, I suspect that Edge is using a custom version of the CommandBar, as I don't think there is any way to avoid the CommandBar extending downwards when you tap the ... overflow button, or to insert icon buttons into the dropdown menu like used for the Zoom buttons.
This is indeed the default style of the CommandBar.
You can remove that blank space by editing a copy of the CommandBarOverflowPresenter template and removing the bottom margin on the ItemsPresenter. Here is the resulting style:
<Style TargetType="CommandBarOverflowPresenter">
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}"/>
<Setter Property="MaxWidth" Value="{ThemeResource CommandBarOverflowMaxWidth}"/>
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CommandBarOverflowPresenter">
<Grid Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
<ScrollViewer AutomationProperties.AccessibilityView="Raw" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ItemsPresenter x:Name="ItemsPresenter" Margin="0"/>
</ScrollViewer>
<Rectangle Stroke="{ThemeResource SystemControlForegroundTransparentBrush}" StrokeThickness="1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
While Olivier's answer does cover how to remove the space below the CommandBar when the overflow menu is open (and does it well) - it doesn't explain the reasoning behind the "blank space" in the first place.
I thought I would add an answer to give a bit of weight as to the use of that "blank space", for future visitors to this question.
The purpose of the overflow button ... is dual-purpose. I'll explain below.
1 - Avoid Ambiguity
The overflow button ... icon provides a way for the user to view the Labels for the PrimaryCommands (the ones along the main strip of the CommandBar).
This proves very useful in the case that some of the icons may not be immediately obvious as to what they might mean.
For example:
×
Could mean either "Cancel", "No", "Delete" etc.
We can add Label="Delete" to the AppBarButton in order to distinguish that this button is to "Delete" an item or whatever.
If the user were to wish to find out what the icons for the buttons mean/represent, they could simply tap the ... to show the labels for the buttons.
In your screenshot, because your PrimaryCommands don't have any labels, there is just the whitespace displayed.
Here's an example of how we can use the Label in order to understand what the buttons mean:
<CommandBar>
<CommandBar.PrimaryCommands>
<AppBarButton Icon="Back" Label="Back" />
<AppBarButton Icon="Stop" Label="Stop" />
<AppBarButton Icon="Play" Label="Play" />
<AppBarButton Icon="Forward" Label="Next" />
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarButton Label="Like" />
<AppBarButton Label="Dislike" />
</CommandBar.SecondaryCommands>
</CommandBar>
The above code could be used to create a playback control bar for a media app:
When the user presses the ... button, the labels are then displayed clearly underneath each button - in order to see what they are intended for.
This kind of UI behaviour has been around since at least Windows Phone 8.1 (Silverlight), albeit with possibly different markup. I could be wrong - it could have been sooner - feel free to correct me
2 - Display SecondaryCommands
In addition to the above useful design feature (and as is obvious from the original question) - the ... overflow button can be pressed to show the SecondaryCommands.
It pops them out into view using the CommandBarOverflowPresenter that is defined.
This is more useful for "less important" actions that the user might wish to take. For example "Leave Feedback", "Download" - or whatever the designer might deem as not-so-important.
As per the sample above, the "Like" and "Dislike" buttons are not of utmost importance to the user in order to use the CommandBar effectively:
I hope this adds a bit of insight into how the CommandBar can be used to aid and enhance user experience in a UWP/WinRT/Silverlight app, in line with the currently accepted answer which shows how to remove the whitespace in the original question.