Blur The Background Of A Custom Control - c#

The title might not be clear but I will explain now. I have a custom control that represents a modal (inspired by SingltonSean), When I trigger a command, it shows this modal that covers the rest of the elements behind it, it somewhat acts like a popup. Now I want everything behind it to be blurred. How can I achieve that?
This is my modal custom control:
<Style TargetType="{x:Type viewModel:Modal}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type viewModel:Modal}">
<ControlTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</ControlTemplate.Resources>
<Grid Visibility="{TemplateBinding IsOpen, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity="0.025" />
</Grid.Background>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" UseLayoutRounding="True" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=border}" />
</Grid.OpacityMask>
<Border x:Name="border" Background="White" CornerRadius="20" />
<Grid Width="500" Height="600">
<StackPanel Width="300" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Padding="10 5" Content="Close Modal" />
</StackPanel>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

You need to apply blur where content is:
<Grid>
<Grid>
<Grid.Effect>
<BlurEffect Radius="20"/>
</Grid.Effect>
<TextBlock Text="Some content I want to blur"/>
</Grid>
<TextBlock Text="Popup"/>
</Grid>
If you want to make a control, which is able to blur something before in visual tree, you still need to apply effect to it. One possibility is to use attached behavior:
public static class Behavior
{
public static UIElement GetBlurTarget(DependencyObject obj) => (UIElement)obj.GetValue(BlurTargetProperty);
public static void SetBlurTarget(DependencyObject obj, UIElement value) => obj.SetValue(BlurTargetProperty, value);
public static readonly DependencyProperty BlurTargetProperty =
DependencyProperty.RegisterAttached("BlurTarget", typeof(UIElement), typeof(Behavior), new PropertyMetadata((d, e) =>
{
if (e.NewValue is UIElement element)
element.Effect = new BlurEffect { Radius = 20 };
}));
}
Then layout should be like this:
<Grid>
<Grid x:Name="container">
<TextBlock Text="Some content I want to blur" />
</Grid>
<TextBlock Text="Popup" local:Behavior.BlurTarget="{Binding ElementName=container}"/>
</Grid>
Both cases will produce same result:

Related

How to use a ContentPresenter inside a UserControl

