Style border and Title Bar cause NullReferenceException - wpf

I want to change my form border and Title Bar and fount this solution.
So after add this into my XAML (i am using the first solution in the first answer) my application running and i can see the Style changed but after few seconds i can see this exception in the designer:
My application still run and show the new style but this is happening again and again, i try to remove and add changes several times but this error still jump after a while.
Update
this is the code that added to XAML:
<Window x:Class="CSharpWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" >
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="{Binding ActualHeight,ElementName=titlebar}"/>
</WindowChrome.WindowChrome>
<DockPanel LastChildFill="True">
<Border Background="LightBlue" DockPanel.Dock="Top" Height="25" x:Name="titlebar">
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource FindAncestor,AncestorType=Window},FallbackValue=Title}"
Margin="10,0,0,0"
VerticalAlignment="Center">
<TextBlock.Effect>
<DropShadowEffect Color="White" ShadowDepth="3"/>
</TextBlock.Effect>
</TextBlock>
</Border>
<Border BorderBrush="LightGray" BorderThickness="1" Padding="4">
<TextBlock Text="Window content"/>
</Border>
</DockPanel>
</Window>

Related

WPF: Map UserControl properties to its children

The short version of my question is: Can properties of the UserControl be made available to the children of the UserControl without applying to the UserControl at the same time?
The long version: I am trying to create a "ButtonInput" which is a text box with a bitmap button at the right side, inside of the text box's border. This is pretty much how the search boxes look on many web sites (or in Visual Studio), with a magnifying glass at the right side.
The UserControl definition is:
<UserControl x:Class="Test.Controls.ButtonInput"
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"
xmlns:local="clr-namespace:Test.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderBrush="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}"
BorderThickness="0"/>
<Button Width="24" Grid.Column="1" Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon"
Source="{Binding Path=Source, RelativeSource={RelativeSource FindAncestor, AncestorType=local:ButtonInput, AncestorLevel=1}}" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</UserControl>
I place this control in a test Window.
<Window x:Class="Test.TestWindow"
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"
xmlns:local="clr-namespace:Test"
xmlns:controls="clr-namespace:Test.Controls"
mc:Ignorable="d"
Title="TestWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal" Height="380" Width="402">
<Label Content="Password" Width="75" VerticalAlignment="Center"/>
<controls:ButtonInput x:Name="biTest" Source="Resources/img/password.png" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" ButtonClick="ButtonInput_ButtonClick" />
</StackPanel>
</Grid>
</Window>
The problem I have is that I expect to have only what is inside the border colored orange, but instead the orange bleeds outside the border. I traced the problem to the way the Live Visual Tree looks like:
(ButtonInput)
(Border)
(ContentPresenter)
(Grid)
Border (Border)
(Grid)
tbInput (TextBox)
(Button)
The first Border is not in my control definition, but its background is Orange as inherited from the ButtonInput.
I did try an alternative: instead of using child controls for the content of the UserControl, I used a ControlTemplate with the same content. In this case, the executable looked OK (rounded rectangle with black border and orange background, no bleeding outside the border), but the designer in Visual Studio does not show anything. There is literally a blank space where the ButtonInput should be.
So, is there a way to prevent the properties set on the UserControl to apply to the first Border? Background is one example but there are other properties that I want to make use of the same way.
What's happening here is that your "ButtonInput" control isn't actually a button, it's a user control which just so happens to have a button on it. So when you set the background in the <controls:ButtonInput> tag on your main window you're effectively saying "ignore everything this user control says about the color of it's entire background because I'm now overriding it".
There are several ways around this, but the easiest one from the UserControl's perspective is to use the one last weapon in its arsenal: the template. Overriding the template in a control effectively says "I'm no longer going to be displayed the way a control of my type normally is, so all the usual settings won't apply unless I explicitly use them. That's as simple as doing this in your ButtonInput xaml:
<UserControl.Template>
<ControlTemplate>
<!-- all your old xaml code goes here -->
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
<!-- etc -->
</ControlTemplate>
</UserControl.Template>
Which results in the following:
Truth be told, there are few cases in WPF where custom controls are actually needed, and this is almost certainly one of them. WPF is more than capable of supporting functionality like this with styles and templates alone. But this answer should suit your needs in the short term.
EDIT: If you want the control to be visible in the designer then populate it with a regular control and template that instead, it's what you probably should be doing anyway. Now your xaml should look like this:
<UserControl x:Class="WpfTestApp.Controls.ButtonInput"
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"
xmlns:local="clr-namespace:WpfTestApp.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="_this">
<UserControl.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid Background="Transparent">
<Border
Name="Border"
CornerRadius="6"
Padding="4"
Margin="2 2 2 2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="tbInput"
Grid.Column="0"
MaxLines="1"
Background="Transparent"
Text="{Binding ElementName=_this, Path=Text, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="0" Margin="0,-1,0,1"/>
<Button Width="24" Grid.Column="1">
<Button.Template>
<ControlTemplate>
<Image x:Name="imgIcon" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Button x:Name="biTest" Width="300" Height="35" Background="Orange" Foreground="Red" BorderBrush="Black" Template="{StaticResource ButtonTemplate}" />
</UserControl>
You haven't addressed the Text binding in your question, the code above is expecting a dependency property in the UserControl code behind:
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ButtonInput), new PropertyMetadata(String.Empty));
And you now use it like this:
<controls:ButtonInput x:Name="biTest" Width="300" Height="35" Text="{Binding MyText, Mode=TwoWay}" />

