I want to produce in code the equivalent of this in XAML:
<TextBlock
Text="Title:"
Width="{Binding FormLabelColumnWidth}"
Style="{DynamicResource FormLabelStyle}"/>
I can do the text and the width, but how do I assign the dynamic resource to the style:
TextBlock tb = new TextBlock();
tb.Text = "Title:";
tb.Width = FormLabelColumnWidth;
tb.Style = ???
You should use FrameworkElement.SetResourceReference if you want true DynamicResource behaviour - ie updating of the target element when the resource changes.
tb.SetResourceReference(Control.StyleProperty, "FormLabelStyle")
You can try:
tb.Style = (Style)FindResource("FormLabelStyle");
Enjoy!
The original question was how to make it Dynamic, which means if the resource changes the control will update. The best answer above used SetResourceReference. For the Xamarin framework this is not available but SetDynamicResource is and it does exactly what the original poster was asking. Simple example
Label title = new Label();
title.Text = "Title";
title.SetDynamicResource(Label.TextColorProperty, "textColor");
title.SetDynamicResource(Label.BackgroundColorProperty, "backgroundColor");
Now calling:
App.Current.Resources["textColor"] = Color.AliceBlue;
App.Current.Resources["backgroundColor"] = Color.BlueViolet;
Causes the properties to change for all controls using the resource this way. This should work for any property.
This should work:
tb.SetValue(Control.StyleProperty, "FormLabelStyle");
Application.Current.Resources.TryGetValue("ResourceKey", out var value)
Related
I need too add some control unit such as Grid, Checkbox ,Textblock and ... dynamically in my C# Code.
Assume XAML node like:
<CheckBox Content="CheckBox" Height="24" Click="CheckBoxes_Click"/>
Its C# equivalent is
AddNewCheckBox()
{
CheckBox NewCheckBox = new CheckBox ();
NewCheckBox.Content = "CheckBox1";
NewCheckBox.Height = 24;
NewCheckBox.Click += CheckBoxes_Click;
}
But there are many XAML assignment which it is hard to understand their C# equivalent.
As an example what should I write in my c# to create a CheckBox like this?
<CheckBox Content="CheckBox" Margin="68,41,0,0" Background="Black"
Height="Auto" Click="CheckBoxes_Click"/>
Is there any way to understand how XAML parser maps phrases to C# code?
Is there any way to understand how XAML parser maps phrases to C# code?
Looking at this example:
<CheckBox Content="CheckBox"
Margin="68,41,0,0"
Background="Black"
Height="Auto"
Click="CheckBoxes_Click"/>
If we want to understand how the XAML parser knows how to set more complicated properties (ones that cannot simply use the TryParse() methods of the types) we need to look at the types of the properties.
If you look at the Margin property for example it is of type Thickness and if you look at that type you will find this attribute:
[TypeConverter(typeof(ThicknessConverter))]
If you look at that type (in PresentationFramework.dll) with for example dotPeek you will find ConvertFrom(...) and ConvertTo(...) methods that take care of the conversion. The internal method FromString(...) contains the relevant parts for this example.
To create checkbox like that you should write it like this:
AddNewCheckBox()
{
CheckBox NewCheckBox = new CheckBox ();
NewCheckBox.Content = "CheckBox1";
NewCheckBox.Height = 24;
NewCheckBox.Click += NewCheckBox_Click;
NewCheckBox.Margin = new Thickness(64, 41, 0, 0);
NewCheckBox.Background = new SolidColorBrush(Color.Black);
//or like this: NewCheckBox.Background = Brushes.Black;
}
what should I write in my c# to create a check box like this?
<CheckBox Content="CheckBox"
Margin="68,41,0,0"
Background="Black"
Height="Auto"
Click="CheckBoxes_Click"/>
The above equates to
var checkBox = new CheckBox () {
Content = "CheckBox",
Margin = new Thickness(64, 41, 0, 0),
Background = Brushes.Black,
Height = Double.NaN
};
checkBox.Click += CheckBoxes_Click
As an example what should I write in my c# to create a CheckBox like this?
The same more or less. Each attribute in XAML maps to a property in C#. So the equivalent would be:
CheckBox checkBox = new CheckBox();
checkBox.Content = "CheckBox";
checkBox.Margin = new Thickness(68,41,0,0);
checkBox.Background = Brushes.Black;
checkBox.Click += CheckBoxes_Click;
The type of the Background property is Brush. And the type of the Margin property is Thickness. You can confirm this by looking at the documentation on MSDN.
The XAML processor is able to translate the string "Black" to a Brush and the value "68,41,0,0" to a Thickness for you. The C# compiler is not. Apart from this, you are setting the exact same properties of the exact same class.
I working on Xamarin project and made custom renderer for my custom control in UWP project. I found how to set the ControlTemplate by using xml code.
XML Way:
var tb = new TextBox(); // or what I do in Xamarin var tb = Control;
var ct = (Controls.ControlTemplate)XamlReader.Load(#"
<ControlTemplate TargetType=""TextBox"" xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Grid>
....
</Grid>
</ControlTemplate>");
tb.Template = ct;
But how I can do the same in code?
var tb = new TextBox(); // or what I do in Xamarin var tb = Control;
var ct = new ControlTemplate();
ct.TargetType = typeof(TextBox);
var grid = new Grid();
ct.VisualTree = grid // This is how it was done in wpf but there is no such option in UWP
tb.Template = ct;
It's not supported in UWP, and I previously found no way to directly set it. As per the MS docs.
ControlTemplate: this is used as the value of the Control.Template
property, which defines the visuals of a control by applying the
template. You almost always define a ControlTemplate as a XAML
resource, using an implicit key TargetType that is the same as a Style
that sets Control.Template with a Setter. You rarely if ever assign a
value for Control.Template directly on a control instance.
Besides possibly delving into reflection, or using the XAMLReader as per your first example, I have never found another way to do it, like you do in WPF.
I used the following code to create data template items:
FrameworkElementFactory textCtrl = new FrameworkElementFactory(typeof(TextBox));
Binding binding1 = new Binding();
string path = "Syncfusion";
binding1.Path = new PropertyPath(path);
textCtrl.SetValue(TextBox.TextProperty,binding1);
Binding binding2 = new Binding();
string path2 = "Text1";
binding2.Path = new PropertyPath(path2);
textCtrl.SetValue(TextBox.NameProperty, binding2);
DataTemplate dt = new DataTemplate();
dt.VisualTree = textCtrl;
How to get the text box from the data template..?
I tried the following links
Link 1
Link 2
But I did not get the things correctly...
I used the below code in xaml
<DataTemplate>
<TextBlock Text="{Binding CellBoundValue}" gridcommon:VisualContainer.WantsMouseInput="False"/>
</DataTemplate>
Can anyone help me on this?
As far as I know, Microsoft does not recommend to use the FrameworkElementFactory, it may get deprecated some times (not sure about this).
But if you want to do it anyway, you must apply your DataTemplate to create instances of controls declared in the DataTemplate. You can do this for example with a ContentControl or an ItemsControl.
I know how to create a dynamic control in c#:
TextBlock tb = new TextBlock();
tb.Text = "This is a new textblock";
But how would I reference this newly created control through code?
I browsed the net for a solution, and came across this code:
TextBlock tb = (TextBlock)this.FindName("TB");
tb.Text = "Text property changed";
Every time I create a new control with a name I get an exception:
TextBlock tb = new TextBlock();
tb.Text = "This is a new textblock";
tb.Name = "TB";
"The parameter is incorrect."
What am I doing wrong? Any help would be greatly appreciated.
Thanks in advance.
The Exception "The parameter is incorrect." may be occurring because of the duplicate names of the controls created.
For the dynamic control part : you must be adding that control to some Grid or Stackpanel or something. you can reference that dynamic control by getting the content or children of the parent control.
Like :
TextBlock Tb= new TextBlock();
tb.Text = "Hello";
ContentPanel.Children.Add(Tb);
//to reference :
var content = ContentPanel.Children;
foreach(UIElement uiElem in content)
{
if(uiElem.GetType() == typeof(TextBlock))
{
TextBlock tb = uiElem as TextBlock;
tb.Text = "Hyee";
}
}
Hope, it might help.
(Note: I have written this code directly here and not copied from VS, so please check syntax and spellings.)
Yes you can use reference dynamic controls this way.
But another way is that you can also keep a list of the references when you create the controls.
I know that TextBlock can present a FlowDocument, for example:
<TextBlock Name="txtFont">
<Run Foreground="Maroon" FontFamily="Courier New" FontSize="24">Courier New 24</Run>
</TextBlock>
I would like to know how to set a FlowDocument that is stored in a variable to a TextBlock.
I am looking for something like:
string text = "<Run Foreground="Maroon" FontFamily="Courier New" FontSize="24">Courier New 24</Run>"
txtFont.Text = text;
However, The result of the code above is that the XAML text is presented unparsed.
EDIT: I guess my question was not clear enough. What I'm really trying to achive is:
The user input some text into a RichTextBox.
The application saves the user input as FlowDocument from the RichTextBox, and serializes it to the disk.
The FlowDocument is deserialized from the disk to the variable text.
Now, I would like to be able to present the user text in a TextBlock.
Therefore, as far as I understand, creating a new Run object and setting the parameters manually will not solve my problem.
The problem is that serializing RichTextBox creates Section object, which I cannot add to TextBlock.Inlines. Therefore, it is not possible to set the deserialized object to TextProperty of TextBlock.
create and add the object as below:
Run run = new Run("Courier New 24");
run.Foreground = new SolidColorBrush(Colors.Maroon);
run.FontFamily = new FontFamily("Courier New");
run.FontSize = 24;
txtFont.Inlines.Add(run);
I know that TextBlock can present FlowDocument
What makes you think that ? I don't think it's true... The content of a TextBlock is the Inlines property, which is an InlineCollection. So it can only contain Inlines... But in a FlowDocument, the content is the Blocks property, which contains instances of Block. And a Block is not an Inline
If your FlowDocument has been deserialized, it means that you have an object of type FlowDocument, right? Try setting the Text property of your TextBlock to this value. Of course, you cannot do this with txtFont.Text = ..., since this only works for strings. For other types of objects, you need to set the DependencyProperty directly:
txtFont.SetValue(TextBlock.TextProperty, myFlowDocument)
Here is how we are setting the look of a textblock by assigning a style on-the-fly.
// Set Weight (Property setting is a string like "Bold")
FontWeight thisWeight = (FontWeight)new FontWeightConverter().ConvertFromString(Properties.Settings.Default.DealerMessageFontWeightValue);
// Set Color (Property setting is a string like "Red" or "Black")
SolidColorBrush thisColor = (SolidColorBrush)new BrushConverter().ConvertFromString(Properties.Settings.Default.DealerMessageFontColorValue);
// Set the style for the dealer message
// Font Family Property setting is a string like "Arial"
// Font Size Property setting is an int like 12, a double would also work
Style newStyle = new Style
{
TargetType = typeof(TextBlock),
Setters = {
new Setter
{
Property = Control.FontFamilyProperty,
Value = new FontFamily(Properties.Settings.Default.DealerMessageFontValue)
},
new Setter
{
Property = Control.FontSizeProperty,
Value = Properties.Settings.Default.DealerMessageFontSizeValue
},
new Setter
{
Property = Control.FontWeightProperty,
Value = thisWeight
},
new Setter
{
Property = Control.ForegroundProperty,
Value = thisColor
}
}
};
textBlock_DealerMessage.Style = newStyle;
You can eliminate the style section and set properties directly, but we like keeping things bundled in the style to help us organize the look throughout the project.
textBlock_DealerMessage.FontWeight = thisWeight;
HTH.