How to add a Style to UserControl Resources in C# programmatically? - c#

I'm trying to do this XAML:
<UserControl.Resources>
<Style TargetType="Label">
<Setter Property="Foreground" Value="Blue"/>
</Style>
</UserControl.Resources>
in C# code.
Here's my attempt in the UserControl Constructor:
InitializeComponent();
string labelForegroundColor = "Blue";
string labelXAMLStyle = #"<Style xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' TargetType=""Label"">
<Setter Property=""Foreground"" Value=""{LabelForegroundColor}""/>
</Style>";
labelXAMLStyle = labelXAMLStyle.Replace("{LabelForegroundColor}", labelForegroundColor);
StringReader mainLabelStyleXAMLStringReader = new StringReader(labelXAMLStyle);
XmlReader mainLabelStyleXAMLXMLReader = XmlReader.Create(mainLabelStyleXAMLStringReader);
Style mainLabelStyle = (Style)XamlReader.Load(mainLabelStyleXAMLXMLReader);
this.Resources.Add("LabelStyle", mainLabelStyle);
When I have the XAML in my UserControl it obviously works, but when I remove the XAML and add the code in my UserControl Constructor; it doesn't.
Where am I going wrong?
Do I have to add some sort of Resource Dictionary?
How can I get it right to set the style of all Label's in my one specific UserControl?

You can try to create a style programatically and then add it to the resources.
Style style = new Style(typeof(Label));
style.Setters.Add(new Setter(Label.ForegroundProperty, Brushes.Blue));
Resources[typeof(Label)] = gridStyle;

Related

Alternative styles in code for DataGrid rows in WPF

I have a DataGrid with its RowStyle set in XAML:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightSteelBlue"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Aquamarine"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
The DataGrid contains rowdetails which I wish to print when that row is selected. However, I need to change the background colour of the row (including its rowdetails) from Aquamarine to White when printing and then back again after printing. I have the following method to achieve this:
private void ChangeStyle(bool printing)
{
Style rsRowStyle = new Style();
Style oldStyle = dgdCustomersListing.RowStyle;
Trigger DataTrigger = new Trigger();
DataTrigger.Property = DataGridRow.IsSelectedProperty;
DataTrigger.Value = true;
rsRowStyle.Triggers.Add(DataTrigger);
Setter TriggerSetter = new Setter();
TriggerSetter.Property = DataGridRow.BackgroundProperty;
TriggerSetter.Value = Brushes.LightGray;
rsRowStyle.Setters.Add(TriggerSetter);
dgdCustomersListing.RowStyle = printing ? rsRowStyle : oldStyle;
}
This works fine when first called for printing (the row background converts to white), but calling the method again when printing is false fails to revert the DataGrid back to the original style.
Why does it not work?
My error: the assignment to oldStyle needs to be made when first calling the printing method, and then passing that value to the ChangeStyle method so that it is not changed by that method. Hence:
private void ChangeStyle(bool printing, Style oldStyle)
{
Style rsRowStyle = new Style();
Trigger DataTrigger = new Trigger();
DataTrigger.Property = DataGridRow.IsSelectedProperty;
DataTrigger.Value = true;
rsRowStyle.Triggers.Add(DataTrigger);
Setter TriggerSetter = new Setter();
TriggerSetter.Property = DataGridRow.BackgroundProperty;
TriggerSetter.Value = Brushes.LightGray;
rsRowStyle.Setters.Add(TriggerSetter);
dgdCustomersListing.RowStyle = printing ? rsRowStyle : oldStyle;
}
I have left this up as Q&A as it took me some time to sort out how to change the style in code, and I hope this might be useful to others.

WPF class library, loading XAML with absolute URI or relative URI both not working