I'd like to create a UserControl (in this case a square-Button with defined Backgroundcolors) which can host it's own content.
UserControl:
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<Button>
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate>
<Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter/>
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Now, as you may expect it, if I use this Control inside my MainView everthing works just fine until I define some Content.
Using:
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
In this case "TEST" will override the whole Content of the UserControl (the whole Button Template). I guess this happens because The Button inside the UserControl is defined as "Content" itself and it will get overridden when defining new Content.
So the final question is: Is it possible to achieve what I'm looking for? if yes: How? How could I "redirect" the Content I'm defining in my MainView into the self-defined ContentPresenter inside my Button Template instead of the UserControls's ContentPresenter?
If possible I don't want to create a new dp-propery which hosts my Content, e.g.:
<controls:MordernButton Size="200" BackgroundColor="Light">
<controls:ModernButton.Content>
I don't want this, if possible
</controls:ModernButton.Content>
</controls:ModernButton>
Use the ContentPropertyAttribute to instruct the xaml to set this property instead of the actual Content property.
[ContentProperty("InnerContent")]
public partial class ModernButton : UserControl
{
public ModernButton()
{
InitializeComponent();
}
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(object), typeof(ModernButton));
public object InnerContent
{
get { return (object)GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
}
Then in your xaml, Bind the Content Presenter to use InnerContent property instead.
<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/>
This way you can do the following without replacing the actual content.
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
Here we go.
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Button Content="{TemplateBinding Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template >
<ControlTemplate TargetType="Button">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Let's assume that youre UserControl is:
<UserControl x:Class="QuickAndDirtyAttempt.Decorator" ....
<UserControl.Template>
<ControlTemplate TargetType="{x:Type local:Decorator}">
<StackPanel Orientation="Vertical">
<Label>Foo</Label>
<ContentPresenter/>
<Label>Bar</Label>
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Note the TargetType property on the template: without it the project will happily compile, but the ContentPresenter will not work.
And then:
<Window ... >
<StackPanel Orientation="Vertical">
<local:Decorator>
<Label Background="Wheat">User supplied content here</Label>
</local:Decorator>
</StackPanel>
</Window>
I strongly recommend you to read this before implementing anything
Simple; Just circumvent and replace the UserControl's Template.
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Button Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
All a user control is (at least it terms of XAML and its template), is a Border with a ContentPresenter inside it. The ContentPresenter being the only important part, really.
So all you do is gut out its Template and feed the Content property the UserControl has into something a little different; in this case, your button.
This is the difference between making a usercontrol out of other controls, and shoving some controls into a user control.
Making the usercontrol out of other controls gives you much more power.
My example for dialog box
<UserControl
x:Class="CyberpunkModManager.Controls.DialogBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CyberpunkModManager.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
Foreground="{StaticResource ThemeForeground}"
mc:Ignorable="d">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid Background="{StaticResource ThemeTransparentColor}">
<Border
MinWidth="400"
Padding="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{StaticResource ThemeElement}"
CornerRadius="4">
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>

ScrollViewer not working with MouseWheel on GroupBox

I am trying to get a scrollviewer to work in a custom styled groupbox.
This is the style for the groupbox:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--Set default style of groupbox-->
<Style TargetType="GroupBox">
<Setter Property="Margin" Value="0, 10, 0, 0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Border CornerRadius="4" BorderThickness="1" BorderBrush="{StaticResource BorderBrush}" Background="{StaticResource ContentBackgroundBrush}">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" CanVerticallyScroll="True">
<Label Content="{TemplateBinding Header}" Margin="5,5,0,0" Style="{StaticResource SmallTitle}"></Label>
<ContentPresenter Margin="10, 5, 10, 10" RecognizesAccessKey="True" x:Name="CtlGroupboxPresenter" />
</StackPanel>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The scrollbar shows up, but I can't scroll using the mouse wheel. It works however when my mouse if over the vertical scrollbar. It seems like a tracking issue.
I saw some guys on SO that suggest adding some code to code behind to get it working, but as this is in a resource dictionary I have no place where I could put it...
Does anyone know what the issue is?
Here is an image of the wpf form:
XAML inside the groupbox:
<UserControl x:Class="Sun.Plasma.Controls.ViewNews"
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">
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Style="{StaticResource LblTitle}" FontWeight="Bold" FontSize="24" >Latest SUN news & announcements</Label>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical" Name="CtlLoadingNews">
<Label Style="{StaticResource LblContent}">Loading content from server...</Label>
<ProgressBar IsIndeterminate="True" Height="30" />
</StackPanel>
<ListView Background="Transparent" DockPanel.Dock="Bottom" ItemsSource="{Binding NewsFeeds}" BorderBrush="Transparent" Name="CtlNews" Visibility="Collapsed">
<!-- Defining these resources prevents the items from appearing as selectable -->
<ListView.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0 0 0 20">
<Label Style="{StaticResource LblTitle}" FontWeight="Bold" Content="{Binding Title}" />
<StackPanel Orientation="Horizontal">
<Label Style="{StaticResource LblFooter}" Content="{Binding PublishDate}" />
<Label Style="{StaticResource LblFooter}">By</Label>
<Label Style="{StaticResource LblFooter}" Content="{Binding Authors[0]}" />
<Label Style="{StaticResource LblFooter}">
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding Source}">Read entry</Hyperlink>
</Label>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DockPanel>
The problem is that the ListView in the contents of the GroupBox stops the MouseWheel event from bubbling up to the ScrollViewer. I found a hacky solution:
You handle the PreviewMouseWheel event on the inner ListView and raise the MouseWheel event directly on the scroll viewer.
private void ListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!e.Handled)
{
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
eventArg.RoutedEvent = UIElement.MouseWheelEvent;
eventArg.Source = sender;
//navigate to the containing scrollbar and raise the MouseWheel event
(((sender as ListView).Parent as GroupBox).Content as ListView).RaiseEvent(eventArg);
}
}
Again, this is not a solution I particularly like, because it is dependent on the layout of the GroupBox.
A second, slightly better way is to add a style to the resources of the GroupBox in which you add a handler to the PreviewMouseWheel event:
<GroupBox Header="test">
<GroupBox.Resources>
<Style TargetType="ScrollViewer">
<EventSetter Event="PreviewMouseWheel" Handler="ScrollViewer_PreviewMouseWheel" />
</Style>
</GroupBox.Resources>
<!-- your contents -->
</GroupBox>
The event handler then does the scrolling:
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var scrollViewer = sender as ScrollViewer;
double change = e.Delta;
double currentPosition = scrollViewer.VerticalOffset;
scrollViewer.ScrollToVerticalOffset(currentPosition - change);
}

