WPF create thumbnail by VisualBrush - wpf

I have a user control for display thumbnail of a window
UserControl XAML :
<Grid x:Name="containerGrid" Margin="0">
<Border Background="White" CornerRadius="5">
<Border.Style>
<Style>
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="True">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="20" Color="White" ShadowDepth="0" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border x:Name="containerBorder" CornerRadius="5" BorderThickness="1" BorderBrush="Black">
<Border.Background>
<VisualBrush x:Name="vb" />
</Border.Background>
</Border>
</Border>
</Grid>
Once a new window been created, I let above user control display thumbnail of window content by VisualBrush
vb.Visual = (Border)Win.Template.FindName("mainBorder", Win);
Everything seems work fine...
Opened Window
Thumbnail
Until the window size changed by user...
Thumbnail
My question is how should I do to let thumbnail width and height always fits my user control (200 X 200) no matter how source(window) size changed??
Many thanks if there is any clue.
SOLVED by set Stretch to Fill and ViewBox to window ActualWidth and ActualHeight
<VisualBrush x:Name="vb" Stretch="Fill" ViewboxUnits="Absolute">
<VisualBrush.Viewbox>
<MultiBinding Converter="{CONV:WidthHeightToRectConverter}">
<Binding Path="Win.ActualWidth" />
<Binding Path="Win.ActualHeight" />
</MultiBinding>
</VisualBrush.Viewbox>
</VisualBrush>

You could try setting stretch on your visualbrush.
<VisualBrush Stretch="Fill"
There are other options on stretch but I think Fill will be the one you want.

Related

Make ErrorTemplate in Style on ComboBox allow tooltip but not mouse click

