How to set a specific image as a Fluent Design AcrylicBackgroundSource - c#

How to set an specific image as a Fluent Design AcrylicBackgroundSource to use in PIP mode (CompactOverlay) like Groove Music PIP feature

The picture-in-picture in UWP applications is strictly a compressed version of the current page. You may see the difference between Groove in normal view and compression attempts, but the principle of implementing Acrylic Brush is the same.
Considering the question you asked, here is a possible way to achieve image blur:
XAML
<Page
...>
<Page.Resources>
<ImageBrush ImageSource="{Here is your image url}" x:Key="ImageBackground" Stretch="UniformToFill"/>
<AcrylicBrush x:Key="MaskBackground" BackgroundSource="Backdrop" TintColor="Black" TintOpacity="0.3" FallbackColor="Black"/>
</Page.Resources>
<Grid Background="{StaticResource ImageBackground}" Name="ImageLayer">
<Grid Background="{StaticResource MaskBackground}" Name="MaskLayer"/>
<Grid>
<!-- Here is other controls, like play button etc. -->
</Grid>
</Grid>
</Page>
Usage
This is done using a layer approach. Set the background to a picture, then add a mask layer.
If you want to change the background image dynamically, you can remove the static reference and change it with C# code.
var backgroundBrush = new ImageBrush();
backgroundBrush.ImageSource = new BitmapImage(new Uri("Here is your image url"));
ImageLayer.Background = backgroundBrush;
Best regards.

Related

Using vector graphics from Inkscape in WPF in a resource effective matter

This question aims to be a best practice on how to use images created with Inkscape and saved as XAML.
There are many articles on the internet but not many of them show the pro and cons of each solution. Example 1, Example 2
When you create an image with Inkscape and save as XAML you'll only have a Viewbox inside an XAML.
<?xml version="1.0" encoding="UTF-8"?>
<!--This file is NOT compatible with Silverlight-->
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="svg8" Width="210" Height="297">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas.Resources/>
<!--Unknown tag: sodipodi:namedview-->
<!--Unknown tag: metadata-->
<Canvas Name="layer1">
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="55.184521" Canvas.Top="113.30357" Width="33.261906" Height="33.261906" Name="rect4485" Fill="#FFFFFFFF" StrokeThickness="5.29166651" Stroke="#FF000000" StrokeMiterLimit="4"/>
</Canvas>
</Canvas>
</Viewbox>
To use this file I'd normally have to wrap it in a ResourceDictionary. This is annoying because I cannot edit the file in Inkscape anymore without having to remove the ResourceDictionary before.
The image will be shown multiple times, for example in a ListViewItem or any other element that has an ItemsSource.
Is there a way to have only one ResourceDictionary where I can import all of these XAML files?
Let's assume I have wrapped it in a ResourceDictionary and given the Viewbox a x:Key="SquareIcon" value.
What is most resource effective way of showing this element?
Should I use a ContentPresenter and set its Content property and set the Canvas x:Shared="false"?
Is it more effective to use a Label (or some other control)?
Maybe remove the Viewbox and always use the Canvas in a Viewbox in my own view?
Should I wrap the Viewbox in a ControlTemplate and use it in ContentPresenter Template property? This way I don't need to use the x:Shared attribute on Canvas.
When saving an asset from Inkscape as xaml, you can copy it to Blend and then convert it to Path. Then you have a vector representation of that asset, which you can easily incorporate as a style.
You can read about converting to path here
Keep in mind that you can also combine several elements and then convert them. Basically, any kind of image that is in one color can be converted to a single path.
As far as best practice goes, I like to keep all of my Path/Image/Icon related styles in a single ResourceDictionary and then reference it globally in App.xaml file.
I think you can create it manually by reading all your files. Steps are next:
1) You have your resources in your project with xaml or svg
2) Create your markup extension which will provide a value of Geometry by a path of your embedded resource file with an icon. (it should parse and provide value)
3) Create a custom control IconControl for displaying icons with dependency property IconPath (String) and bind it in your template by template binding
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:IconControl">
<Viewbox ><!--Could be other container -->
<Path Data="{TemplateBinding IconPath}"
Fill="{StaticResource DefaultBrush}" />
</Viewbox>
</ControlTemplate>
Viewbox isnt so good, because it applies transformations to content. So you should use simpliest container to achive good performance.
4)Use your control in markup
<IconControl IconPath={locl:IconSvgMarkupExtension PathToYourEmbededResourceHere}/>
I wrote it without VS, from memory, so there could be some mistakes.
Should I wrap the Viewbox in a ControlTemplate and use it in
ContentPresenter Template property? This way I don't need to use the
x:Shared attribute on Canvas.
It is also a possible case, a few years ago I've used the same approach without so each of my icons was ContentControl with different Template for it depending on Icon.
I had a similar issue : Inkscape svg saved as XAML does not work for me.
After some long search I found this very quick but useful video on Youtube :
https://www.youtube.com/watch?v=otEV-skBqyI
combine with the converter available on Github here : https://github.com/BerndK/SvgToXaml
used to convert svg to a DrawingImage ressource
(available thanks BerndK)
It solves my issue !
Just then have to save the ressource file as .xaml in my project
content of Xaml file
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingImage x:Key="MyVectorImageName">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V297 H210 V0 H0 Z">
.... //this part is the DrawingImage content Iget in converter and I copied pasted
</ResourceDictionary>
And to use it :
<Grid x:Name="gridImage" Margin="0,62.8,0,0" >
<!-- Add vector ressource and display it -->
<Grid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="images/MyVectorImageName.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Grid.Resources>
<Image x:Name="imgName" Source="{StaticResource MyVectorImageName}"/>
</Grid>
Note : I added it as a local ressouce not a global one (but i is possible too)

