Reputation: 149
I'm looking for a way to assign style with parameters(most of them just text) and assign to specified blocks
<StackPanel Orientation="Horizontal">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="field1" Text="Field1"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field2" Text="Field2"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field3" Text="Field3"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
There is 3 TextBlocks(field1,field2,field3), now is there any way to pass parameters(parameters are string type), to this template, and this template is generated through loop. And how to do it? Of course I could make everything in c# but thought it would be much easier just create field(stackpanel) and assign parameters
<stackpanel Style="{StaticResource mystyle}" param1="hello" param2="this" param3="world"/>
This would be perfect if its possible to make this way. Unless there is better one. Thanks for help.
Upvotes: 3
Views: 2033
Reputation: 48129
You can by declaring your own Styles and Control templates with additional use of DependencyProperties.
A DependencyProperty is basically a declaration on your own custom class of your own custom property that you want to expose available during xaml entry and can also be applied to your style templates.
Once that is done, you then define your style, plenty of resources on that. Include your dependency properties as {TemplateBinding} to your custom properties.
Then add instance of your new class to your form, and specify which style to use. I have a sample showing utilization of TWO styles under the same class. I first started with a brand new WPF application. In the MainWindow.xaml.cs, I defined my own class based on a type of UserControl (which can then hold any other control(s) such as you have nested). I added 3 Dependency Properties to reflect 3 possible text values you want to implement.
public class MyControl : UserControl
{
public static readonly DependencyProperty MyText1Property =
DependencyProperty.Register("MyText1", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText1
{
get { return (string)GetValue(MyText1Property); }
set { SetValue(MyText1Property, value); }
}
public static readonly DependencyProperty MyText2Property =
DependencyProperty.Register("MyText2", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText2
{
get { return (string)GetValue(MyText2Property); }
set { SetValue(MyText2Property, value); }
}
public static readonly DependencyProperty MyText3Property =
DependencyProperty.Register("MyText3", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText3
{
get { return (string)GetValue(MyText3Property); }
set { SetValue(MyText3Property, value); }
}
}
Next, my application name is StackOverflow for sample purposes, and in the following is the entire MainWindow.xaml. Clarification of components follows code.
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding MyText1}"/>
<TextBlock Text="{TemplateBinding MyText2}"/>
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="{TemplateBinding MyText1}"/>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText2}"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- NOW, we can expand the custom properties-->
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
</Window.Resources>
<Grid Height="150">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
</Grid>
At the top within the main declaration, I added
xmlns:myApp="clr-namespace:StackOverflow"
this basically states that when within this xaml file, I see a prefix of "myApp", it is similar to a "using StackOverflow;" command as if in code. So now I have access to the custom class(es) or other things within that namespace to the xaml.
Next I start to declare my own "style" for the custom MyControl class via
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
...
You might want to create a separate ResourceDictionary if you deal with many styles / templates used throughout your app. Notice the "Syle" and custom "ControlTemplate" are based on the "myApp:MyControl" class structure. Now, I can make use of my "MyText1", "MyText2", "MyText3" elements within the control template.
The x:Key="MyControlStyle1" is like creating a variable by given name so it can be used if you need to explicitly say which style to use. This first style is just to show the point that the 3 "MyText" properties are available and the Text is getting its value from the
Text="{TemplateBinding MyText1}"
Class that the control template is bound to (hence TemplateBinding).
Once you get the basics working, then you can glorify your template as you have with your nested stack panels which is the lower
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
declaration by a different x:Key name.
Now, so you don't have to explicitly keep adding xaml for your control and say... by the way, use this explicit style of MyControlStyle, I have the following
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
indicating whenever you see a target type of "MyControl", default the style to the "MyControlStyle" so I don't have to keep remembering to do it.
Finally implementing its use. The end of the code has a simple Grid control with 3 rows.
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
Notice the first instance I CAN explicitly declare the style to be used. The second has no explicit style as per the default, but the third instance explicitly states to use the simplified "MyControlStyle1" which was just the 3 textblocks side-by-side showing that you can have one class and make it look differently as needed.
Revision per questions/comments.
If you are building these controls based on a loop and dynamically adding them, you would just set the properties respectively in the code. Performance should not be significant because the CLASS is already declared, you are just adding one more into your list.
foreach( var oneThing in YourListOfToBeAddedItems )
{
var mc = new MyControl();
mc.MyText1 = oneThing.TextFieldUsedForField1;
mc.MyText2 = oneThing.FieldForSecondText;
mc.MyText3 = oneThing.ThirdTextBasisForDisplay;
// Now, add the "mc" to whatever your control is
// can't confirm this line below as I dont know context
// of your form and dynamic adding.
YourWindowGridOrOtherControl.Controls.Add( mc );
}
Also, since the default style was defined, I would not need to explicitly declare the "Style" for the control.
Upvotes: 4