Button font properties ignored when customizing button content

I got the following setup:
<Button x:Name="DeleteFilter" Margin="5" Grid.Column="1" Padding="2">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Stretch="Fill" Margin="5 3">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_delete}"/>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="{Resx DeleteFilter}"/>
</StackPanel>
</Button>
However, when launching my application I get the following result which is not what I want. All font properties seem to be ignored when I set the Content property of my button manually.
Live example:
I'd like to have the same fontstyle and fontsize as the right button. I tried to specify the style manually by using StaticResource and DynamicResource as follows:
<Button Style="{StaticResource MetroButton}"....
but nothing changed.
I guess that I need to implement a style which overrides the existing one and transfers the formatting to the TextBlock element but I have no clue how to do that.
The working "LOAD FILTERS" button in the right:
<Button x:Name="LoadFilter" Content="{Resx LoadFilters}" Margin="5" Grid.Column="2"/>
MahApps.Metro's standard button (MetroButton) is included in this file.
The style I applied to my icon button:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MetroIconButton" BasedOn="{StaticResource MetroButton}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
In your setup the StackPanel is used as a content which is not so ideal, you may create a style containing the template and the required property setters for font so it remain consistent for the desired buttons across the application.
So if I try to create a button style for you that would be
<Style x:Key="MetroButton" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
then I would use this style on button as
<Button Content="Delete" Style="{StaticResource MetroButton}" Tag="{StaticResource appbar_delete}"/>
Update
leveraging the ContentTemplate to achieve the same while utilizing the existing template.
<Style x:Key="MetroIconButton" BasedOn="{StaticResource MetroButton}" TargetType="{x:Type Button}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType=Button}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentControl Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
usage remain quite same except the style MetroIconButton
<Button Content="Delete" Style="{StaticResource MetroIconButton}" Tag="{StaticResource appbar_delete}"/>
I am using Tag property to hold the icon so it is plug and play for you, but better is to use Attached properties for the same. l:ExtraProperties.Icon={StaticResource appbar_delete}", I can provide a sample if you need that too.
Actually in previous style we override the Template defined in the MetroButton style so it failed. After looking at the original implementation of MetroButton style I come up with the ContentTemplate way to actieve the same. So instead of setting Template we will set the content template which will be picked up by MetroButton style and applied to the content.
Using Attached Properties
declare a class inheriting DependencyObject or any of its derived class along with the desired property as mentioned below
class ExtraProperties: DependencyObject
{
public static Visual GetIcon(DependencyObject obj)
{
return (Visual)obj.GetValue(IconProperty);
}
public static void SetIcon(DependencyObject obj, Visual value)
{
obj.SetValue(IconProperty, value);
}
// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(Visual), typeof(ExtraProperties), new PropertyMetadata(null));
}
add namespace to your xaml
<Window x:Class="Example.MainWindow"
...
xmlns:l="clr-namespace:Example">
then change the style as
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=(l:ExtraProperties.Icon)}"/>
and usage as
<Button Content="Delete" Style="{StaticResource MetroIconButton}" l:ExtraProperties.Icon="{StaticResource appbar_delete}"/>
using Attached properties is more WPF approach, instead of hacking other properties which may not be guaranteed to behave as expected.

Windows store app - XAML - One style with different images