WPF Net Framework 3.5 Window Metro Style

I want to make Window with Metro style.
I found the 3 following libraries:
http://elysium.asvishnyakov.com/en/
https://github.com/MahApps/MahApps.Metro
http://mui.codeplex.com/
All are for Net Framework 4+.
Is there anything for 3.5?
I also tried to make it on my own (Didnt finish - still need to design it and add Resize [which I dont know how]) but I dont really like how it's made...:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" x:Class="Windows_Hider.MainWindow"
Title="Windows Hider" Height="350" Width="525" WindowStartupLocation="CenterScreen"
AllowsTransparency="True"
ResizeMode="CanResize" WindowStyle="None" BorderBrush="Black" BorderThickness="1" Icon="windowshider.ico">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image Width="24" Height="24" Source="{Binding Icon, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
<Label VerticalAlignment="Center" FontSize="14" Content="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
</StackPanel>
<Grid MouseDown="Grid_MouseDown" Background="Transparent"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Row="0">
<Button ToolTip="minimize" Background="White">
<Grid Width="30" Height="25">
<TextBlock Text="0" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="3.5,0,0,3" />
</Grid>
</Button>
<Grid Margin="1,0,1,0">
<Button x:Name="Restore" ToolTip="restore" Visibility="Collapsed">
<Grid Width="30" Height="25" UseLayoutRounding="True">
<TextBlock Text="2" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
<Button x:Name="Maximize" ToolTip="maximize">
<Grid Width="31" Height="25">
<TextBlock Text="1" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
</Grid>
<Button x:Name="Close" ToolTip="close">
<Grid Width="30" Height="25">
<TextBlock Text="r" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="0,0,0,1" />
</Grid>
</Button>
</StackPanel>
</Grid>
</Grid>
</Window>
Ok, it took me few days but in the end I managed to do something.
I had to make it by myself because there's no Metro Window for Net Framework 3.5.
I combined some of the references below:
Launch window's System Menu on custom window
http://www.codeproject.com/Articles/107994/Taskbar-with-Window-Maximized-and-WindowState-to-N
http://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/
http://codekong.wordpress.com/2010/11/10/custom-window-style-and-accounting-for-the-taskbar/
http://blog.creativeitp.com/posts-and-articles/c-sharp/simple-methods-to-drag-and-resize-your-c-transparent-wpf-application-with-the-windowstyle-property-set-to-none/
this is the final solution
Known problems / bugs:
1. When resizing the arrow cursor appear instead of the resizing cursor.
2. Designer cant display the custom window.
3. When maximizing, randomly there's blue (the color of the borders) in big area of the screen - for split second
If you can fix any of the problems above it will be even better but I am satisfied with what I achieved.
EDIT:
Updated to allow resize modes (also added sample)
It's relatively easy to do this yourself... all you need to do is copy the Style that you see in the Metro UI, as you call it. To start you off, here is a very simple Style that changes the ControlTemplate of the Button elements to remove their default look:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Of course, you'll want something to happen when the user moves their mouse pointer over the Button and you can do that by adding VisualStateManager.VisualStateGroups to the ControlTemplate. You can find a full example of this in the ControlTemplate Class page on MSDN.
The other controls Metro-style controls can be easily developed by creating simple ControlTemplates in the same way. Basically, you'll just need to remove the default WPF look and for the most part, just replace it with just a ContentPresenter as in the above example, or an ItemsPresenter for collection controls. Luckily the Metro look is very plain and simple, just remember to keep everything spaced out and plain.
To address another point you mad about resizing; you can set the Window.ResizeMode property to CanResizeWithGrip to add the resize grip in the bottom right corner of the Window as is often seen in these applications.

