All,
I am trying to create a Metro Window Style. I have the style in Application.Resource file. I am trying to enable Dragging of the window in inline code. The problem is, when I have the style inside the Window XAML itself, I can access the properties of the Window. But in Application.Resource file, I loose the reference to the Window.
What I want to know is: how can I access the Window properties in inline code to which the style is applied to so I can apply the DragMove to the Window?
If this is not the right way then can I get the correct way of handling this problem please?
<Application.Resources>
<Style x:Key="MetroWindowStyle" TargetType="{x:Type Window}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome ResizeBorderThickness="6" CaptionHeight="0" GlassFrameThickness="0" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border x:Name="MainBorder" Background="#FFEEEEEE" BorderBrush="#FFA4A4A4" BorderThickness="1">
<DockPanel LastChildFill="True">
<Border x:Name="HeaderBorder" Height="30" Background="#FFE6E6E6" DockPanel.Dock="Top" MouseLeftButtonDown="HeaderBorder_MouseLeftButtonDown">
</Border>
<AdornerDecorator DockPanel.Dock="Bottom">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}"/>
</AdornerDecorator>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<x:Code>
<![CDATA[
private void HeaderBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove(); //////Complains here because I don't have access to the Window to which this style is applied to
}
]]>
</x:Code>
</Application.Resources>
Thanks
You could use an attached behaviour.
public class DraggableWindowBehaviour : Behavior<Window>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseLeftButtonDown += _associatedObject_MouseLeftButtonDown;
}
private void _associatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
AssociatedObject.DragMove();
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseLeftButtonDown -= _associatedObject_MouseLeftButtonDown;
}
}
Inside the Border control of your window control template:
<e:Interaction.Behaviors>
<b:DraggableWindowBehaviour/>
</e:Interaction.Behaviors>
Related
I have two Windows for an application. One of them is MainWindow and the other is for settings. SettingsWindow opens when settings button is clicked by using ShowDialog and setting its Owner to MainWindow.
On the SettingsWindow I have a button at the very bottom of the window and it changes the color to red when IsMouseOver is True and blue for False. But it doesn't change when the cursor is over the MainWindow. The image is below to be clear. How can I fix this problem?
CASE: The cursor is out of SettingsWindow but it keeps the red color, no change.
Xaml code:
<Window x:Class="AltoSS.SettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SettingsWindow"
Height="150"
Width="360"
WindowStyle="None"
AllowsTransparency="True"
WindowStartupLocation="CenterOwner">
<!-- Other control codes-->
<Button Grid.Row="2" Content="KAYDET"
FontSize="15"
FontWeight="Bold"
BorderBrush="Gray"
BorderThickness="0,2,0,2">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</Window>
Alright, after doing some research, I couldn't find any logical reason for this to occur. It seems more like a bug to me. So if anyone knows exactly why this happens, let us know!
Anyway, I've come up with a workaround. Basically, we can use Show() and add some code to get closer to a modal behavior - like disabling the parent window until the dialog gets closed or the user has selected OK or Cancel for instance.
Example:
SettingsWindow settingsWindow = new SettingsWindow();
this.IsEnabled = false; //disables the main window
settingsWindow.Owner = this; // main window is the settings window owner
settingsWindow.Show();
settingsWindow.Closed += (o, e1) => { onWindowClosed(o,e1); }; // this is the close event
After subscribing for the settingsWindow closed event, we can now enable the parent window again when settingsWindow gets closed:
private void onWindowClosed(object sender, EventArgs e)
{
this.IsEnabled = true;
}
Triggers will now work correctly and parent window gets disabled until its child is closed.
I think you have to observe the mouse position manually. For this you could use the code behind posted by Peheje here.
I used this to program a working example. While leaving your window, the Button gets the correct style.
using System.Runtime.InteropServices;
using Point = System.Drawing.Point;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(ref Point lpPoint);
public bool IsMouseOverButton {
get { return _isMouseOverButton; }
set {
if (value == _isMouseOverButton) return;
_isMouseOverButton = value;
OnPropertyChanged();
}
}
public SettingsWindow()
{
InitializeComponent();
new Thread(() =>
{
while (true)
{
//Logic
Point p = new Point();
GetCursorPos(ref p);
//Update UI
Application.Current.Dispatcher.Invoke(() =>
{
double btnLeft = DlgWindow.Left;
double btnRight = btnLeft + DlgBtn.ActualWidth;
double btnBottom = DlgWindow.Top + DlgWindow.ActualHeight;
double btnTop = btnBottom - DlgBtn.ActualHeight;
IsMouseOverButton =
p.X >= btnLeft && p.X <= btnRight &&
p.Y >= btnTop && p.Y <= btnBottom;
});
//async wait (non blocking)
(new ManualResetEvent(false)).WaitOne(100);
}
}).Start();
}
xaml
<Window x:Name="DlgWindow"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
AllowsTransparency="True">
<Button x:Name="DlgBtn"
Height="50"
VerticalAlignment="Bottom"
BorderBrush="Gray"
BorderThickness="0,2,0,2"
Content="KAYDET"
FontSize="15"
FontWeight="Bold">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOverButton}" Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
This works for me: Define a style resource (for the button) under settings Window.Resources - This style then sets the new Template (a border), the default background as blue, and the IsMouseOver trigger to change it to red. Reference the style either explicitly for implicitly (both worked for me).
Link to small test project: https://1drv.ms/u/s!AhlMAmchX3R6nDJ1MXS6DxlRXtnA
<Window x:Class="IsMouseOverTriggerSecondWindow.SettingsWindow"
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:IsMouseOverTriggerSecondWindow"
mc:Ignorable="d"
Title="SettingsWindow" Height="170" Width="330">
<!-- my settings window button style-->
<!-- defined as a resource in SettingsWindow.xaml, so it doesnt effect MainWindow -->
<Window.Resources>
<Style TargetType="Button" >
<Setter Property="Background" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBlock Text="This is the settings window" />
<Button Content="KAYDET" Height="30" VerticalAlignment="Bottom" Foreground="White" FontWeight="Bold" />
</Grid>
</Window>
I'm binding a button command, in a ControlTemplate, to an Execute() method in a CustomControl. I'm using a RoutedCommand, the CanExecute() fires, but the Execute() never does. When the CustomControl is placed in the main window, the code works as expected. When it is placed in a Usercontrol, I have this issue. I have tried several ways to wire up the buttons Command (RelayCommand etc) but can't seem to figure out what's wrong. Any help is appreciated.
For context, this is a TokenizingTextBox control - an early fork of the Xceed open source version. The button is for deleting the token from the list of tokens.
The complete style of a TokenIten (which contains the button of interest):
<Style TargetType="{x:Type local:TokenItem}">
<Setter Property="Background" Value="#F3F7FD" />
<Setter Property="BorderBrush" Value="#BBD8FB" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Padding" Value="2,1,1,1" />
<Setter Property="Margin" Value="1,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TokenItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
CornerRadius="0,0,5,5"
Margin="{TemplateBinding Margin}"
>
<StackPanel Orientation="Horizontal" Margin="1" x:Name="myRoot">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
<Button Margin="3,0,0,0" Cursor="Hand"
Command="{x:Static local:TokenizedTextBoxCommands.Delete}" CommandParameter="{TemplateBinding TokenKey}"
PresentationTraceSources.TraceLevel="High">
<!--<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>-->
<Image Source="/Resources/delete8.png" Width="8" Height="8" />
</Button>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The static Command:
public static class TokenizedTextBoxCommands
{
private static RoutedCommand _deleteCommand = new RoutedCommand();
public static RoutedCommand Delete => _deleteCommand;
}
The Custom Control inherits from ItemsControl. In the non-static constructor, we wire up the static delete command to the DeleteToken method:
public TokenizedTextBox()
{
CommandBindings.Add(new CommandBinding(TokenizedTextBoxCommands.Delete, DeleteToken, CanDelete));
}
Finally CanDelete which just sets CanExecute to true:
private void CanDelete(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
{
canExecuteRoutedEventArgs.CanExecute = true;
}
And DeleteToken - functionality omitted, signature is really only important thing here:
private void DeleteToken(object sender, ExecutedRoutedEventArgs e)
{
...
}
So, hopefully this is enough information for anyone interested in providing guidance/suggestions. Thanks.
Little interest here so I hired a Mentor through Pluralsight. The bindings were correct, but the CustomControl had a RichTextBox which was capturing the Mouse Click. We fixed the issue using a Behavior targeting the Button's PreviewMouseDown.
For my custom control, I am using the Dynamic resource to set the Foreground property. Initially when i run the app the Foreground property was not set to my control. When I change value dynamically Foreground was applied correctly. How can I resolve this issue?
PS: Simple sample WpfApplication4
MainWindow.xaml
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="300"
Height="200">
<Window.Resources>
<SolidColorBrush x:Key="ForegroundBrush" Color="Red" />
<SolidColorBrush x:Key="BackgroundBrush" Color="Yellow" />
<Style x:Key="MyStyle" TargetType="ContentControl">
<Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource BackgroundBrush}" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel>
<Button Click="ButtonBase_OnClick" Content="Create and Add Custom Control With Style" />
<Button Click="ButtonBase_OnClick_1" Content="Change Color" />
</StackPanel>
<StackPanel x:Name="myPanel" Grid.Row="1" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var control = new MyControl {Style = this.Resources["MyStyle"] as Style};
control.CreateContent(string.Format("My Control {0}", myPanel.Children.Count + 1));
myPanel.Children.Add(control);
}
private void ButtonBase_OnClick_1(object sender, RoutedEventArgs e)
{
var brush = (SolidColorBrush)Resources["ForegroundBrush"];
Resources["ForegroundBrush"] = new SolidColorBrush(Color.Add(brush.Color, Color.FromRgb(0, 100, 100)));
var brush1 = (SolidColorBrush)Resources["BackgroundBrush"];
Resources["BackgroundBrush"] = new SolidColorBrush(Color.Add(brush1.Color, Color.FromRgb(0, 100, 100)));
}
}
public class MyControl : ContentControl
{
public MyControl()
{
DefaultStyleKey = typeof(MyControl);
}
public void CreateContent(string text)
{
this.Content = new TextBlock() {Text = text};
}
}
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4">
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If you want to apply a Style to a control, then you have to apply the Style to that control (which you haven't done in the code example that you have provided). You have two choices here... either try this (wherever you use the control):
<local:MyControl Style="{StaticResource MyStyle}" />
Or define your Style like this, which will affect all instances of your control within scope:
<Style TargetType="ContentControl">
<Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource BackgroundBrush}" />
</Style>
We can easily make an icon button using a control template like the following code:
<Style x:Key="IconButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Image x:Name="Background" Source="/UOC;component/TOOLBAR_BUTTON_NORMAL.png"/>
<Image Source="/UOC;component/ICON_SLICER.gif" Width="20" Height="20" Margin="0,-10,0,0"/>
<TextBlock Foreground="White" FontSize="9" Text="{TemplateBinding Button.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,15,0,0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Source" TargetName="Background" Value="/UOC;component/TOOLBAR_BUTTON_OVER.png"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Source" TargetName="Background" Value="/UOC;component/TOOLBAR_BUTTON_CLICK.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But i think it's not a productive way in practice. because i can't make a number of styles for each one of icon buttons. (ex. let's assume three buttons in App:'open' button, 'close' button and 'navigate' button. these buttons have different icon sets. i can't make styles like 'IconButton_Close', 'IconButton_Open', 'IconButton_Nav'. it's too stupid.)
UserControl may be an answer. but i think it's not a smart way for that. because if i make UserControl, it'll be just a wrapper of the Button control. it's not a right way.
So, give me the best way for icon button.
thanks.
The correct way to do this would be to define a custom button class, like so:
public class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(ImageSource),
typeof(MyButton), new FrameworkPropertyMetadata(null));
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSourceHoverProperty = DependencyProperty.Register("ImageSourceHover", typeof(ImageSource),
typeof(MyButton), new FrameworkPropertyMetadata(null));
public ImageSource ImageSourceHover
{
get { return (ImageSource)GetValue(ImageSourceHoverProperty); }
set { SetValue(ImageSourceHoverProperty, value); }
}
public static readonly DependencyProperty ImageSourcePressedProperty = DependencyProperty.Register("ImageSourcePressed", typeof(ImageSource),
typeof(MyButton), new FrameworkPropertyMetadata(null));
public ImageSource ImageSourcePressed
{
get { return (ImageSource)GetValue(ImageSourcePressedProperty); }
set { SetValue(ImageSourcePressedProperty, value); }
}
}
Then define the default Style like so:
<Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyButton}">
<Grid>
<Image x:Name="Background" Source="{TemplateBinding ImageSource}" />
<Image Source="/UOC;component/ICON_SLICER.gif" Width="20" Height="20" Margin="0,-10,0,0"/>
<TextBlock Foreground="White" FontSize="9" Text="{TemplateBinding Button.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,15,0,0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Source" TargetName="Background" Value="{TemplateBinding ImageSourceHover}"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Source" TargetName="Background" Value="{TemplateBinding ImageSourcePressed}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And you'd use it like so:
<local:MyButton ImageSource="/UOC;component/TOOLBAR_BUTTON_NORMAL.png"
ImageSourceHover="/UOC;component/TOOLBAR_BUTTON_OVER.png"
ImageSourcePressed="/UOC;component/TOOLBAR_BUTTON_CLICK.png" />
I did something similar to this for a custom control a while back using the TemplatePart attribute. This displays an icon and some text in a panel. If the icons is the error or fail icon, it turns the text red. There is a dependency property called "Type" which is really just the image file name without the extension. Here's the code, I bet you can adapt this for a custom Button where you can set the source and still have your customization to the template.
[TemplatePart(Name = "PART_Image", Type = typeof(Image))]
public class IconPanel : ContentControl
{
static IconPanel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IconPanel), new FrameworkPropertyMetadata(typeof(IconPanel)));
}
public string Type
{
get { return (string)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(string), typeof(IconPanel),
new UIPropertyMetadata("warning", TypeChangedCallback));
static void TypeChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
IconPanel panel = obj as IconPanel;
panel.UpdateImage();
}
void UpdateImage()
{
Image img = GetTemplateChild("PART_Image") as Image;
if (img == null) return;
string ImagePath = String.Format("pack://application:,,,/Resources/{0}.png", this.Type);
Uri uri = new Uri(ImagePath, UriKind.RelativeOrAbsolute);
BitmapImage bmp = new BitmapImage(uri);
img.Source = bmp;
if ( String.Compare(Type, "error", true) == 0 ||
String.Compare(Type, "fail", true) == 0 )
{
this.Foreground = new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));
}
}
public override void OnApplyTemplate()
{
UpdateImage();
base.OnApplyTemplate();
}
}
XAML:
<Style TargetType="{x:Type local:IconPanel}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:IconPanel}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="7">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image
x:Name="PART_Image"
Margin="0,0,5,5"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="16"
Height="16" />
<ContentPresenter Grid.Column="1"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am trying to use charts from the WPF Toolkit (with LineSeries) and I don't want a legend at all. I need this since I have 10 such charts each with data from a different source and I would like to draw one legend for all 10, to save screen real estate.
By default the legend appears the moment you add a second LineSeries. Is there any way to prevent it from even appearing?
Thanks,
sprite.
There doesn't seem to be an especially clean way. One simple approach is to set the Legend's Width to zero using LegendStyle:
<charting:Chart>
<charting:Chart.LegendStyle>
<Style TargetType="datavis:Legend">
<Setter Property="Width" Value="0" />
</Style>
</charting:Chart.LegendStyle>
A more drastic approach is to replace the ControlTemplate with one that does not include a Legend:
<charting:Chart>
<charting:Chart.Template>
<ControlTemplate TargetType="{x:Type charting:Chart}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<datavis:Title Content="{TemplateBinding Title}" Style="{TemplateBinding TitleStyle}" />
<chartingprimitives:EdgePanel Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}" Grid.Row="1" Margin="0,15,0,15">
<Grid Panel.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
<Border Panel.ZIndex="10" BorderBrush="#FF919191" BorderThickness="1" />
</chartingprimitives:EdgePanel>
</Grid>
</Border>
</ControlTemplate>
</charting:Chart.Template>
Use following namespaces:
xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:datavis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:chartingprimitives="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
I tried Quarermeister's approach but his has a reference to a "datavis" assembly in the TargetType attribute that I didn't have.
<chartingToolkit:Chart.LegendStyle>
<Style TargetType="Control">
<Setter Property="Width" Value="0" />
<Setter Property="Height" Value="0" />
</Style>
</chartingToolkit:Chart.LegendStyle>
I also had to add padding to the right side of the chart because without the legend, my x-axis interval labels were extending outside the chart area.
Much more sensible approach...
<charting:LineSeries.LegendItemStyle >
<Style TargetType="{x:Type charting:LegendItem}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</charting:LineSeries.LegendItemStyle>
Worked better for me than setting values to 0...
Cheers!
Attached Property for DRY, easy usage:
<charting:Chart helpers:ChartHelpers.IsLegendHidden="True" ...
public static class ChartHelpers
{
static ChartHelpers()
{
HideLegendStyle = new Style(typeof(Legend));
HideLegendStyle.Setters.Add(new Setter(Legend.WidthProperty, 0.0));
HideLegendStyle.Setters.Add(new Setter(Legend.HeightProperty, 0.0));
HideLegendStyle.Setters.Add(new Setter(Legend.VisibilityProperty, Visibility.Collapsed));
}
/// <summary>Gets a <see cref="Style"/> to hide the legend.</summary>
public static readonly Style HideLegendStyle;
#region IsLegendHidden
[Category("Common")]
[AttachedPropertyBrowsableForType(typeof(Chart))]
public static bool GetIsLegendHidden(Chart chart)
{
return (bool)chart.GetValue(IsLegendHiddenProperty);
}
public static void SetIsLegendHidden(Chart chart, bool value)
{
chart.SetValue(IsLegendHiddenProperty, value);
}
public static readonly DependencyProperty IsLegendHiddenProperty =
DependencyProperty.RegisterAttached(
"IsLegendHidden",
typeof(bool), // type
typeof(ChartHelpers), // containing static class
new PropertyMetadata(default(bool), OnIsLegendHiddenChanged)
);
private static void OnIsLegendHiddenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
OnIsLegendHiddenChanged((Chart)d, (bool)e.NewValue);
}
private static void OnIsLegendHiddenChanged(Chart chart, bool isHidden)
{
if (isHidden)
{
chart.LegendStyle = HideLegendStyle;
}
}
#endregion IsLegendHidden
}