I've been looking at a blog that contains some info about having styles for app bar buttons. Below is one of the styles i edited slightly.
<Page.Resources>
<ResourceDictionary>
<Style x:Key="TasksButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="9"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0" To="White" Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="ButtonEllipse" />
<ColorAnimation Duration="0" To="Black" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Glyph" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel Orientation="Vertical">
<Grid Margin="0,14,0,5" >
<Ellipse x:Name="ButtonEllipse" Height="40" Width="40" Fill="Transparent" HorizontalAlignment="Center"
Stroke="#FF00A5E7" StrokeThickness="2" VerticalAlignment="Center"/>
<Image x:Name="ButtonImage" Source="/Assets/Image1.png" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center"
FontFamily="Segoe UI" FontSize="12"/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Page.Resources>
I want to use this style many times though I'm unsure if there is way I can change the image source of this line
<Image Source="/Assets/Image1.png" HorizontalAlignment="Center" VerticalAlignment="Center"/>
without simply just copying a pasting the entire style.
I want to do something like this. (I've tried it but it doesn't appear to be valid)
Pseudo XAML
<Button x:Uid="appbarOne" Click="NavButton_Click" Tag="Client.Pages.one" Style="{StaticResource TasksButtonStyle ButtonImage.Source="Assets/Image1"}" Content="Tasks"/>
<Button x:Uid="appbarTwo" Click="NavButton_Click" Tag="Client.Pages.two" Style="{StaticResource TasksButtonStyle ButtonImage.Source="Assets/Image2"}" Content="Tasks"/>
<Button x:Uid="appbarThree" Click="NavButton_Click" Tag="Client.Pages.three" Style="{StaticResource TasksButtonStyle ButtonImage.Source="Assets/Image3"}" Content="Tasks"/>
<Button x:Uid="appbarFour" Click="NavButton_Click" Tag="Client.Pages.four" Style="{StaticResource TasksButtonStyle ButtonImage.Source="Assets/Image4"}" Content="Tasks"/>
Is there a way i can do this using something similar to Style="{StaticResource TasksButtonStyle ButtonImage.Source="Assets/Image4"}"?
Replace <Image /> in custom style with this.
<Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None"
Source="{Binding Path=(local:AppBarButton.Image),RelativeSource={RelativeSource TemplatedParent}}"/>
Remove below line from style as there is no element named "Glyph"
<ColorAnimation Duration="0" To="Black" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Glyph" />
Add a class named AppBarButton with below given definition. It has one attached property Image. We will use that to provide image source from button tag to button style.
public class AppBarButton
{
public static string GetImage(DependencyObject obj)
{
return (string)obj.GetValue(ImageProperty);
}
public static void SetImage(DependencyObject obj, string value)
{
obj.SetValue(ImageProperty, value);
}
public static readonly DependencyProperty ImageProperty =
DependencyProperty.RegisterAttached("Image", typeof(string), typeof(AppBarButton), new PropertyMetadata(string.Empty));
}
Now in you XAML page add buttons like this,
<StackPanel>
<Button Style="{StaticResource TasksButtonStyle}" local:AppBarButton.Image="ms-appx:///Assets/Screenshot_2.png" />
<Button Style="{StaticResource TasksButtonStyle}" local:AppBarButton.Image="ms-appx:///Assets/Screenshot_3.png" />
<Button Style="{StaticResource TasksButtonStyle}" local:AppBarButton.Image="ms-appx:///Assets/Screenshot_4.png" />
</StackPanel>
Here local refers to namespace of class AppBarButton. For my case it's
<Page
x:Class="App2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
Because I declared AppBarButton class in App2 namespace.
you can use put the styles in a new xaml file say globalstyles.xaml.
then refer the xaml file in you page as below,
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Styles.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
once the styles have been referred in the Page you can use the style as below
<Button Name="cancel" Content="cancel" Style="{StaticResource CancelButtonStyle}"
HorizontalAlignment="Right" Margin="5,45,5,7" />
<Button Name="Submit" Content="Submit" Style="{StaticResource SubmitButtonStyle}"
HorizontalAlignment="Right" Margin="5,45,5,7" />
Hope this helps.
You can define a template that will use an attached property. In code, add a new class for the attached property:
public class AssociatedObject
{
public static ImageSource GetImage(DependencyObject obj)
{
return (ImageSource)obj.GetValue(ImageProperty);
}
public static void SetImage(DependencyObject obj, ImageSource value)
{
obj.SetValue(ImageProperty, value);
}
// Using a DependencyProperty as the backing store for Image. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageProperty =
DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(AssociatedObject), new PropertyMetadata(null));
}
Then, in your template, do a TemplateBinding to the parent object (removing most of the style for brevity):
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
// REMOVED A BUNCH HERE
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="3">
<Grid>
// YOUR IMAGE IS HERE
<Image Source="{TemplateBinding local:AssociatedObject.Image}" Stretch="None"/>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
</ControlTemplate>
// REMOVED A BUNCH HERE
</Setter.Value>
</Setter>
</Style>
Look at the Image element in the Grid. It contains a TemplateBinding to the parent. Then, when you instantiate your button in XAML, you simply need to say what the AssociatedObject.Image is set to:
<Button Style="{StaticResource ButtonStyle1}" local:AssociatedObject.Image="/assets/Logo.scale-100.png"></Button>
If you want the look of an appbar button, you should look at the AppBarButton class instead which has everything for you. You can then use the Icon property to use one of the 200+ built-in icon styles or provide your own through the PathIcon, SymbolIcon or BitmapIcon classes as well.
See: http://timheuer.com/blog/archive/2013/10/29/use-new-appbarbutton-in-windows-8-1-commandbar.aspx

