I need to apply style in grid resources programmatically in code behind.
I've the following snippet of code :
<Grid x:Name="grid">
<Grid.Resources>
<Style TargetType="{x:Type ig:LabelPresenter}">
<EventSetter Event="PreviewMouseMove" Handler="LabelPresenter_PreviewMouseMove"/>
</Style>
</Grid.Resources>
.
.
.
</Grid>
I want to create the Style in code behind and add this to resources for handle the relative action.
I tried to do this in this way but it dosen't work.
public MainWindow()
{
InitializeComponent();
var style = new Style { TargetType = typeof(LabelPresenter) };
var eventSetter = new EventSetter(PreviewMouseMoveEvent, new MouseButtonEventHandler(LabelPresenter_PreviewMouseMove));
style.Setters.Add(eventSetter);
grid.Resources.Add("style", style);
}
Where I'm wrong?
Thanks in advance.
EDIT: I wrote wrong grid's name. The grid's right name is grid
The style defined in the XAML markup is implicit, i.e. it has no x:Key. So change the first argument that you are passing to the Add method to typeof(LabelPresenter).
Also, a PreviewMouseMove event handler accepts a MouseEventArgs:
var style = new Style { TargetType = typeof(LabelPresenter) };
var eventSetter = new EventSetter(PreviewMouseMoveEvent, new MouseEventHandler(LabelPresenter_PreviewMouseMove));
style.Setters.Add(eventSetter);
grid.Resources.Add(typeof(LabelPresenter), style);
Related
I'm trying to set font size dynamically in WPF. Here what i did so far.
App.xaml
<Style TargetType="{x:Type FrameworkElement}" x:key="baseStyle"></Style>
<Style TargetType="{x:Type TextBlock}" BasedOn={StaticResource baseStyle}"/>
App.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
double fontSize = System.Drawing.SystemFonts.IconTitleFont.Size;
Style style = new Style{ TargetType = typeof(FrameworkElement)};
style.Setter.Add(new Setter(TextElement.FontSizeProperty, fontSize));
Application.Current.Resources["baseStyle"] = style;
}
}
MainWindow.xaml
<TextBlock Text="This is Sparta!!!"/>
Issue:
When the OnStartup called the resource 'baseStyle' is not available. So the style is assigned to Null value due to which the style is not applied. Anyone having idea to implement it in some other way. Your help will be appreciated.
Edit:
There is one thing that i would like to clarify. In reality i have wrote that App.xaml and App.xaml.cs code in resource dictionary and merged it in App.xaml. The code written in OnStartup is written in constructor of that code behind class.
With a little modification your code works. Just remove and add the base style
Style style = new Style { TargetType = typeof(FrameworkElement) };
style.Setters.Add(new Setter(TextElement.FontSizeProperty, fontSize));
Application.Current.Resources.Remove("baseStyle");
Application.Current.Resources.Add("baseStyle" , style);
Here is my XAML. The UserControl is named "Event"
<UserControl.Resources>
<Style x:Key="eventStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle Name="rect" Fill="CadetBlue" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Canvas>
<Thumb Canvas.Left="0" Canvas.Top="0" Name="MoveThumb" Style="{StaticResource eventStyle}" Cursor="SizeAll" DragDelta="MoveThumb_DragDelta" DragStarted="MoveThumb_DragStarted" DragCompleted="MoveThumb_DragCompleted" />
</Canvas>
And here is the code behind
var ev = new Event();
var rect = ev.Template.FindName("rect", ev) as Rectangle;
But it doesn't work : the "rect" variable is null. What am I doing wrong ?
Thanks
The template you're defining is applied to the Thumb control, and not the Event control - that's why there's no rect control in Event's template.
Since you're creating the Event control from another class, what you can do is expose the MoveThumb control as a property in Event's code-behind, like this:
public Thumb TheThumb
{
get { return MoveThumb; }
}
Then you can change your code to this:
var ev = new Event();
var rect = ev.TheThumb.Template.FindName("rect", ev.TheThumb) as Rectangle;
Better yet, you can expose the rect control as a property:
public Rectangle Rect
{
get { return MoveThumb.Template.FindName("rect", MoveThumb) as Rectangle; }
}
and use it like this
var ev = new Event();
var rect = ev.Rect;
It returned null because the function FindName("controlName",TemplatedParent) expects a control on which the template is applied as the second parameter. From the code you've provided, I couldn't see when the template was applied to the control (ev used to the default template). Hence, the rect variable was null.
Try this
var rectangle = MoveThumb.Template.FindName("rect", MoveThumb) as Rectangle;
More information is available here and here
I've got a simple custom control :
namespace Application.Custom_Controls
{
public class ReadOnlyTextBox : TextBox
{
public ReadOnlyTextBox()
{
this.DefaultStyleKey = typeof(ReadOnlyTextBox);
this.IsReadOnly = true;
}
}
}
And a custom style to make the control look like a TextBlock (in App.xaml).
<Application
x:Class="Application.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:tb = "clr-namespace:Application.Custom_Controls"
>
<!--Application Resources-->
<Application.Resources>
<Style x:Key="ReadOnlyTextBox" TargetType="tb:ReadOnlyTextBox">
//...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="tb:ReadOnlyTextBox">
//...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But when I'm using it in my application it does'nt display at all.
It diplays as a normal TextBox if I remove this.DefaultStyleKey = typeof(ReadOnlyTextBox);.
How to apply this style to my custom control in code behind ?
By the way, this style works well in xaml with Style="{StaticResource ReadOnlyTextBox}", but I can't use xaml in this case.
Thanks in advance.
this.Style = (Style)Application.Current.Resources["ReadOnlyTextBox"];
Add this line to the constructor of the ReadOnlyTextBox
I am trying to add control to ContentPresenter on then run, but control I've added does not apply theme.
Theres is code with reference to theme in xaml file:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/PocGraphDataTemplates.xaml" />
</ResourceDictionary.MergedDictionaries>
Also I've tried to set style in code behind, does not work:
this.graphLayout.Content = analyzerViewModel.AnalyzedLayout = new PocGraphLayout()
{
LayoutAlgorithmType = "FR"
};
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri("Resources/PocGraphDataTemplates.xaml", UriKind.Relative);
analyzerViewModel.AnalyzedLayout.Style = new Style(typeof(PocGraphLayout));
analyzerViewModel.AnalyzedLayout.Style.Resources.MergedDictionaries.Add(rd);
When control was static everything worked fine:
<ViewModel:PocGraphLayout x:Name="graphLayout"
Graph="{Binding Path=Graph}"
LayoutAlgorithmType="{Binding Path=LayoutAlgorithmType}"
Sample:LayoutManager.ManagedLayout="True"
OverlapRemovalAlgorithmType="FSA"
HighlightAlgorithmType="Simple" />
Any ideas?
PS. I am newbie in wpf.
just see the style applied are using DynamicResource instead of StaticResource
I'm trying to use the context menu in a listview to run some code that requires data from which item it originated from.
I initially just did this:
XAML:
<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.Resources>
<ContextMenu x:Key="resourceContextMenu">
<MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click" />
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource resourceContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
...
C#:
private void cmMetadata_Click(object sender, RoutedEventArgs e)
{
// code that needs item data here
}
But I found that the originating listview item was not accessible that way.
I've read some tactics about how to get around this, like intercepting the MouseDown event and setting a private field to the listviewitem that was clicked, but that doesn't sit well with me as it seems a bit hacky to pass data around that way. And WPF is supposed to be easy, right? :) I've read this SO question and this MSDN forum question, but I'm still not sure how to really do this, as neither of those articles seem to work in my case. Is there a better way to pass the item that was clicked on through to the context menu?
Thanks!
Similar to Charlie's answer, but shouldn't require XAML changes.
private void cmMetadata_Click(object sender, RoutedEventArgs e)
{
MenuItem menu = sender as MenuItem;
ListViewItem lvi = lvResources.ItemContainerGenerator.ContainerFromItem(menu.DataContext) as ListViewItem;
}
Well in the cmMetadata_Click handler, you can just query the lvResources.SelectedItem property, since lvResources will be accessible from the code-behind file that the click handler is located in. It's not elegant, but it will work.
If you want to be a little more elegant, you could change where you set up your ContextMenu. For example, you could try something like this:
<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.Style>
<Style TargetType="ListView">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click"
DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</ListView.Style>
<ListViewItem>One Item</ListViewItem>
<ListViewItem>Another item</ListViewItem>
</ListView>
What this does is plug in a template for your ListViewItem, and then you can use the handy TemplatedParent shortcut to assign the ListViewItem to the DataContext of your menu item.
Now your code-behind looks like this:
private void cmMetadata_Click(object sender, RoutedEventArgs e)
{
MenuItem menu = sender as MenuItem;
ListViewItem item = menu.DataContext as ListViewItem;
}
Obviously the downside is you will now need to complete the template for a ListViewItem, but I'm sure you can find one that will suit your needs pretty quickly.
So I decided to try and implement a command solution. I'm pretty pleased with how it's working now.
First, created my command:
public static class CustomCommands
{
public static RoutedCommand DisplayMetadata = new RoutedCommand();
}
Next in my custom listview control, I added a new command binding to the constructor:
public SortableListView()
{
CommandBindings.Add(new CommandBinding(CustomCommands.DisplayMetadata, DisplayMetadataExecuted, DisplayMetadataCanExecute));
}
And also there, added the event handlers:
public void DisplayMetadataExecuted(object sender, ExecutedRoutedEventArgs e)
{
var nbSelectedItem = (MyItem)e.Parameter;
// do stuff with selected item
}
public void DisplayMetadataCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
I was already using a style selector to dynamically assign styles to the listview items, so instead of doing this in the xaml, I have to set the binding in the codebehind. You could do it in the xaml as well though:
public override Style SelectStyle(object item, DependencyObject container)
{
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container);
MyItem selectedItem = (MyItem)item;
Style s = new Style();
var listMenuItems = new List<MenuItem>();
var mi = new MenuItem();
mi.Header= "Get Metadata";
mi.Name= "cmMetadata";
mi.Command = CustomCommands.DisplayMetadata;
mi.CommandParameter = selectedItem;
listMenuItems.Add(mi);
ContextMenu cm = new ContextMenu();
cm.ItemsSource = listMenuItems;
// Global styles
s.Setters.Add(new Setter(Control.ContextMenuProperty, cm));
// other style selection code
return s;
}
I like the feel of this solution much better than attempting to set a field on mouse click and try to access what was clicked that way.