WPF DataTrigger on UserControl Not Working - xaml

My project is WPF (Windows Presentation foundation) with the 4.5 framework using Visual Studio 2012.
I have a UserControl in my window which I'd like to animate(move) automatically after input has been entered into a textbox.
Here is the usercontrol...
<nbcuc:Search x:Name="search" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<nbcuc:Search.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</nbcuc:Search.RenderTransform>
<nbcuc:Search.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SearchAnimationState, UpdateSourceTrigger=PropertyChanged}" Value="New">
<Setter Property="nbcuc:Search.HorizontalAlignment" Value="Left"/>
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource StoryboardSearch}" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</nbcuc:Search.Style>
</nbcuc:Search>
I know the Storyboard animation works because I had it working on the Window.Load event trigger. I want a property to be set to something and then fire the trigger. I know the property it working because I set the value to a textbox in my window.
I'm rather new to wpf and xaml so this really makes little sense to me why it would not work.
Thanks

Related

Create a Radio Button group using standard buttons

The idea here is simple, I've got 2 or more buttons and want to have them act like Radio Buttons. So only one can be checked at any time, and when one is checked the others must uncheck themselves. I'm using MVVM so don't want to go down the route of code behind although it would have been easier for this.
Here is the XAML I've tried which locks up due to the buttons referencing each other.
<Label Text="Group Header Sorting" TextColor="{DynamicResource InverseTextColor}"/>
<StackLayout Orientation="Horizontal" Spacing="0">
<buttons:SfButton x:Name="GroupHeaderSortAscButton" Text="Ascending" HeightRequest="35" WidthRequest="90" IsChecked="{Binding Source={x:Reference GroupHeaderSortDescButton}, Path=IsChecked, Converter={converters:InverseBoolConverter}}">
</buttons:SfButton>
<buttons:SfButton x:Name="GroupHeaderSortDescButton" Text="Descending" HeightRequest="35" WidthRequest="90" IsChecked="{Binding Source={x:Reference GroupHeaderSortAscButton}, Path=IsChecked, Converter={converters:InverseBoolConverter}}">
</buttons:SfButton>
</StackLayout>
I've also tried Data Triggers with more success but its still not perfect as it requires the unselected button pressed twice before it starts work.
<StackLayout Orientation="Horizontal" Spacing="0">
<buttons:SfButton x:Name="GroupHeaderSortAscButton" Text="Ascending" HeightRequest="35" WidthRequest="90" IsChecked="False">
<buttons:SfButton.Triggers>
<DataTrigger TargetType="buttons:SfButton" Binding="{Binding Source={x:Reference GroupHeaderSortDescButton}, Path=IsChecked}" Value="True">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
<DataTrigger TargetType="buttons:SfButton" Binding="{Binding Source={x:Reference GroupHeaderSortDescButton}, Path=IsChecked}" Value="False">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</buttons:SfButton.Triggers>
</buttons:SfButton>
<buttons:SfButton x:Name="GroupHeaderSortDescButton" Text="Descending" HeightRequest="35" WidthRequest="90" IsChecked="True">
<buttons:SfButton.Triggers>
<DataTrigger TargetType="buttons:SfButton" Binding="{Binding Source={x:Reference GroupHeaderSortAscButton}, Path=IsChecked}" Value="True">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
<DataTrigger TargetType="buttons:SfButton" Binding="{Binding Source={x:Reference GroupHeaderSortAscButton}, Path=IsChecked}" Value="False">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</buttons:SfButton.Triggers>
</buttons:SfButton>
</StackLayout>
I'm aware that from XF 4.6 they introduced the RadioButton control, I've tried this and its buggy and according to comments on Git Hub it will have major changes in XF 5, so I don't want to implement this experimental version.
This is the look I'm after:
We have achieved your requirement by using Syncfusion SfButton. To make it as toggle type, need to set the IsCheckable property as True. Then only it will update the IsChecked property properly. To maintain the single selection, we have extended the SfButton by including the GroupKey internal with further validation.
CustomRadioButton
I wanted to be able to do this using standard buttons and XAML and avoid 3rd party controls, nothing more nothing less.
I ended up using Syncfusion's SfSegmentedControl which works rather well, but this is a paid for, 3rd party control.

Custom control with text box and text block

I would like to build a validation text box, which would be a normal UWP TextBox wrapped within a StackPanel, which also contains a TextBlock. The intent is that a validation message can be shown beneath the text box when there is a validation error.
I know I can do this by creating a custom control, but this would require me to implement all the properties I need and create a bunch of dependency properties, etc.
I'm hoping there is an easier way, where I can just completely derive the text box, but override the display template for it and include a label beneath it.
You can get most of the way there in XAML using the built-in IDataErrorInfo-based validation machinery and defining a control template for the TextBox's Validation.ErrorTemplate. There's a pretty good article at this link:
The XAML from the article at the link above follows, also check out this discussion on WPF's built-in validation here.
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="5,0,5,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,2,40,2" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="OrangeRed" DockPanel.Dock="right" Margin="5,0,0,0"
Width="20" Height="20" CornerRadius="5"
ToolTip="{Binding ElementName=customAdorner,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center"
FontWeight="Bold" Foreground="white" />
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Getting a value from a higher databinding path

