So in my main app ResourceDictionary I have a style that starts with
<Style TargetType="{x:Type TabItem}" x:Key="{x:Type TabItem}">
Now what I'm doing is overriding the TabControl to make a custom control(without ANY xaml). The problem is at this point it doesn't inherit the custom TabControl template.
So what I'm wondering, is how can I programatically bind to the 'x:Key' of the template, considering it's bound to a specific control without having my control have a xaml file.
Some places online say to do this
this.Style = (Style)FindResource("TabItem");
But it doesn't seem to work in my situation. The 'style' is in a separate file, and imported into my App.Xaml resource dictionary...so it overrides all TabItems properly, but not the one I overrode.
Here is my App.xaml
<Application x:Class="Octgn.OctgnApp" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/Themes/Full/ExpressionDark.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
And the item(slightly truncated cause it's large) from the ExpressionDark.xaml
<Style d:IsControlPart="True" TargetType="{x:Type TabItem}" x:Key="{x:Type TabItem}">
<Setter Property="Foreground" Value="{DynamicResource TextBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="grid" Margin="2,1,2,3">
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Grid.LayoutTransform>
<Border x:Name="border" BorderBrush="{x:Null}" CornerRadius="2,2,2,2" Opacity="0.5">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,0.976" StartPoint="0.5,0.039">
<GradientStop Color="#7F595959" Offset="0" />
<GradientStop Color="#19FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="SelectedBorder" BorderBrush="{x:Null}" CornerRadius="2,2,2,2" Opacity="0" Background="{DynamicResource SelectedBackgroundBrush}"/>
<Border x:Name="HoverBorder" BorderBrush="{x:Null}" CornerRadius="2,2,2,2" Opacity="0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,0.976" StartPoint="0.5,0.039">
<GradientStop Color="#7F595959" Offset="0" />
<GradientStop Color="#19FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Grid>
<ContentPresenter x:Name="ContentSite" RecognizesAccessKey="True" ContentSource="Header" d:LayoutOverrides="Width, Height" HorizontalAlignment="Center" Margin="6,1,6,1" VerticalAlignment="Center" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This style auto applies to a TabItem, but I'm trying to apply it to my override of TabItem.
Here's the code for that
/// <summary>
/// The chat bar item.
/// </summary>
public class ChatBarItem : TabItem
{
/// <summary>
/// Sets the Chat Room
/// </summary>
private readonly NewChatRoom room;
/// <summary>
/// Initializes static members of the <see cref="ChatBarItem"/> class.
/// </summary>
static ChatBarItem()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(ChatBarItem), new FrameworkPropertyMetadata(typeof(TabItem)));
}
/// <summary>
/// Initializes a new instance of the <see cref="ChatBarItem"/> class.
/// </summary>
/// <param name="chatRoom">
/// The chat Room.
/// </param>
public ChatBarItem(NewChatRoom chatRoom)
{
this.room = chatRoom;
this.ConstructControl();
}
/// <summary>
/// Initializes a new instance of the <see cref="ChatBarItem"/> class.
/// </summary>
public ChatBarItem()
{
this.room = null;
this.ConstructControl();
}
/// <summary>
/// Constructs this control
/// </summary>
private void ConstructControl()
{
//this.Background = Brushes.Transparent;
//this.BorderThickness = new Thickness(0);
//this.Style = (Style)FindResource("TabItem");
// this is where I want to set the style of this control
// Main content object
var mainBorder = new Border { Margin = new Thickness(5) };
// Main content grid
var g = new Grid();
g.ColumnDefinitions.Add(new ColumnDefinition());
g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(16) });
// Create item label
var label = new TextBlock() { VerticalAlignment = VerticalAlignment.Center };
if (this.IsInDesignMode() || this.room == null)
{
label.Inlines.Add(new Run("test"));
}
else
{
label.Inlines.Add(new Run(this.room.GroupUser.User.User));
}
// Create close button
var borderClose = new Border { Width = 16, Height = 16 };
var imageClose = new Image()
{
Source = new BitmapImage(new Uri("pack://application:,,,/Octgn;component/Resources/close.png")),
Stretch = Stretch.Uniform
};
// --Add items to items
// Add close image to closeBorder
borderClose.Child = imageClose;
// Add Close 'button' to grid
g.Children.Add(borderClose);
Grid.SetColumn(borderClose, 1);
// Add label to main grid
g.Children.Add(label);
// Add main grid to main border
mainBorder.Child = g;
// Add main grid to this
this.Header = mainBorder;
}
}
If I had a xaml for the TabItem I could easly just go Style="{DynamicResource {x:Type TabItem}}"(or something similar), but I'm doing it all programatically.
You already tried:
<Style TargetType="{x:Type TabControl}" BasedOn="{StaticResource {x:Type TabControl}}">
</Style>
By the way, you need not define an x:Key, if you want the style to be applied to all TabControl and if you want it to work for your entire application, set the style in App.xaml
Edit: I still do not understand exactly what you want to do. (If you can, edit your question again).
But you can try to set the style manually by:
Style customStyle = (Style)Application.Current.FindResource("StyleKey");
As mentioned,
static MyCustomTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomTabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
}
But this will only work if:
1) The style your control is in the file: Themes\Generic.xaml
2) The file "Generic.xaml" has the property "BuildAction" with value = Page.
3) AssemblyInfo.cs contains:
[assembly: ThemeInfo (
ResourceDictionaryLocation.None,
ResourceDictionaryLocation.SourceAssembly
)]
What about this in your static constructor of your dervied tab Control
static MyCustomTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomTabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
}
Ok so after some digging around, and the help of the other two answers here, I was able to figure this out. Instead of doing a string for the FindResource, it would seem that the resource dictionary, is in fact a diciontary with an object key. So...
this.Style = (Style)Application.Current.FindResource(typeof(TabItem));
And that did it for me.
Thanks again to the other two answers as well.
Related
I've been fighting this xaml for hours now. It should be very simple. I have a general WindowDialog (Billing.WindowDialog) with a ContentPresenter displaying a UserControl (NovaLibraries.Views.DxLibraryView). The UserControl itself has a ListView (in row=0) and followed by other controls in the below rows.
The good news: When the WindowDialog presents the UserControl, it correctly displays the UserControl to the size of the display screen and minimizing the
WindowDialog (or resizing it) does correctly change the size of the UserControl and shrinks the ListView correctly.
The problem (the bad news): When a filter is placed on the list contained within the ListView, so that the ListView has fewer items, it shrinks due to lack of items and the entire UserControl shrinks. This becomes very distracting when the list is large with a hundred items then shrinks to 4 items as this causes the entire UserControl to shrink in size.
What I Need: I need the UserControl initially to be maximized to the size of the screen with the ListView using all available space. The UserControl is to shrink (or enlarge) according to its parent WindowDialog--not according to the contents of the ListView.
Thanks for reading all this. Any help is most appreciated.
The WindowDialog:
<Window x:Class="Billing.WindowDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="SingleBorderWindow"
WindowStartupLocation="CenterOwner"
Title="{Binding DialogTitle}">
<ContentPresenter x:Name="DialogPresenter" Content="{Binding .}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Window>
using System.Windows;
using Client;
namespace Billing
{
/// <summary>
/// Interaction logic for WindowDialog.xaml
/// </summary>
public partial class WindowDialog : Window, IWindowDialog
{
public WindowDialog()
{
InitializeComponent();
}
}
}
C# code to dispaly the UserControl:
var dialog = new WindowDialog
{
Title = "ICD Library",
ShowInTaskbar = false,
Topmost = false
};
DialogService dialogService = new DialogService();
dialogService.ShowDialog(
dialog,
new DxLibraryViewModel(null, null)
);
// Opens a window and returns only when the newly opened window is closed.
public void ShowDialog<TDialogViewModel>(IWindowDialog windowdialog, TDialogViewModel viewModel,
Action<TDialogViewModel> onDialogClose, bool sizetocontent = false)
{
// Assign the viewmodel as the DataContext of the WindowDialog.xaml
windowdialog.DataContext = viewModel;
// Set window size.
SizeToContent SizeToContent = SizeToContent.Manual;
WindowState WindowState = WindowState.Maximized;
if (sizetocontent)
{
SizeToContent = SizeToContent.WidthAndHeight;
WindowState = WindowState.Normal;
}
// The WindowDialog is the mainwindow.
(windowdialog as WindowDialog).WindowState = WindowState;
(windowdialog as WindowDialog).SizeToContent = SizeToContent;
// Open MainWindow in modal fashion (Returns only when the newly opened window is closed).
// Implicict DataTemplate in App.XAML used to display usercontrol.
windowdialog.ShowDialog();
}
public void ShowDialog<TDialogViewModel>(IWindowDialog mainwindow, TDialogViewModel viewModel, bool sizetocontent = false)
{
ShowDialog(mainwindow, viewModel, null, sizetocontent);
}
The UserControl is:
<UserControl x:Class="NovaLibraries.Views.DxLibraryView"
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:c="clr-namespace:NovaLibraries.Converters"
mc:Ignorable="d"
BorderBrush="Black" BorderThickness="2" Background="Beige" >
<UserControl.Resources>
<!--Display a checkmark without the surrounding box as an image-->
<c:CheckMarkConverter x:Key="mycheckmark" />
<Style x:Key="ItemContStyle" TargetType="{x:Type ListViewItem}">
<Style.Resources>
<!--ORANGE-->
<LinearGradientBrush x:Key="OrangeBrush" StartPoint="0.5,0" EndPoint="0.5,1" >
<GradientStop Offset="0.1" Color="#AA00CC00" />
<GradientStop Offset="0.8" Color="Orange" />
</LinearGradientBrush>
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=chronic}" Value="true">
<Setter Property="Background" Value="{StaticResource OrangeBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*" />
<RowDefinition Height="275" />
</Grid.RowDefinitions>
<ListView Grid.Row="0"
ItemContainerStyle="{StaticResource ItemContStyle}"
ItemsSource="{Binding DxView.View}"
SelectedItem="{Binding SelectedItem}"
IsEnabled="{Binding CanSelect}"
Width="781" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=rank}" Header="Rank" Width="50" />
<GridViewColumn DisplayMemberBinding="{Binding Path=code}" Header="ICD-9" Width="50" />
<GridViewColumn DisplayMemberBinding="{Binding Path=cdesc}" Header="Diagnosis" Width="550" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
By removing
HorizontalAlignment="Center" VerticalAlignment="Center"
from the ContentPresenter, the ListView and its parent UserControl behave as expected.
I'm creating a custom control library and I started with a simple round edge separator but there is something I can't seem to be able to do.
I have a CornerRadius dependency property and I would like CornerRadius to be equal to Height / 2 if CornerRadius is not defined or take the user value otherwise. I initialize the height in the constructor so that it's never null
I know how to define a default value for the dependency property, but I don't know how, or if it is possible to set the CornerRadius value according to the Height of the control. I've searched a while in vain so far.
Xaml file
<!-- Rounded Separator -->
<Style TargetType="{x:Type local:RoundedSeparator}" BasedOn="{StaticResource {x:Type Separator}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:RoundedSeparator}">
<!-- Mask for round edges -->
<Grid Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Border Name="PART_TitleBarMask"
CornerRadius="{TemplateBinding CornerRadius}"
Background="White"/>
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=PART_TitleBarMask}"/>
</Grid.OpacityMask>
<!-- Separator -->
<Rectangle Fill="{TemplateBinding Background}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
.cs file
public class RoundedSeparator : Separator
{
static RoundedSeparator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(RoundedSeparator), new FrameworkPropertyMetadata(typeof(RoundedSeparator)));
}
public RoundedSeparator()
{
this.Height = 100;
this.Background = Brushes.Black;
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius",
typeof(CornerRadius),
typeof(RoundedSeparator),
new UIPropertyMetadata(default(CornerRadius));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
}
try :
static RoundedSeparator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(RoundedSeparator), new FrameworkPropertyMetadata(typeof(RoundedSeparator)));
RoundedSeparator.HeightProperty.OverrideMetadata
(typeof(RoundedSeparator), new FrameworkPropertyMetadata(new PropertyChangedCallback(HeightPropertyChanged)));
}
private static void HeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Do what you will .... :)
}
I want to implement this in Silverlight.
Combobox with an inline filter in the popup
http://gregandora.wordpress.com/2012/01/25/filtering-items-in-a-wpf-combobox/
Unfortunately it's for WPF and XAML is not compatible. It's very hard to convert it or understand how to change the control template of the combobox.
Any idea?
Here's a demo of the solution: https://dl.dropbox.com/u/8424800/StackOverflowSl.html (see ComboBox Filter)
I took the default Silverlight ComboBox template and added a "FilterTextBox" to the Popup section. I couldn't post the whole xaml as it exceeded StackOverflow's limit. The full sources are here as a GitHub Gist. I've left in the important parts. Next, the event handlers on the TextBox needs to be hooked up.
<Style TargetType="ComboBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder"
Height="Auto"
HorizontalAlignment="Stretch"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#FFFFFFFF" />
<GradientStop Offset="1" Color="#FFFEFEFE" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<TextBox x:Name="FilterTextBox"
Height="22"
VerticalAlignment="Top" />
<ScrollViewer x:Name="ScrollViewer"
Margin="0,25,0,0"
BorderThickness="0"
Padding="1">
<ItemsPresenter />
</ScrollViewer>
</Grid>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Wiring up the TextBox
public Q12513294()
{
// Required to initialize variables
InitializeComponent();
InitializeMyCombo(
Enumerable.Range(1, 99).Select(x => "Beer " + x.ToString() + " on the wall"),
(object item, string filter) => (item as String).Contains(filter)
);
}
private void InitializeMyCombo(IEnumerable items, Func<object, string, bool> filter)
{
MyComboBox.Loaded += (s, e) =>
{
// PagedCollectionView implements a filterable collection
PagedCollectionView list = new PagedCollectionView(items);
MyComboBox.ItemsSource = list;
// Set the filter based on the contents of the textbox
TextBox filterTextBox = MyComboBox.GetTemplateChild<TextBox>("FilterTextBox");
list.Filter = new Predicate<object>(
item => filter(item, filterTextBox.Text)
);
// Refresh the filter each time
filterTextBox.TextChanged += (s2, e2) =>
{
list.Refresh();
filterTextBox.Focus();
};
};
}
public static class Helper
{
public static T GetTemplateChild<T>(this DependencyObject parent, string partName)
{
return (T)(VisualTreeHelper.GetChild(parent, 0) as Panel).FindName(partName);
}
}
I've got a ribbon bar in my silverlight app and on one of the icons I would like for there to be a badge icon showing the number of items in the view that the icon activates.
Picture the Mail icon in OS X showing the number of unread messages or the notifications counter on an IOS app icon.
I don't know much about xaml styles, but it seems to me I could duplicate the default style for the ribbon bar button, then add to it with some sort of red circle, and a white text that took in its value from a new property on the ribbon bar button somehow so I would be able to bind to it.
Does anyone have an example of something like this I can start from?
Thanks Shawn for the answer. This is what I ended up doing:
In the xaml:
<telerikRibbonBar:RadRibbonRadioButton
Text="Expired Active Call Factors"
Size="Large"
LargeImage="/CallFactorDatabase.UI;component/Images/Ribbon/Large/ExpiredActiveView.png"
Command="{Binding ActivateViewCommand}"
CommandParameter="ExpiredActiveView">
<Grid>
<Grid.Resources>
<converters:BooleanToVisibilityConverter x:Key="visibleWhenTrueConverter" VisibilityWhenTrue="Visible" VisibilityWhenFalse="Collapsed" />
</Grid.Resources>
<Grid Width="27" Height="27" Visibility="{Binding ExpiredActiveCallFactors, Converter={StaticResource visibleWhenTrueConverter}}" Margin="50,-40,0,0">
<Ellipse Fill="Black" Width="27" Height="27"/>
<Ellipse Width="25" Height="25" VerticalAlignment="Center" HorizontalAlignment="Center">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Coral" Offset="0.0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Viewbox Width="25" Height="25" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock Text="{Binding ExpiredActiveCallFactorsCount}" Foreground="White"/>
</Viewbox>
</Grid>
</Grid>
</telerikRibbonBar:RadRibbonRadioButton>
How it looks:
No luck getting it in front of the ribbon button but oh well.
This can be accomplished with a few bindings and an optional value converter. This samples assumes you are binding to a model that has an Items property and that that property is of type ObservableCollection so that the Count property of the collection will fire property changed when items are added/removed.
<Grid>
<Grid.Resources>
<local:CountToVisbilityConverter x:Key="CountToVis"/>
</Grid.Resources>
....
<Grid Width="25" Height="25" Visibility="{Binding Items.Count, Converter=CountToVis}">
<Ellipse Fill="Red" Width="25" Height="25"/>
<ViewBox Width="25" Height="25">
<TextBlock Text="{Binding Itmes.Count}" Foreground="White"/>
</Viewbox>
</Grid>
</Grid>
And the value converter:
public class CountToVisibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null) return Visibility.Collapsed;
int count = System.Convert.ToInt32(value);
return count == 0 ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
The reason I saw optional" converter is because you can also use the Interaction DataTriggers like such
<Grid x:Name="UnreadNotification" Width="25" Height="25">
<Ellipse Fill="Red" Width="25" Height="25"/>
<ViewBox Width="25" Height="25">
<TextBlock Text="{Binding Itmes.Count}" Foreground="White"/>
</Viewbox>
</Grid>
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding Items.Count, Comparison="Equal"
Value="0">
<ei:ChangePropertyAction PropertyName="IsEnabled"
Value="True"
TargetName="UnreadNotification" />
</ei:DataTrigger>
</i:Interaction.Triggers>
Here's my solution for this. By default, the badge will show in the upper right corner. You can change this by setting the "BadgeMarginOffset" property. I've attached a couple of images to show how it appears. One, which shows the badge wrapping a Telerik RadRibbonButton. You can also change the background and foreground colors of the badge (BadgeBackground, BadgeForeground). The defaults are shown below.
The UserControl's XAML
<UserControl x:Class="Foundation.Common.Controls.Wpf.Badge"
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:converters="clr-namespace:Foundation.Common.Controls.Wpf.Converters"
Background="Transparent" x:Name="UserControl"
mc:Ignorable="d" >
<UserControl.Resources>
<converters:GreaterThanZeroBooleanConverter x:Key="GreaterThanZeroBooleanConverter" />
<converters:GreaterThanZeroVisibilityConverter x:Key="GreaterThanZeroVisibilityConverter"/>
</UserControl.Resources>
<UserControl.Template>
<ControlTemplate>
<Grid HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border CornerRadius="10"
UseLayoutRounding="True"
x:Name="BadgeBorder"
Grid.ZIndex="99"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Visibility="{Binding ElementName=UserControl, Path=Count, Mode=TwoWay, Converter={StaticResource GreaterThanZeroVisibilityConverter}}"
Grid.Row="0"
Margin="{Binding ElementName=UserControl, Path=BadgeMarginOffset}"
Height="22"
Padding="6.7,2,7,3"
Background="{Binding ElementName=UserControl, Path=BadgeBackground}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=UserControl, Path=Count, Mode=TwoWay, Converter={StaticResource GreaterThanZeroBooleanConverter}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0.0"
To="1.0"
Duration="0:0:0.7"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=UserControl, Path=ShowDropShadow}" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="6" ShadowDepth="4" Color="#949494"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{Binding ElementName=UserControl, Path=Count}"
Foreground="{Binding ElementName=UserControl, Path=BadgeForeground}"
FontWeight="Bold"
FontSize="12">
</TextBlock>
</Border>
<ContentPresenter Grid.Row="0"
Grid.RowSpan="2"
DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
</Grid>
</ControlTemplate>
</UserControl.Template>
The UserControl's code behind
public partial class Badge : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty CountProperty =
DependencyProperty.Register("Count", typeof(int), typeof(Badge));
public static readonly DependencyProperty ShowDropShadowProperty =
DependencyProperty.Register("ShowDropShadow", typeof(bool), typeof(Badge), new PropertyMetadata(true));
public static readonly DependencyProperty BadgeMarginOffsetProperty =
DependencyProperty.Register("BadgeMarginOffset", typeof(Thickness), typeof(Badge));
public static readonly DependencyProperty BadgeBackgroundProperty =
DependencyProperty.Register("BadgeBackground", typeof(Brush), typeof(Badge), new PropertyMetadata(Brushes.Red));
public static readonly DependencyProperty BadgeForegroundProperty =
DependencyProperty.Register("BadgeForeground", typeof(Brush), typeof(Badge), new PropertyMetadata(Brushes.White));
#endregion Dependency Properties
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="Badge"/> class.
/// </summary>
public Badge()
{
this.InitializeComponent();
}
#endregion Constructor
#region Properties
/// <summary>
/// Gets or sets a value indicating whether [show drop shadow].
/// </summary>
/// <value>
/// <c>true</c> if [show drop shadow]; otherwise, <c>false</c>.
/// </value>
public bool ShowDropShadow
{
get => (bool)this.GetValue(ShowDropShadowProperty);
set => this.SetValue(ShowDropShadowProperty, value);
}
/// <summary>
/// Gets or sets the badge margin offset.
/// </summary>
/// <value>
/// The badge margin offset.
/// </value>
public Thickness BadgeMarginOffset
{
get => (Thickness)this.GetValue(BadgeMarginOffsetProperty);
set => this.SetValue(BadgeMarginOffsetProperty, value);
}
/// <summary>
/// Gets or sets the badge background.
/// </summary>
/// <value>
/// The badge background.
/// </value>
public Brush BadgeBackground
{
get => (Brush)this.GetValue(BadgeBackgroundProperty);
set => this.SetValue(BadgeBackgroundProperty, value);
}
/// <summary>
/// Gets or sets the badge foreground.
/// </summary>
/// <value>
/// The badge foreground.
/// </value>
public Brush BadgeForeground
{
get => (Brush)this.GetValue(BadgeForegroundProperty);
set => this.SetValue(BadgeBackgroundProperty, value);
}
/// <summary>
/// Gets or sets the count.
/// </summary>
/// <value>
/// The count.
/// </value>
public int Count
{
get => (int)this.GetValue(CountProperty);
set => this.SetValue(CountProperty, value);
}
#endregion Properties
}
Sample code for the top two images
<wpf:Badge Count="108" Margin="20" HorizontalAlignment="Left" BadgeMarginOffset="0,-5,-5,0">
<Button Height="100" Width="100">
<Button.Content>
<Image Source="Resources/about.png" />
</Button.Content>
</Button>
</wpf:Badge>
I am writing a custom control that is a ListView that has a CheckBox on each item in the ListView to indicate that item is Selected. I was able to do so with the following XAML.
<ListView x:Class="CheckedListViewSample.CheckBoxListView"
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">
<ListView.Style>
<Style TargetType="{x:Type ListView}">
<Setter Property="SelectionMode" Value="Multiple" />
<Style.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
<CheckBox.Content>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</CheckBox.Content>
</CheckBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>
</ListView.Style>
</ListView>
I however am trying to attempt one more feature. The ListView has a SelectedItems DependencyProperty that returns a collection of the Items that are checked. However, I need to implement a SelectedValues DependencyProperty. I also am implementing a SelectedValuesPath DependencyProperty. By using the SelectedValuesPath, I indicate the path where the values are found for each selected item. So if my items have an ID property, I can specify using the SelectedValuesPath property "ID". The SelectedValues property would then return a collection of ID values. I have this working also using this code in the code-behind:
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
namespace CheckedListViewSample
{
/// <summary>
/// Interaction logic for CheckBoxListView.xaml
/// </summary>
public partial class CheckBoxListView : ListView
{
public static DependencyProperty SelectedValuesPathProperty =
DependencyProperty.Register("SelectedValuesPath",
typeof(string),
typeof(CheckBoxListView),
new PropertyMetadata(string.Empty, null));
public static DependencyProperty SelectedValuesProperty =
DependencyProperty.Register("SelectedValues",
typeof(IList),
typeof(CheckBoxListView),
new PropertyMetadata(new List<object>(), null));
[Category("Appearance")]
[Localizability(LocalizationCategory.NeverLocalize)]
[Bindable(true)]
public string SelectedValuesPath
{
get
{
return ((string)(base.GetValue(CheckBoxListView.SelectedValuesPathProperty)));
}
set
{
base.SetValue(CheckBoxListView.SelectedValuesPathProperty, value);
}
}
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Category("Appearance")]
public IList SelectedValues
{
get
{
return ((IList)(base.GetValue(CheckBoxListView.SelectedValuesPathProperty)));
}
set
{
base.SetValue(CheckBoxListView.SelectedValuesPathProperty, value);
}
}
public CheckBoxListView()
: base()
{
InitializeComponent();
base.SelectionChanged += new SelectionChangedEventHandler(CheckBoxListView_SelectionChanged);
}
private void CheckBoxListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
List<object> values = new List<object>();
foreach (var item in SelectedItems)
{
if (string.IsNullOrWhiteSpace(SelectedValuesPath))
{
values.Add(item);
}
else
{
try
{
values.Add(item.GetType().GetProperty(SelectedValuesPath).GetValue(item, null));
}
catch { }
}
}
base.SetValue(CheckBoxListView.SelectedValuesProperty, values);
e.Handled = true;
}
}
}
My problem is that my binding only works one way right now. I'm having trouble trying to figure out how to implement my SelectedValues DependencyProperty so that I could Bind a Collection of values to it, and when the control is loaded, the CheckBoxes are checked with items that have values that correspond to the SelectedValues.
I've considered using the PropertyChangedCallBack event, but can't quite figure out how I could write that to achieve my goal.
I'm also unsure of how I find the correct ListViewItem to set it as Selected.
And lastly, if I can find the ListViewItem and set it to be Selected, won't that fire my SelectionChanged event each time I set a ListViewItem to be Selected?
Go through the below links.
Sync SelectedItems in a muliselect listbox with a collection in ViewModel
http://alexshed.spaces.live.com/blog/cns!71C72270309CE838!149.entry
http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html