I use telerik, but that should not mean much for this question. My application is WPF (.Net 4.5).
I have a style, that I use for all comboboxes, which has an errortemplate. The style looks like this:
<Style TargetType="{x:Type telerik:RadComboBox}" x:Key="RadComboBoxStyle" >
<Setter Property="FontFamily" Value="Calibri"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="{StaticResource InputBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource RadComboBoxValidationErrorTemplate}" />
</Style>
My ErrorTemplate looks like this:
<ControlTemplate TargetType="{x:Type Control}" x:Key="RadComboBoxValidationErrorTemplate">
<Grid ToolTipService.IsEnabled="True" ToolTipService.ShowOnDisabled="True"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors), Converter={StaticResource ValidationErrorsConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border BorderBrush="{StaticResource ErrorBrush}" BorderThickness="3" Panel.ZIndex="999" HorizontalAlignment="Right" Margin="0,0,10,0"
Background="Transparent" DockPanel.Dock="right" Width="16" Height="16" CornerRadius="10">
<Rectangle Fill="{StaticResource ErrorBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="3" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="315" />
</Rectangle.RenderTransform>
</Rectangle>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="{StaticResource ErrorBrush}" BorderThickness="1" />
</AdornedElementPlaceholder>
</Grid>
</ControlTemplate>
The entire thing is defined in a global ResourceDictionary.
What this code does, it to put a "forbidden sign" on top of the combobox (Panel.ZIndex="999"), just before the dropdown button (using margins). The Border and the Rectangle makes a sign much like this: Picture.
The combobox itself must be able to hold a tooltip, set locally. So the error-message cannot be shown in the tooltip of the combobox - unless I find a way to combine the two without having to resolve it locally (I want that code in my resourcedictionary).
I also do not want the "forbidden sign" to handle mouse clicks (it gobbles up the click and prevent the combobox from dropping down, if the user clicks on the "forbidden sign".
I tried setting IsHitTestVisible to false on the grid and on the border inside the ErrorTemplate, but that caused the Tooltip to never show.
I also tried setting IsEnabled to false on the same two constrols, but that would not send the mouseclick on to the combobox itself (the list in the combobox does not drop down).
Is there any way to do this directly in the combobox-style or errortemplate? I do not even mind having a code behind - but I really do not want to add code locally where the combobox-style is used.

Blur effect on image as a window background

I have a window in my WPF app with an image as a background. I want that image to be blurred. This is how I do it:
This is my window:
<Window x:Class="kiosk.UI.Views.PageSwitch"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:myProjectName.Converters"
Title="PageSwitch" Height="1024" Width="1280"
Style="{StaticResource WindowStyle}"
WindowStyle="None" ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
</Window>
And here's the style I apply to it:
<Style x:Key="WindowStyle" TargetType="{x:Type Window}">
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="Background">
<Setter.Value>
<VisualBrush>
<VisualBrush.Visual>
<Image Source="Images\myImage.png" >
<Image.Effect>
<BlurEffect Radius="20"/>
</Image.Effect>
</Image>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Style>
This works - the image is blurred. However, there's a thick black border of about 5 mm around the background image. Why is it there and how can I remove it?
Here's what I tried as an alternative:
<VisualBrush Viewbox="0, 0, 1280, 1024" ViewboxUnits="Absolute" >
and the border is removed but the image is stretched a lot. Almost half of the image isn't even shown.
How can I fix this?
Do it like shown in this answer to one of your previous questions. Put the Image control in a Grid with ClipToBounds set to true.
<VisualBrush>
<VisualBrush.Visual>
<Grid ClipToBounds="True">
<Image Source="Images\myImage.png">
<Image.Effect>
<BlurEffect Radius="20"/>
</Image.Effect>
</Image>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
I do a similar thing but just add the image as a element to the LayoutRoot. From this I set the margin to minus out the blur radius to avoid blurring in edges. If you're black border fades in I would suspect this is the issue.
<Image Source="pack://siteoforigin:,,,/image.jpg" Stretch="UniformToFill" Margin="-50">
<Image.Effect>
<BlurEffect Radius="100"/>
</Image.Effect>
</Image>

WPF: Textblock Font size should be even when its size change

I create a custom button in my application as following
<Button x:Class="MyApp.ButtonMainMenuSubCat"
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"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="536">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Grid Name="gridParent">
<Image Name="imgTransparent" Source="/MyApp;component/Resources/LeftCategoryTransparent.png" Stretch="Fill" Margin="0,0,0,0" />
<Image Name="Part_Pressed" Source="/MyApp;component/Resources/PressedMainScreenSubMenu.png" Stretch="Fill" Margin="0,0,0,4" Visibility="Hidden"/>
<Image Name="Focused" Source="/MyApp;component/Resources/MainSubMenuFocus.png" Margin="-3,0,-3,3" Stretch="Fill" Visibility="Hidden" />
<Image Name="Seperator" Source="/MyApp;component/Resources/MainSubMenuSeperator.png" Margin="5,0,5,-1" Stretch="Uniform" VerticalAlignment="Bottom"/>
<TextBlock Name="lblTitle" Text="{TemplateBinding Content}" HorizontalAlignment="Left" Foreground="Gray" FontWeight="{TemplateBinding FontWeight}" FontSize="24" Margin="10" VerticalAlignment="Center" TextWrapping="WrapWithOverflow" TextAlignment="Left"/>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<!--<Setter TargetName="Pressed" Property="Visibility" Value="Visible"/>-->
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="Focused" Property="Visibility" Value="Visible"/>
<Setter TargetName="lblTitle" Property="Foreground" Value="#f8cb1c" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
In my application, I call web service and depending upon the no of items, i create button for each item and finally add these button in StackPanel. Its works well. Stakpanel layout is on left side in screenshot. Now problem is that when I run this application on different machine which have different Screen resolution (like 1920 *1200), then font size seems too small. So i want to adjust font size when container size change. One option is use ViewBox but in case of ViewBox all buttons seems like have different font size and TextWrapping is not possible.
So my actual requirement is that increase/decrease the textblock's font size with TextWrapping and font size must be even for all buttons.
You can use a LayoutTransform based on the screen resolution, you can either scale up your stackpanel or scale up the whole window depending on the resolution.
For the stackpanel:
<StackPanel>
<StackPanel.LayoutTransform>
<ScaleTransform x:Name="ScaleTransform" />
</StackPanel.LayoutTransform>
<Button>A</Button>
<Button>B</Button>
<Button>C</Button>
<Button>D</Button>
</StackPanel>
Then bind the ScaleX and ScaleY to a formula based on the resolution. An example of this:
double scale = System.Windows.SystemParameters.PrimaryScreenHeight / 720;
//using 720p as the base screen height.
this.ScaleTransform.ScaleX = scale;
this.ScaleTransform.ScaleY = scale;
You may want to do this in a ViewModel with some databinding if you are using MVVM.

How to draw shape or lines within a WPF button that size to the control without cause the button to expand forever?

I had a quick Google, and a quick look around StackOverflow, but couldn't find anyone else who'd run into this problem.
I want to create a close button with a little X in it. The close button will do things like fade in and out when you're hovering over the item containing it, change colour when you mouse over, and all the usual WPF loveliness. Bottom line, it doesn't seem like it should be that difficult, but I'm running into one of the weirdest issues ever before I've even got to this stage.
Here's my XAML style for the button:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TabCloseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Content">
<Setter.Value>
<Grid>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="0"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"/>
<Line Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
X1="0"
Y1="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Mode=OneWay}"
X2="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Mode=OneWay}"
Y2="0"/>
</Grid>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And I create my button, just as a test, like this:
<Window x:Class="WpfTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="124" Width="569">
<Grid Background="#2b3c59">
<StackPanel Orientation="Horizontal">
<!-- Other controls removed for clarity -->
<Button Style="{DynamicResource TabCloseButtonStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Padding="2"
Margin="0, 10, 0, 0"
MinWidth="50"
MinHeight="50"></Button>
</StackPanel>
</Grid>
</Window>
And here's where it all goes horribly wrong. When you run the application the button will expand infinitely, one pixel at a time, horizontally, and vertically until it hits the height of the window.
Now I can understand why this is happening: the Lines actually go one unit beyond the width and height of the Grid causing the Grid to expand by one unit, then there's a relayout, the data binding causes the lines to redraw, ad infinitum.
So, to try and deal with this I decided to put a in the grid but then, no matter what I do with HorizontalAlignment and VerticalAlignment, I end up with both the Canvas and the Grid having zero width and height, which means I don't get my cross, which is massively irritating. If I bind to the ActualWidth and ActualHeight properties of the button I just end up with an X that has the top-left corner centred on the centre of the button.
Does anybody have any idea at all what I can do to fix this? I'd be extremely grateful for any pointers - WPF is still a rather new beast to me.
Thanks!
You shouldn't have to resort to bindings just to do layout. As you've seen, the bindings and the layout systems don't work in concert (I think databinding gets priority over layout, but in your case, layout causes another databinding)
You should be able get quite a nice looking, stretchable X with a just a Path:
<Path Data="M0,0 L1,1 M0,1 L1,0" Stretch="Uniform" Stroke="Red" />
If you want it to scale with the button size instead of stretch (scale affects apparent stroke width), then just use a ViewBox
Instead of binding, I'd suggest using the Stretch and Margin or Padding properties, like the following
<Grid Margin="2">
<Line X1="0" Y1="0" Y2="1" X2="1" Stroke="Black" Stretch="Fill" />
<Line Y1="1" X2="1" Stroke="Black" Stretch="Fill" />
</Grid>
Update
So the problem with your example seems to be the min height & width. If you can't just use height & width, I'd suggest something like the following
<Grid MinHeight="{TemplateBinding MinHeight}" MinWidth="{TemplateBinding MinWidth}">
<Line X1="0" Y1="0" Y2="1" X2="1" Stroke="Black" Stretch="Fill" />
<Line Y1="1" X2="1" Stroke="Black" Stretch="Fill" />
</Grid>
Thanks everyone. Rob's solution with the Viewbox turned out to be the answer. The button behaves perfectly, even if I remove the MidWidth and MinHeight attributes from the Button declaration in MainWindow.xaml.
Here's my modified style:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TabCloseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Content">
<Setter.Value>
<Grid>
<Viewbox>
<Path Data="M0,0 L10,10 M0,10 L10,0"
Stretch="Uniform"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground, Mode=OneWay}" />
</Viewbox>
</Grid>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Thanks again for all the suggestions!

Display image in content presenter in button

I have a button with a style that displays an image inside it. I would like to be able to specify the image it uses using the Content property on the button (or some other means).
How can accomplish this without actually nesting an image directly in the button.
<BitmapImage x:Key="closeImage" UriSource="close.png" />
I thought I could maybe specify the image file name like so:
<Button Content="{{StaticResource closeImage}" x:Name="closeButton" Click="closeButton_Click" Style="{DynamicResource WindowToolboxButton}"/>
Style:
<Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackgroundFill}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid" Height="15" Width="15">
<Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF82A3AC" Offset="1"/>
<GradientStop Color="#7FCDD9DC"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Image x:Name="image" Source="close.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm pretty sure I'm missing the problem of your question, but the following code works for me:
<Window.Resources>
<Image x:Key="test" Source="/Images/ChangeCase.png"/>
</Window.Resources>
<!-- Using a Resource for the Content -->
<Button Width="100" Height="20" Content="{StaticResource test}"/>
<!-- Specifying the Content directly -->
<Button Width="100" Height="20">
<Image Source="/Images/ChangeCase.png"/>
</Button>
Plus I spotted an error in your code:
<Button Content="{{StaticResource closeImage}" [...]
should be:
<Button Content="{StaticResource closeImage}" [...]
I don't quite understand what your style is doing. Why do you have the Content Property set to a StaticResource when you want to specify the image via style?
Edit:
Alright, I tried your style and it also works for me.
<Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid" Height="15" Width="15">
<Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF82A3AC" Offset="1"/>
<GradientStop Color="#7FCDD9DC"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Image x:Name="image" Source="/Images/ChangeCase.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Width="100" Height="20" Content="Test" Style="{DynamicResource WindowToolboxButton}"/>
The image is shown. However, I can't see your border due to the opacity-prop being set to 0.
The content that is given directly on the button is overriden by the style.
Maybe there is sth wrong with your image? Did you set its build-property to Resource?
I think the correct way of doing this is
Create a new custom control ImageButton which derives from Button
Create a DP 'ImageSource' of type 'ImageSource' in ImageButton and in its style bind the Source of the Image to this DP.
Then you can use it like <ImageButton ImageSource={StaticResource ...}/>
If you try to add an image defined in a resource to a content control it will only work the first time. The second time you try to add the same image into another content control it will fail with "Specified visual is already a child of another visual..."
Actually, this is really easy. Use the Style you already have and add the following to 'image'
Source="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
Then (as long as you have the image set as Content/Copy if newer) you can set the Content with the desired image's Uri.
<Button Content="/[projectname];component/.../close.png" Style="{StaticResource WindowToolboxButton}" ... />
note: replace '[projectname]' with your project's name and the '...' with path to the image
Replace
<Image x:Name="image" Source="close.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
With
<Image x:Name="image" Source="{Binding Content, RelativeSource={RelativeSource AncestorType=Button}" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
Where your ancestor type will be That button that is called in xaml, and there you can Set Content of that button to point to some image.
Example:
<cc:customButton Content={StaticResource someImage}.../>

Resources