I'm programming a WPF class library mainly based on C# code and I'm currently trying to load XAML file only for styling UI Elements.
Here is the XAML "style" code with "BuildAction : Content" :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="Height" Value="53" />
<Setter Property="Width" Value="130" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="99,71,0,0" />
<Setter Property="VerticalAlignment" Value= "Top" />
<Setter Property="Foreground" Value="#FFE75959" />
<Setter Property="FontFamily" Value="Calibri" />
<Setter Property="FontSize" Value="40" />
</Style>
Here is the code for my label :
private void CreateElement(int i)
{
UIElementOut[i] = new Label();
var uiElement = (Label)UIElementOut[i];
uiElement.HorizontalAlignment = HorizontalAlignment.Center;
uiElement.VerticalAlignment = VerticalAlignment.Center;
uiElement.FontFamily = new FontFamily(FFontInput[i]);
uiElement.FontSize = Convert.ToDouble(FontSizeIn[i]);
uiElement.Content = TextIn[i];
Brush BgBrushColor = new SolidColorBrush(RGBAToMediaColor(FBgCol[i]));
Brush FgBrushColor = new SolidColorBrush(RGBAToMediaColor(FFgCol[i]));
uiElement.Background = BgBrushColor;
uiElement.Foreground = FgBrushColor;
Uri uri = new Uri("pack://application:,,,/WpfApplication1;component/WpfApplication1/Styles/LabelStyle.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetContentStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
ResourceDictionary myResourceDictionary = Application.LoadComponent(uri) as ResourceDictionary;
Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary);
Style myLabelStyle = myResourceDictionary["LabelStyle"] as Style;
uiElement.Style = myLabelStyle;
}
if UriKind is set to "Relative" I get this error message :
A relative URI cannot be created because the 'uriString' parameter represents an absolute URI.
But if Urikind is set to "Absolute" then I get this one :
Cannot use absolute URI.
So in both anyway, XAML file is not loaded and style is not applied.
EDIT :
I tried this URI :
pack://application:,,,/WpfApplication1;component/Styles/LabelStyle.xaml
And get the same error.
Correct format to reference resourcefile located in a subfolder of the local assembly's project folder
pack://application:,,,/Subfolder/ResourceFile.xaml
Correct format to reference resourcefile in separate referenced assembly is
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml
Changing your uri to
pack://application:,,,/WpfApplication1;component/Styles/LabelStyle.xaml
should solve the issue

How to change the window.resource style setter?

<Window.Resources >
<Style x:Name="stylepropery" x:Key="BaseContentControlStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Foreground" Value="{DynamicResource MyFillBrush}" />
</Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseContentControlStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseContentControlStyle}" />
</Window.Resources>
which is applying common font color to all the labels and textboxes now i want to change the color of font from code behind but some how its not applying
i just want to change setter propery value
Setter setter = new Setter(ContentControl.ForegroundProperty, dt.Rows[0]["value"]);
Style style = this.FindResource("BaseContentControlStyle") as Style;
style.Setters.Add(setter);
I have used this but not succedd
Try this code this may help you
Style style = new Style(typeof(ContentControl));
style.Setters.Add(new Setter(ContentControl.ForegroundProperty, Brushes.Green));
Resources["BaseContentControlStyle"] = style;
var converter = new System.Windows.Media.BrushConverter();
var brush = (Brush)converter.ConvertFromString(dt.Rows[0]["value"].ToString());
Style st = this.Resources["BaseContentControlStyle"] as Style;
Random r = new Random();
this.Resources["MyFillBrush"] = (new BrushConverter().ConvertFrom(dt.Rows[0]["value"].ToString()));
After lots of googling i have found the solution i am adding this solution for the future refrence users so they don't have to search many things :)

Set WPF VisualStyle in C#

I'm trying to indent items on a WPF navBar. I can do this in XAML using resources and setting the visualstyle to the appropriate style
<dx:DXWindow.Resources>
<Style x:Key="nestedNavBarItemL1" TargetType="ButtonBase">
<Setter Property="Margin" Value="20,0,0,0"/>
</Style>
<Style x:Key="nestedNavBarItemL2" TargetType="ButtonBase">
<Setter Property="Margin" Value="40,0,0,0"/>
</Style>
</dx:DXWindow.Resources>
.
.
<dxnb:NavBarItem Content="Source Group"
ImageSource="Images/Icons/Group.png"
VisualStyle="{StaticResource nestedNavBarItemL1}"/>
.
.
However, this is fine if the controls are already created but I'm building up the controls through code using something similar to
NavBarGroup group1 = new NavBarGroup();
group1.Header = eventItems[i].name;
group1.Tag = eventItems[i].id;
for (int i = 0; i < nodeCount; i++)
{
NavBarItem item = new NavBarItem();
item.Content = "Home";
item.Tag = "Level" + i;
//item.VisualStyle = ? How do I set VisualStyle="{StaticResource nestedNavBarItemL1}"/>
group1.Items.Add(item);
}
group1.IsExpanded = false;
navBarControl.Groups.Add(group1);
How do I set VisualStyle="{StaticResource nestedNavBarItemL1}" in code?
Thank you,
O
If you already have style defined in resources, you could use FindResource method to get it and then assign to the relevant property like this (window is where resource defined):
Style visualStyle = (Style)window.FindResource("nestedNavBarItemL1");
item.VisualStyle = visualStyle;
If you don't you can create it as shown in this codeproject article.
Define the style in app.xaml then you can access it with Application.Current.Resources["YourDefinedStyle"] as Style within your application.
ex:
item.VisualStyle = Resources["YourStyle"] as Style