How to change color of all shapes in window with C# and XAML?

Brief
I am trying to programmatically change the colour of specific elements at runtime. The project currently uses Telerik and I am able to change the theme at runtime: This works as expected with no issues. I can't, however, figure out how to change the fill or stroke colour at runtime of custom shape elements in XAML.
Within my project I have a ResourceDictionary file named _Icons.xaml that contains vector shapes to use as the content for other controls (such as buttons).
Code
App.xaml.cs
I am using the following code to change the theme's marker colours at runtime.
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
_Icons.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyNamespace">
<ControlTemplate x:Key="Box">
<Viewbox>
<Rectangle Width="357" Height="357" Fill="#000000"/>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="BoxOutline">
<Viewbox>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
</Viewbox>
</ControlTemplate>
</ResourceDictionary>
MainWindow.xaml
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource Box}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">Box</TextBlock>
</StackPanel>
</telerik:RadButton>
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource BoxOutline}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">BoxOutline</TextBlock>
</StackPanel>
</telerik:RadButton>
Question
In _Icons.xaml I have the following lines:
<Rectangle Width="357" Height="357" Fill="#000000"/>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
Given the following line in App.xaml.cs:
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
How can I either...
Programmatically change the values of Fill and/or Stroke (an element that only has Fill set should only change the Fill value and not add a Stroke attribute) from the App.xaml.cs file? Or ...
Bind the values in XAML for Fill or Stroke to receive the value given by my App.xaml.cs file?
Thank you for taking the time to read my question. Any help regarding this is greatly appreciated.
First i advise you to eject that controls off your resource sheet so you can actually control them properly.
When you do that, go the code behind your control and just use dependency property of type 'Color' of the 'SolidColorBrush' that is used by the background and then bind it by element name, you gotta build the project at least once before attempting to bind.
Here is how you write a dependency property
hint: in VS write 'propdp' and hit tab twice to bring up a template, but you can use mine for now.
public Color _color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("_color", typeof(Color), typeof(Fileentity), null);
after you build once go to the xalm and put this inside your rectangle:
<Grid.Background>
<SolidColorBrush Color="{Binding
_color,ElementName=YourControlName" />
</Grid.Background>
if you do it right you will be able to access this property when inserting the control on you Page like
<local:YourcontrolName _color="{x:Bind MyColorProperty }"/>
where 'MyColorProperty' is a property that implements INotifyPropertyChanged.
An alternative way is to use a datacontext directly on the usercontrol and just bind your color to one of its properties like:
public YourControl(){
this.InitializeComponent();
this.DataContext = new MyClassDataContext();
var myContext= (MyClassDataContext)this.DataContext;
_color=MyContext.MyColorProperty;}
Where MyClassDataContext is any given class that contains a Color property(MyColorProperty) of your choosing.
You need a Dependency property here as well that binds to your Controls xalm like i showed before.
I know all this is might too hard to grasp at once, thats cause it requires basic knowledge of MvvM.

How to set the background of a WPF grid to an image in local folder?