I have an object that contains a control defined in a control template, and an object which it gets notifications from.
These notification object keeps track of the status of the object, which translates on the screen to the colour in this instance, although they are used in other areas of the UI to reflect the state of these objects.
The rectangle colour changes fine on the status change, but I have another property which provides the foreground colour of the text.
However, because of the ContentPresenter getting the text from the control, I can no longer get the foreground colour with the TextBlock.Foreground setter in the style, as the binding is pointing elsewhere.
I could put the name of the object in the notification object as well which would get rid of this question and problem, but I have run up against a similar issue in other places, and as I am new to WPF would like to know the way to do it.
This is the main relevant part of the ControlTemplate 'AnimatedTemplate':
<Rectangle x:Name="ColourFill" Stroke="White" RadiusX="5" RadiusY="5">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding Path=FillColour}"/>
</Rectangle.Fill>
<Rectangle.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Active}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard> ... </BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="2"
TextBlock.FontFamily="Segoe UI"
TextBlock.FontWeight="Bold">
<ContentPresenter.Style>
<Style>
<Setter Property="TextBlock.FontSize"
Value="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent},
Converter={StaticResource PushPinContentSizeConverter}}" />
<Setter Property="TextBlock.Foreground"
Value="{Binding Path=TextColour}"/>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
this is created with:
ControlTemplate template = (ControlTemplate)_window.FindResource("AnimatedTemplate");
Control c = new ContentControl();
c.Template = template;
c.SetValue(ContentControl.ContentProperty, displayName);
c.DataContext = <the notification object referred to as the first binding>
_window.d1overlay.Children.Add(c);

UserControl style only visible in designer

I'd like to have page headers in my app with either an icon or text centered in a 50px high bar at the top of the page. Optionally with a back-button.
For this reason I use a UserControl on each page which gets either one of those styles applied: PageHeaderStyle or PageHeaderBackStyle.
My implementation of one of those is the following (style definition in my App.xaml):
<Style x:Key="PageHeaderBaseStyle" TargetType="UserControl">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="50" />
<Setter Property="Width" Value="NaN" />
<Setter Property="Background" Value="{StaticResource CDColor}" />
</Style>
<Style x:Key="PageHeaderStyle" TargetType="UserControl" BasedOn="{StaticResource PageHeaderBaseStyle}">
<Setter Property="Content">
<Setter.Value>
<Grid Background="{StaticResource CDColor}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{StaticResource MainPageModel}">
<TextBlock Style="{StaticResource PageHeaderTextBlockStyle}" Text="{Binding Title}" Visibility="{Binding TitleVisibility}" />
<Image Style="{StaticResource PageHeaderIconStyle}" Source="{Binding Icon}" Visibility="{Binding IconVisibility}" />
</Grid>
</Setter.Value>
</Setter>
</Style>
Applied like it should be:
<UserControl Style="{StaticResource PageHeaderStyle}" />
Now first I had used "Template" and applied a DataTemplate with the grid component. But this didn't work. Then I changed it to directly set the Content of the UserControl. This does work: After building the designer shows the page header (before it showed only the blue selection border, but no content - it was transparent).
But as soon as I start debugging the app on the emulator it disappears and the running app only shows a blank spot where it should be.
Why is this so? I mean after all the designer already shows it, why does it disappear then, though?
FYI: I do not get any binding exceptions nor any other. It just doesn't show up.
PS: I tried setting the Background in the base style while setting the grid's background to transparent. This didn't work either - only a blank spot.
Solved the problem: Best approach is probably to use a ContentControl. Using the Content property did not work, though. You have to use the ContentTemplate property. Using that one does work just fine.

Windows Phone 8.1 MenufFyout acting up(bug?)

I'm trying to have a MenuFlyout on every item of a ListView. This work's so far without a problem in the way i want it to. But there's one thing that never get solved no matter how much i try. No matter what property i set, the MenuFlyout always clamps to the right side of the screen. i've checked every link with documentation and questions in regards of Windows Phone 8.1 applications using this but without luck. Here's some of the code.
<StackPanel>
<AppBarButton Icon="More"
ClickMode="Release"
Foreground="Black"
IsDoubleTapEnabled="False"
IsHoldingEnabled="False"
RenderTransformOrigin="0.5,0.5"
VerticalAlignment="Top"
HorizontalAlignment="Right">
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyout.MenuFlyoutPresenterStyle>
<Style TargetType="MenuFlyoutPresenter">
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="Margin" Value="25,0,25,25"></Setter>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
</Style>
</MenuFlyout.MenuFlyoutPresenterStyle>
<ToggleMenuFlyoutItem Text="Copy" HorizontalAlignment="Left" />
<ToggleMenuFlyoutItem Text="Delete" HorizontalAlignment="Left" />
</MenuFlyout>
</AppBarButton.Flyout>
<AppBarButton.RenderTransform>
<CompositeTransform Rotation="90" TranslateX="0" TranslateY="0"/>
</AppBarButton.RenderTransform>
</AppBarButton>
</StackPanel>