Add Items to ListBox and Style

I have a simple class:
public class Foo
{
public string Text { get; set; }
public bool AppleStyle { get; set; }
public Foo(string text, bool applyStyle)
{
Text = text;
ApplyStyle = applyStyle;
}
public override string ToString()
{
return Text;
}
}
Which is then used to add items to a ListBox:
var one = new Foo("Some Text", false);
var two = new Foo("More Text", true);
MyListBox.Items.Add(one);
MyListBox.Items.Add(two);
I then loop through the items in the ListBox to figure out how to style them. This is where I get stuck. I tried inheriting from ListBoxItem for the class, but no items get added if I do that.
for (int i = 0; i < MyListBox.Items.Count; i++)
{
if(((Foo)MyListBox.Items[i]).ApplyStyle)
{
((ListBoxItem)MyListBox.Items[i]).Style = Resources["MyStyle"] as Style;
}
}
Update:
In MainWindow.xaml:
<Window.Resources>
<Style x:Key="MyStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</Window.Resources>
Update 3:
Making some progress, just need to know how to refresh the styles (after clicking on a button). Plus if Resource is not in MainWindow.xaml, would it then look in App.xaml before returning null?
MainWindow.xaml
<Window...>
<Window.Resources>
<Style x:Key="MyClass" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
<myapp:MyListItemStyleSelector x:Key="MyListItemStyleSelector" />
</Window.Resources>
<Grid>
...
<ListBox .... ItemContainerStyleSelector="{StaticResource: MyListItemStyleSelector}" />
...
</Grid>
</Window>
MyListItemStyleSelector.cs
public class MyListItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container);
int index = ic.ItemContainerGenerator.IndexFromContainer(container);
Style applyStyle = null;
var data = item as Foo;
if (data != null && data.ApplyStyle)
{
applyStyle = ic.TryFindResource("MyStyle") as Style;
}
return applyStyle;
}
}
I think you have some sort of mixup here, i try to explain as good as i can.
First of all You usually never need to change the Style in code, like your last code block.
One thing that is difficult to understand in the beginning is the use of a ItemContainerStyle and DataTemplate.
I would suggest that you do the following.
Instead of changing the style off your ListBoxItem see if it is sufficient to use a DataTemplate. The DataTemplate defines how the Content of your ListBoxItem is shown.
<DataTemplate TargetType="{x:Type Foo}">
<!-- your visuals and controls here -->
</DataTemplate>
Now if you want to use different datatemplates you could use different classes and create different DataTemplates for them, or you use a DataTemplateSelector
public class FooTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
var mdl = item as Foo;
if( mdl.AppleStyle )
return element.FindResource("appleTemplate") as DataTemplate;
return element.FindResource("normalTemplate") as DataTemplate;
}
}
Create that templateselector in xaml and reference it in your listbox
<myNs:FooTemplateSelector x:Key="fooTemplateSelector"/>
<Listbox DataTemplateSelector="{StaticResource fooTemplateSelector}"/>
now you need to create 2 DataTemplates appleTemplate *normalTemplate* and you can easyl distinguish which data template to use vial the selector. Which is done automatically in the ListBox for you.
If you really want to change the Style of the ItemContainer you can use ItemContainerStyleSelector which works similar to the DataTemplateSelector. But i would not suggest it. You should supply the content and leave the ListBoxItem as it is, only if you want to modify the design(in this case, the selection color etc.), otherwise it might confuse the user or break functionality.
If you add data-objects directly to the ListBox the container-items will be generated automatically, you cannot get them this way.
Use the ItemContainerGenerator:
((ListBoxItem)MyListBox.ItemContainerGenerator.ContainerFromIndex(i)).Style = Resources["MyStyle"] as Style;
Why not do this in the XAML?
<ListBox Name="MyListBox">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding ApplyStyle}" Value="True">
<Setter Property="Background" Value="Bisque" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
But your overall problem is that ListBox.Items returns a collection of data objects, not XAML Controls. To get the XAML control that contains the Data Object you have to do as H.B. suggested and use MyListBox.ItemContainerGenerator.ContainerFromItem(dataObject) to get the XAML Container for the data object. Just be sure you wait until after the ItemContainerGenerator has finished rendering items to get the container (I believe it has a Status property or StatusChanged event you can use... it's been a while and I can't remember the exact syntax)

Categories