C# Equivalent code for xaml phrases - c#

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.

Related

How to create buttons/shorcuts dynamically in XAML/C#

I want to create an application where the user can enter shortcuts to files. I know how to create buttons in code at compile time but I have no idea how to create dynamic buttons where the name and the click event are going to be dynamic.
How hard would it be to create something like the image below? Is that even possible in C#/WPF/XAML?
What would be the logic?
FYI - I don't need help with saving the buttons objects, for this I will be using JSON.
You should create an ItemsControl to show what you want, this could be an approach:
<ItemsControl
ItemsSource="{Binding YourListOfLinkObject}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding WhateverYouWantToShow}"
Command="{Binding YourCommand} "
CommandParameter="{Binding YourFileName}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You should create a new (if it's not already created) class with the name of the file, the content you want to show in the button and your command. And when initializing the view, create a list of "Link" object.
The command will be the same for all of them, just declare it in a generic way to open the file you put in the CommandParameter
Now that I know you are using MVVM I will try to expand my answer focus on that.
You need a class that I will call FileLink. FileLink will have, at least, 3 properties:
public string WhateverYouWantToShow - This will be the content of your button
public ICommand YourCommand - This will have a DelegateCommand<string> that will be the one who "does" things. This command will be the same for every item you create. You just need one because you will use the parameter to execute/open one file or another.
public string YourFileName - This will be the string you need to execute your command method. I guess it will be a path or a file name.
Now that we have this class created, when initializing the third view, the one with the buttons, you will have an ObservableCollectionproperty, what I called YourListOfLinkObject, of FileLinkobjects. There you will have to add as many FileLink objects as you got from the database and they will be displayed.
If you need to change the way they are shown you just need to modify the DataTemplate.
If there's something I failed to explain again or you want me to go further just let me know :)
It is possible and simple. You add controls to your container and add container to main form. Click event is simply defined in code (which actually you know at dev time - probably you should instead use user controls).
Below is some partial code, doing a similar thing in a real world Silverlight application from years ago to give the idea:
...
sp.Children.Add(p);
foreach (var slot in group)
{
var color = colors[(int)slot.State];
var name = String.Format("W{0}", slot.When.ToString("yyyyMMddHHmm"));
Rectangle rect = new Rectangle
{
Name = name,
Width = rectWidth,
Height = rectWidth,
Margin = new Thickness(rectMargin),
Stroke = new SolidColorBrush(slot.State == Availability.Booked ? Colors.White : Colors.Black),
StrokeThickness = 1,
Fill = new SolidColorBrush(color),
RadiusX = 2,
RadiusY = 2,
Cursor = (slot.State == Availability.Booked ? Cursors.Arrow : Cursors.Hand)
};
if (slot.State != Availability.Booked)
{
rect.Effect = new DropShadowEffect(); //myDropShadowEffect,
}
if (slot.State != Availability.Booked)
{
rect.MouseLeftButtonDown += new MouseButtonEventHandler(rect_MouseLeftButtonDown);
ToolTipService.SetToolTip(rect, slot.When.ToString("MMM dd,yyyy dddd hh:mm tt"));
}
sp.Children.Add(rect);
}
b.Child = sp;
contentStackPanel.Children.Add(b);
}

How to set the value of ControlTemplate in UWP

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.

How to bind the Image.Source in MVVM correctly?

I spent some time now trying to work this out but I am still stuck on it. I have a WPF application with a MVVM pattern. In my ViewModel I have three cases where:
X needs Y and Y is available
X needs Y and Y is not available
X doesn't need Y
I am trying to set an image icon on my view based on these conditions (Like a Check Mark, exclamation Mark... whatever).
In ViewModel:
I created my properties. On any GUI change, I set the variables based on the above cases similar to the following:
void MyBigFunctionToSetAllProperties()
{
// other cases
// ..
if (NeedsY && YExists)
{
// properties
StatusIconPath = "#\"/Resources/SessionView/X-With-Green-Check-White.png\"";
ResultIconPath = "#\"/Resources/SessionView/Y-White.png\"";
}
}
In View.Cs: I did literally nothing.
In View.xaml: I bind like this:
<StackPanel>
<Image Source="{Binding StatusIconPath} />
</StackPanel>
I still can't see why it is not working. What is that thing that I am missing? Please and thanks.
It did not work to bind the properties directly with the Xaml as recommended. I tried it this way:
VM: sample property:
public BitmapImage VerificationStatusIcon{ get { return new BitmapImage(new Uri(#VerificationStatusIconPath, UriKind.Relative));}}
View Xaml:
<Image Name="verificationStatusImage" Source="{Binding VerificationStatusIcon}" Margin="5,0" Width="40" Height="40"/>
You have a whole bunch of unnecessary characters in your icon paths:
StatusIconPath = "#\"/Resources/SessionView/X-With-Green-Check-White.png\"";
ResultIconPath = "#\"/Resources/SessionView/Y-White.png\"";
Change them to this:
StatusIconPath = "Resources/SessionView/X-With-Green-Check-White.png";
ResultIconPath = "Resources/SessionView/Y-White.png";
. But no images originally to view and no changes..
Verify that the path to the image is correct. Maybe hard code an image to test the control against it.
One other scenario is that the resources are not being copied over for run-time acquisition. Make sure they are actually available during runtime.
can't see why it is not working
Is the main view's DataContext set to the live VM's instance?
What is that thing that I am missing?
If you are sure that the view's datacontext contains the live VM, then make sure that the property StatusIconPath on the VM reports a property change event.
That is so that the XAML control which is bound to it knows that it changed and correspondingly one needs to make sure that the ViewModel which holds StatusIconPath adheres to INotifyPropertyChanged which will facilitate such an operation in general:
private string _StatusIconPath;
public string StatusIconPath
{
get { return _StatusIconPath; }
set
{
_StatusIconPath = value;
PropertyChanged("StatusIconPath");
}
}
I provide more robust example on my blog entitled:
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding
It turned out that I have an extra unneeded characters in my ImagePaths as Kyle stated. And then, I needed to set my Image.Source from within my View.cs. At least, this is how it worked for me:
ViewModel Something like this:
if (Whatever)
{
StatusIconPath = "/Resources/SessionView/X-With-Green-Check-White.png";
ResultIconPath = "/Resources/SessionView/Y-White.png";
}
Then in View.cs and on SelectedItemChanged:
private void Grid_SelectedItemChanged(object sender, DevExpress.Xpf.Grid.SelectedItemChangedEventArgs e)
{
string tempStatus = ((SessionViewModel) DataContext).StatusIconPath;
string tempResult = ((SessionViewModel) DataContext).ResultIconPath;
StatusImage.Source = new BitmapImage(new Uri(#tempStatus, UriKind.Relative));
ResultImage.Source = new BitmapImage(new Uri(#tempResult, UriKind.Relative));
}
and in Xaml: just a fallback value(any original/default image we want). Ex:
<Image Name="ResultImage" Source="/EZ3D;component/Resources/SessionView/Retake-White.png"/>

How to assign a dynamic resource style in code?

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)

Setting WPF text to TextBlock

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.

Categories

Resources