Customize silverlight combobox component - silverlight

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>

Related

WPF Add menu in line with title bar

I've been searching for ways to get a menu in line with the title bar like the below image. It has the logo on the far left that acts as a menu item and the rest of the text menu items following after it. I've only found ways to get a menu that looks like the second image, where the menu is below the title bar. How can I put the menu in line with the title bar in XAML?
First put a Grid with two rows in the form.
Put a Menu in the first row.
In the second row is the content of the form.
Place a DockPanel in the first row and a Menu on the left with
DockPanel.Dock = "Left"
Place a Border on the set side to place the required Buttons with DockPanel.Dock="Right"
The following code implements the above steps
<Window x:Class="For_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:For_Test"
mc:Ignorable="d"
Title="CanvasWindow" Height="450" Width="800" WindowStyle="None" BorderBrush="Gray" BorderThickness="2">
<Window.Resources>
<Style TargetType="{x:Type local:TestWindow}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CornerRadius="0" GlassFrameThickness="0" ResizeBorderThickness="0" CaptionHeight="0"></WindowChrome>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<DockPanel.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FF454545" Offset="0.528" />
<GradientStop Color="#FF555555" Offset="0.01" />
<GradientStop Color="#FF454545" Offset="1" />
<GradientStop Color="#FF666666" Offset="1" />
</LinearGradientBrush>
</DockPanel.Background>
<Menu Width="Auto" Name="menu1" VerticalAlignment="Top" DockPanel.Dock="Left" Foreground="White" Background="Transparent" Padding="5 5 5 5">
<MenuItem Header="File" IsCheckable="true" FontSize="12">
</MenuItem>
<MenuItem Header="Settings" IsCheckable="true" Foreground="White" FontSize="12">
</MenuItem>
<MenuItem Header="Security" IsCheckable="true" Foreground="White" FontSize="12">
</MenuItem>
<MenuItem Header="Database" IsCheckable="true" Foreground="White" FontSize="12">
</MenuItem>
</Menu>
<Border HorizontalAlignment="Right" DockPanel.Dock="Right" Padding="5 5 5 5">
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Content="Colse" Width="50" Foreground="White" Background="Transparent" BorderBrush="#FFDDDDDD" BorderThickness="1"></Button>
<Button Content="Minimize" Width="60" Foreground="White" Background="Transparent" BorderBrush="#FFDDDDDD" BorderThickness="1" Margin="5 0 0 0"></Button>
</StackPanel>
</Border>
</DockPanel>
<StackPanel Grid.Row="1" Background="Blue">
<TextBlock Text="Content"></TextBlock>
</StackPanel>
</Grid>
</Window>
In TestWindow.cs i put the code to move the form by dragging it on the header and closing the application.
public partial class TestWindow: Window
{
public TestWindow()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
private void DockPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
}
Note: Setting WindowStyle="None" removes the Windows header and adds an extra margin to the window, which is cleared by setting the following code.
<Window.Resources>
<Style TargetType="{x:Type local:TestWindow}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CornerRadius="0" GlassFrameThickness="0" ResizeBorderThickness="0" CaptionHeight="0"></WindowChrome>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
In TargetType="{x: Type local:TestWindow}" enter your window name instead of TestWindow in the code above.
demo :
Unfortunately, there is no easy way to add elements to the default title bar. The way to go is to implement your own title bar which requires you to implement all the features yourslef that would normally come with the default title bar (at least all the features you whant).
This blog article provides a pretty good solution to create a W10 like title bar which can be enhanced by custom elements. The solution is quite lengthy and it would not be apropriate to share the whole blog here. In case the link might break in the future, here is an application where the blogs author used the described implementation.

Style border and Title Bar cause NullReferenceException

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>

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.

Why is the WPF Border’s "Border" visible in design mode, but not in the application?

The designer shows a black border around the red background, but the actual application only shows the red background. What gives? How to force the black border to be visible?
Here’s the XAML for this window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinWidth="400" MinHeight="300"
TextOptions.TextFormattingMode="Display">
<DockPanel Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<Button DockPanel.Dock="Top" Content="A button"
Padding="8,2" Margin="8" />
<Border DockPanel.Dock="Top" Height="10" BorderBrush="Black"
SnapsToDevicePixels="True" Background="Red" />
<Button DockPanel.Dock="Top" Content="A button"
Padding="8,2" Margin="8" />
</DockPanel>
</Window>
My guess is that the default thickness of the border during runtime is 0 - possibly because of an inherited style in the application resource dictionary. Default styles inherited from a global resource dictionary often don't show up during design time.
Try explicitly setting the BorderThickness="1"
I'm not sure why the border is showing up in Design Mode but you can make it show up in the application by adding an explicit thickness
<Border DockPanel.Dock="Top" Height="10" BorderBrush="Black"
SnapsToDevicePixels="True" Background="Red" BorderThickness="1" />
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource Gray4}"/>
</Border.BorderBrush>
Replace value of property "Color", using hex:
<Border.BorderBrush>
<SolidColorBrush Color="#FFD33B3B"/>
</Border.BorderBrush>

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