One-sided rounded buttons in Silverlight

I want to make a collection of buttons in silverlight.
They are in a collection that goes from left to right and the buttons are lined up so that they are touching on the left and right sides.
Here is the rub:
The collection has rounded corners but the buttons in between the end buttons in the collection do not have rounded ends. So basically, for the buttons on the far left and right side of the collection, they have to be somewhat special because they have to have one flat vertical side and one rounded side. Is this possible to do in silverlight without resorting to making a special bitmap for the end buttons?
One idea I have is somehow declare a canvas with a bitmap background and then have overlapping ellipse and rectangle
<Canvas Height="100" HorizontalAlignment="Left" Margin="189,381,0,0" VerticalAlignment="Top" Width="200" Background="Black">
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Stroke="Black" Width="58" Height="61" Canvas.Left="7" Canvas.Top="16" />
<Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Stroke="White" Width="65" StrokeThickness="0" Height="59" Canvas.Left="31" Canvas.Top="17" />
</Canvas>
Here is a simple example of the effect you are trying to achieve that utilizes custom ControlTemplate to skin the buttons in three ways:
<Grid HorizontalAlignment="Center">
<Grid.Resources>
<Style x:Key="ButtonLeftStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="DarkGray" CornerRadius="10,0,0,10">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ButtonCenterStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="DarkGray" CornerRadius="0,0,0,0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ButtonRightStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="DarkGray" CornerRadius="0,10,10,0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Orientation="Horizontal">
<Button Width="75" Height="25" Style="{StaticResource ButtonLeftStyle}" Content="Left"/>
<Rectangle Width="2"/>
<Button Width="75" Height="25" Style="{StaticResource ButtonCenterStyle}" Content="Center"/>
<Rectangle Width="2"/>
<Button Width="75" Height="25" Style="{StaticResource ButtonRightStyle}" Content="Right"/>
</StackPanel>
</Grid>
And this looks like:
There's a lot more you can do here but this shows an approach you can use. Here's a great blog article with more information and examples of this technique:
Silverlight Tutorial Part 7: Using Control Templates to Customize a Control's Look and Feel
I solved the problem by using a visual trick. First of all, my trick required I placed the buttons on an image that would represent the background. The buttons were somewhat transparent so the color of this background came through
The buttons in the middle be simple rectangle canvas classes. While the end buttons had rounded ends.
The middle buttons were in front of the buttons on the end and they overlapped them.
The buttons were transparent and so normally it would not work because you would be able to see the end buttons edges behind the middle buttons. I solved this by putting a rectangle filled with the color of the background image "between" (think in 3D layered depth terms) the end buttons and the rectangle shapped buttons in front of it. The colored rectangles only were positioned in front of the end buttons that were behind the rectangle buttons in front of them.
This was kind of a hack but it worked. When I have time, I will try the solutions suggested here.
Yeah, even simpler, based on Rick'S, as you just want to use the styles to address the rounded corners of your button template border:
<Grid HorizontalAlignment="Center">
<Grid.Resources>
<!-- Default Template -->
<ControlTemplate TargetType="Button">
<Border x:Name="Border" Background="DarkGray" CornerRadius="0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
<!-- Custom Styles for edges -->
<Style x:Key="ButtonLeftStyle" TargetType="Button">
<Setter Property="CornerRadius" Value="10,0,0,10" TargetName="Border"/>
</Style>
<Style x:Key="ButtonRightStyle" TargetType="Button">
<Setter Property="CornerRadius" Value="0,10,10,0" TargetName="Border"/>
</Style>
</Grid.Resources>
<StackPanel Orientation="Horizontal">
<Button Width="75" Height="25" Style="{StaticResource ButtonLeftStyle}" Content="Left"/>
<Rectangle Width="2"/>
<Button Width="75" Height="25" Content="Center"/>
<Rectangle Width="2"/>
<Button Width="75" Height="25" Style="{StaticResource ButtonRightStyle}" Content="Right"/>
</StackPanel>

Categories

Resources