Adding Style property to UserControl - c#

I am having difficulties in adding Style property to a UserControl. There is a parser exception when I try to view the consumer page.
private Style _headerStyle = new Style();
public Style HeaderStyle
{
get { return _headerStyle ; }
set
{
_headerStyle .CopyFrom(value);
}
}
Usage:
Style="border: 1px solid blue;"
Error:
Cannot create an object of type 'System.Web.UI.WebControls.Style' from its string representation ...

A Style instance is not a string and vice-versa. Style.CopyFrom expects a Style as argument and you're passing a String. That's the reason why it cannot be copied to the new style object.
If you want to give your UserControl a border programmatically:
myControl.HeaderStyle.BorderStyle = BorderStyle.Solid;
myControl.HeaderStyle.BorderWidth = new Unit(1);
myControl.HeaderStyle.BorderColor = System.Drawing.Color.Blue;

You'r trying to create an ASP.NET Style but declaring a CSS Style, that's the problem. If you want to apply an ASP.NET style you need to call the ApplyStyle method instead:
control.ApplyStyle(styleName);

Related

How to Set Parent Panel Alignment of The Control Programmatically?

Background:
I have created a helper method to set properties of each TextBlockas per its adjacent TextBox for some scenarios in my application. In this method I already have the TextBlock object, the TextBox object and the parent object (it's always RelativePanel in my case).
The RelativePanel in my views always contain only TextBox & TextBlock.
// Helper Method
public static void SetPropertiesOfEachTextBlock(IList<TextBox> boxes)
{
foreach (TextBox textBox in boxes)
{
var parent = VisualTreeHelper.GetParent(textBox) as RelativePanel;
foreach(var element in parent.Children)
{
if(element is TextBlock)
{
TextBlock textBlock = (TextBlock)element;
textBlock.FontSize = textBox.FontSize;
textBlock.Margin = textBox.Margin;
textBlock.FontWeight = textBox.FontWeight;
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
// Here I need to set alignment to the adjacent TextBox by the RelativePanel
}
}
}
}
Relative Panel Sample:
<RelativePanel>
<TextBox Name="UserName"/>
<TextBlock RelativePanel.AlignLeftWith="UserName" />
</RelativePanel>
Question:
How can I set the following property of TextBlock programmatically:
RelativePanel.AlignLeftWith="UserName"
AlignLeft is an Attached Property and can be found on RelativePanel itself. You set them like this:
RelativePanel.SetAlignLeftWith(element, UserName);
You can read the docs on the property here:
Edit: fixed syntax error based on comment

Can't find element that should exist?

I am adding tabs to my tab control through code:
TabItem tab = new TabItem();
var stack = new StackPanel() { Orientation = Orientation.Horizontal };
stack.Children.Add(new TextBlock() { Text = header });
stack.Children.Add(new TextBlock() { Name = "extra" });
tab.Header = stack;
tabControl.Items.Add(tab);
As you can see, it creates the header of the tabItem with a stack panel. It adds two text blocks; one of which is empty, but I've assigned the name "extra". What I would like to do is, later in the code, edit the textBlock named "extra" and add some new text to it.
How would I find and edit this element? I have tried the following code, but its producing an error saying the element can not be found:
object test = Application.Current.FindResource("extra");
FindName is what you are looking for but your TextBlock is not in the correct WPF Namescope.
MSDN states:
If you add an object to an object tree at a point in time after the XAML that produced that tree was parsed, a Name or x:Name value on the new object does not automatically update the information in a XAML namescope. To add a name for an object into a WPF XAML namescope after XAML is loaded, must call the appropriate implementation of RegisterName on the object that defines the XAML namescope.
For example:
var textBlock = new TextBlock() { Name = "extra" };
stack.Children.Add(textBlock );
RegisterName(textBlock);
...
TextBlock textBlock = FindName("extra") as TextBlock;
Finally, Application.Current.FindResource("extra") is returning null because the element does not exist when project resources are created. More on FindResource.
Just use FrameworkElement.FindName method:
var control = tab.FindName("extra");
if(control is TextBlock){
// your logic here
}
You don't need Application.Current.Resource dictionary here because it's different collection. If you want to use it then you should put user controls within Resource dictionary beforehand.
Because you are trying to find resource with the key "extra". It's wrong.
Try this:
TabItem tab = new TabItem();
var stack = new StackPanel() { Orientation = Orientation.Horizontal };
var textBlock = new TextBlock() { Name = "extra" }
stack.Children.Add(new TextBlock() { Text = header });
stack.Children.Add(textBlock);
tab.Header = stack;
tabControl.Items.Add(tab);
Now you can reach it with textBlock instance.
Here's some VB WPF code for what you need
Dim test As TextBlock
test = DirectCast(FindName("extra"), TextBlock)
I have no idea if it will work like that in C# WPF although if that doesn't work try looking up CType

How can I bind to the property of a class from the codebehind?

In my XAML I have this:
<TextBlock Text="{Binding Stats.Scores.Team}" Style="{StaticResource Column_Value_Large}" />
I need to be able to create that TextBlock, in it's entirety, in the codebehind. Here's what I have:
foreach (var Stats in player){
var columnHeaderScore = new TextBlock
{
Style = Application.Current.Resources["Column_Value_Large"] as Style,
};
columnHeaderScore.SetBinding(TextBlock.TextProperty, new Binding
{
Path = new PropertyPath("Stats.Scores.Team"),
});
columnHeaderStackPanel.Children.Add(columnHeaderScore);
}
However, the binding doesn't seem to be working. What's the appropriate way to set the binding in the codebehind?
Edit for context: my goal is to generate a bunch of these text boxes inside a big loop in the codebehind. See my revised example above which now shows the loop. Since I want to do it this way, I don't think there's any possible way for me to do it in the XAML; I would have to set the binding in the codebehind.
I think you use xaml in a wrong way. Why dont you set theTextBlockin the XAML code and bind itsVisibilityto a property or use aStyle. Then you dont have to create the binding in the codebehind.
EDIT: Why don't you use a ItemPanel or something like that to which you bind your collection and give it a DataTemplate which displays the TextBoxes?
I got it.
My problem was using "Path" in SetBinding instead of "Source". The working code looks like this:
foreach (var Stats in player){
var columnHeaderScore = new TextBlock
{
Style = Application.Current.Resources["Column_Value_Large"] as Style,
};
columnHeaderScore.SetBinding(TextBlock.TextProperty, new Binding
{
Source = Stats.Scores.Team,
});
columnHeaderStackPanel.Children.Add(columnHeaderScore);
}

Can't apply style in WPF via C# code

I've discovered what the problem was, It is nothing to do with the C# code itself, But it's in the XAML instead, The issue was the default colors that I've set in the XAML were overriding my style's colors.
So in conclusion, when you are setting any property by XAML it always overrides later styles set by C# code at runtime, this seems strange to me but at least that is how it worked for me.
The default Background colors in the XAML code avoided the C#'s style to apply on the panels (At-least avoided the new Background to be applied over the default ones).
I used your code and modified little bit for verification. Seems to be working fine. Have a look:
Style Style_Panel = new Style(typeof(Panel));
public void Init_Style()
{
// Create Styles :
#region "Create Styles"
Style_Panel.Setters.Add(new Setter()
{
Property = Panel.BackgroundProperty,
Value = new SolidColorBrush(Colors.Red)
});
Resources.Add(Style_Panel.TargetType, Style_Panel);
#endregion
// Apply Styles :
#region "Apply Styles"
List<Visual> List_Visual = new List<Visual>();
List_Visual.Add(new StackPanel() { Name = "btn" });
//Enum_Visual(Panel_Main, List_Visual);
foreach (Visual visual in List_Visual)
{
if (visual is Panel)
{
Panel panel = visual as Panel;
//if (Tagged(panel, "titlebar"))
//{
//}
//else if (Tagged(panel) == false)
{
// panel.Background = new SolidColorBrush( Colors.Red ); // <- WORKS .
panel.Style = Style_Panel; // <- DOES NOT WORKS !
}
}
}
#endregion
}
You haven't posted the creation of your style, maybe something is missing there?
There is another similar answer on StackOverflow which is a very good and short example of creating and setting a style in code:
Q: Does anyone know how to create a wpf Style in code behind, I can't find anything on the web or MSDN docs. I have tried this but it is not working:
A: You need to add setters to the style rather than using RegisterName. The following code, in the Window_Loaded event, will create a new TextBlock style which will become the default for all instances of a TextBlock within the Window. If you'd rather set it explicitly on one particular TextBlock, you can set the Style property of that control rather than adding the style to the Resources dictionary.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Style style = new Style(typeof (TextBlock));
style.Setters.Add(new Setter(TextBlock.ForegroundProperty, Brushes.Green));
style.Setters.Add(new Setter(TextBlock.TextProperty, "Green"));
Resources.Add(typeof (TextBlock), style);
}

Creating a Style in code behind

Does anyone know how to create a wpf Style in code behind, I can't find anything on the web or MSDN docs. I have tried this but it is not working:
Style s = new Style(typeof(TextBlock));
s.RegisterName("Foreground", Brushes.Green);
s.RegisterName("Text", "Green");
breakInfoControl.dataTextBlock.Style = s;
You need to add setters to the style rather than using RegisterName. The following code, in the Window_Loaded event, will create a new TextBlock style which will become the default for all instances of a TextBlock within the Window. If you'd rather set it explicitly on one particular TextBlock, you can set the Style property of that control rather than adding the style to the Resources dictionary.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Style style = new Style(typeof (TextBlock));
style.Setters.Add(new Setter(TextBlock.ForegroundProperty, Brushes.Green));
style.Setters.Add(new Setter(TextBlock.TextProperty, "Green"));
Resources.Add(typeof (TextBlock), style);
}
This should get you what you need:
Style style = new Style
{
TargetType = typeof(Control)
};
style.Setters.Add(new Setter(Control.ForegroundProperty, Brushes.Green));
myControl.Style = style;

Categories