I'm developing a small WPF application and I'm trying to change the background of a grid to an image the user chooses (stored somewhere on the computer on a different location from the app). Is it possible without having the images included on the project and marked as a Resource? How?
Assuming you Grid name is grid, then xaml would be:
<Grid Name="grid">
...
</Grid>
then to set an image programatically to grid, you should use the following code snippet:
string imgPath=#"E:\anImage.jpg";
grid.Background= new ImageBrush { ImageSource = new BitmapImage(new Uri(imgPath,
UriKind.RelativeOrAbsolute)) };
you just need to set the image's source URI to the image location
<Image Source="<<URI of image>>"/>
<ImageBrush ImageSource="<<URI of image>>"/>
or you can do the same via binding to allow it to be customised
<Image Source="{Binding Data}"/>
in this example Data is a byte[] stored in the model, but could be anything that converts to an image source
This works for me :
1) Add image in solution (Add => Existing Item)
2)<Grid>
<Grid.Background>
<ImageBrush ImageSource="/App;component/Chrysanthemum.jpg">
</ImageBrush>
</Grid.Background>
</Grid>

Reload ThemeResources when resuming the App

I've defined a simple TextBlock in my MainPage:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Example" FontSize="30" Foreground="{StaticResource PhoneForegroundBrush}"/>
</Grid>
As you can see I'm using StaticREsource PhoneForegroundBrush. It works quite nice:
but there is a problem when the User changes Phone Theme (Light/Dark) while the App is Suspended. Then when the User goes back to the App, Resources are not being updated so my Textblock looks like this:
When I close the app and start it again, everything is ok:
Is there a method that I can put into Resuming event, that would update the resources so that my UIElements are visible?
Use a ThemeResource, it retrieves value depending on the currently active theme.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Example" FontSize="30" Foreground="{ThemeResource PhoneForegroundBrush}"/>
</Grid>
ThemeResource XAML markup extension provides a value for any XAML
attribute by evaluating a reference to a resource, with additional
system logic that retrieves different resources depending on the
currently active theme. Similar to StaticResource, resources are
defined in a ResourceDictionary, and a ThemeResource usage references
the key of that resource in the ResourceDictionary.
ThemeResource markup extension

Choosing Layout Control for WPF Item

I am trying to learn WPF.. Although, Im having trouble with the layouts and which one to choose. I dont want to use canvas because the whole point is the get the hang of WPF..
I have decided to transfer one of my simple programs (in Windows Forms) to WPF..
I have attached the picture of the simple, 1 page form.. Can someone suggest how I could replicate this in WPF?
Form layouts are an interesting predicament. They usually involve a LOT of boilerplate, there's many techniques for removing boilerplate code in form layouts but they're fairly advanced WPF Concepts.
The Simplest Solution for you is going to be a StackPanel for laying out your sections and putting a Grid inside your GroupBox controls.
The Grid can be setup with 4 colunms:
Col 1 Label
Col 1 Body
Col 2 Label
Col 2 Body
With a global style in the resources of your stack panel you can define default visual behaviour so the items dont end up touching:
<Style TargetType="TextBox">
<Setter Property="Margin" "0,0,5,5" />
</Style>
The Above Style will put a 5px margin on the right & bottom of all TextBox controls under it in the visual tree.
This is the absolute simplest (read: straight forward) approach to making this ui in WPF. It is by no means the best, or the most maintainable, but it should be doable in about 10 minutes max.
There are other methods out there for emulating a form layout with WPF like this one or by using other combinations of basic layout components.
For example:
<StackPanel>
<!-- Vertical Stack Panel, Stacks Elements on top of each other -->
<StackPanel Orientation="Horizontal">
<!-- Horizontal Stack Panel, Stacks Elements left to right -->
<Label Width="100">This Label is 100units Wide</Label>
<TextBox />
</StackPanel>
</StackPanel>
Different approaches have different drawbacks, some are flex width, some are not, some play nicely with colunms, some don't. I'd suggest experimenting with the many subclasses of Panel to see what they all do, or you can even roll your own.
Using Grid as container, TextBlock al read-only text, Textbox as editable text and Button.
With these elements and using (for example) XAML:
<Window
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="MainWindow"
Width="640" Height="480" Background="White">
<Grid>
<TextBlock HorizontalAlignment="Left" Height="20" Margin="34,30,0,0"
TextWrapping="Wrap" Text="Connection String" VerticalAlignment="Top"
Width="107" Foreground="Black"/>
<TextBox HorizontalAlignment="Left" Height="18" Margin="170,32,0,0"
TextWrapping="Wrap" VerticalAlignment="Top" Width="379"/>
<Button Content="Save" HorizontalAlignment="Left" Height="26"
Margin="529,387,0,0" VerticalAlignment="Top" Width="69"/>
</Grid>
you can put all objects in your Window. But if you prefer you can add the elements programmatically. This is the result:
Here an introduction to WPF layout.

Categories