Customize silverlight combobox component

This is (should be) a simple question.
I'd like to create a component like the Facebook notification button (so if you click it a drop down menu appears, and there is the "badge" with the number of unread notification).
I thought to customize the default combo box component (it has the popup and the toggle button), by removing the textfield and the arrow inside the toggle button, and by adding the toggle button inside a canvas so I can absolutely position the badge.
So.. I want to "export" some basic behavior, and the possibility to further stylish the component (like setting a template for the toggle button, for the badge and for each item in the list).
I can't find how can I achieve this.. make a "first" level of style so that people who use my component don't know it is a combo box, but instead they can set my properties (like "ButtonContent", "NotificationItem" and "Badge")…
Thank you.
Francesco
If you don't mind paying for 3rd party components there is always RadControls for Silverlight from Telerik. The suite contains the RadDropDownButton control, which I think should do exactly what you need.
I decided not to style the combo box, but to create a new component (strongly inspired by the combo box)
<UserControl x:Class="silverlight.Components.Notification.View.NotificationSummary"
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"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:conv="clr-namespace:silverlight.ViewModel.Converters"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100">
<StackPanel x:Name="LayoutRoot">
<StackPanel.Resources>
<conv:NumberToVisibilityConverter x:Key="HasUnreadEventsConverter" />
</StackPanel.Resources>
<ToggleButton x:Name="eventButton" Click="notificationButtonClicked">
<ToggleButton.Content>
<StackPanel Orientation="Horizontal">
<Border Padding="5 3" VerticalAlignment="Center" HorizontalAlignment="Left">
<ContentPresenter x:Name="buttonContent" />
</Border>
<Border x:Name="badge" Padding="5 2" CornerRadius="5" Margin="0 0 5 0"
HorizontalAlignment="Right" VerticalAlignment="Center"
BorderThickness="1"
Visibility="{Binding numberOfUnreadEvents, Converter={StaticResource HasUnreadEventsConverter}}">
<Border.BorderBrush>
<SolidColorBrush Color="Black" />
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush Color="Red"/>
</Border.Background>
<TextBlock x:Name="badgeText" Text="{Binding numberOfUnreadEvents}"/>
</Border>
</StackPanel>
</ToggleButton.Content>
</ToggleButton>
<Popup IsOpen="{Binding ElementName=eventButton, Path=IsChecked}" x:Name="notificationPopup">
<Border x:Name="popupBorder" Background="White" CornerRadius="0 0 5 5"
Padding="5">
<Border.Effect>
<DropShadowEffect BlurRadius="5" Direction="315" ShadowDepth="5" Color="Black" />
</Border.Effect>
<ListBox x:Name="eventsList" ItemsSource="{Binding events}"
IsHitTestVisible="False">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter x:Name="itemTemplate" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Popup>
</StackPanel>
</UserControl>

Animation to change user controls

I have a simple custom window (XAML below).
When first loaded, it will add a user control to the grdContainer.Children collection.
User selection/action will cause other user controls to added/removed to the children collection. (one loaded at a time). What I am attempting to do is provide a simple animation as the new control is loaded, something like a 45degree swipe from top left to bottom right.
If anyone can point me in the right direction, I would appreciate it.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WinClientFolder"
x:Name="WinClientFolder"
Title="MainWindow"
Width="450" Height="300" AllowsTransparency="True" WindowStyle="None" ResizeMode="CanResizeWithGrip">
<Window.Background>
<SolidColorBrush />
</Window.Background>
<Grid x:Name="LayoutRoot">
<Border BorderBrush="Black" BorderThickness="2,2,2,0" Margin="18,13,0,0" CornerRadius="10,10,0,0" Background="#FFCCC523" Height="32" VerticalAlignment="Top" HorizontalAlignment="Left" Width="179" Name="FolderTab">
<Grid Height="25" HorizontalAlignment="Left" Name="grdFolderTop" VerticalAlignment="Top" Width="175">
<TextBlock x:Name="txtClientName" Height="34" TextWrapping="NoWrap" Width="Auto" FontSize="18" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,0,0,0"><Run Text="Doe, John Family " /><LineBreak /><Run /></TextBlock>
</Grid>
</Border>
<Border BorderBrush="Black" BorderThickness="2,1,6,2" Margin="0,45,0,0" Background="#FFCCC523" CornerRadius="10,10,0,0" Grid.ColumnSpan="2" Name="FolderBody">
<Grid Height="Auto" Name="grdContainer" Width="Auto" />
</Border>
</Grid>
I asked a somewhat similar question in this post. I can highly recommend this Transitionals framework. It's simple to use and looks great.

How do I apply an effect to a Border but not to its contents in WPF?

I have a WPF application that has a 3rd party data grid with a border around it. I've used the DropShadowEffect to put a shadow behind the border, but this seems to affect performance somewhat (not nearly as much as a BitmapEffect, but still noticeable) and makes the font rendering fuzzy. Is there a way to somehow apply the effect to the border, but not its contents?
I tried setting the Effect on the contents to {x:Null}, but that didn't help.
Here is a sample app I came up with. It puts a shadow behind the border, but it also puts a shadow behind each line of text. I want the shadow behind the border, but not the text.
<Window x:Class="WpfEffectTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Border BorderBrush="Black" BorderThickness="10" CornerRadius="5" Margin="25">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="5" />
</Border.Effect>
<StackPanel>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
</StackPanel>
</Border>
</Grid>
</Window>
The link from gcores had the answer, which is to put the border and its content together in the same grid so the content overlays the border.
<Window x:Class="WpfEffectTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Border BorderBrush="Black" BorderThickness="10" CornerRadius="5" Margin="25">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="5" />
</Border.Effect>
</Border>
<StackPanel Margin="35">
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
<TextBlock>This is some text</TextBlock>
</StackPanel>
</Grid>
</Window>
One simple (hack?) solution is to do
<StackPanel Background="White">
This should solve the text with drop-shadow problem (Not sure about the performance problem though).
The problem is that WPF applies effects to the set element and all it's children in the visual tree.
This link explains it better:
DropShadowEffect performance issue
Try the following block (or similar) for all TextBlocks:
<TextBlock>
<TextBlock.Effect>
<DropShadowEffect BlurRadius="30" ShadowDepth="5" Color="White"/>
</TextBlock.Effect>
</TextBlock>

Resources