How to use Windows 10 style resource in WPF with XAML Islands - c#

I'm using XAML Islands to make my app and I want to use Windows 10 styling in my WPF app like here. For example <TextBlock Text="Header" Style="{StaticResource HeaderTextBlockStyle}"/> would result in:
But this doesn't work in WPF (It does work in UWP without any modifications), my understanding is that XAML Islands should make it possible. When I try to simply add the code above to my xaml file I get the exception
Cannot find resource named 'HeaderTextBlockStyle'. Resource names are case sensitive.
I get the same exception if I add Style="{StaticResource HeaderTextBlockStyle}" to a <xamlhost:WindowsXamlHost> element.
So I tried to add the controls with code so I added this WindowsXamlHost control as a stackpanel:
<xamlhost:WindowsXamlHost InitialTypeName="Windows.UI.Xaml.Controls.StackPanel" ChildChanged="WindowsXamlHost_ChildChanged"/>
And added this method (an event handler that is ran when the control is made. Learned it from this) that handles adding additional controls (a TextBlock) to the StackPanel:
private void WindowsXamlHost_ChildChanged(object sender, EventArgs e)
{
// Get the host control
WindowsXamlHost host = (WindowsXamlHost)sender;
// Get the StackPanel in the host
Windows.UI.Xaml.Controls.StackPanel sp = (Windows.UI.Xaml.Controls.StackPanel)host.Child;
// Make a TextBlock to add to the StackPanel
Windows.UI.Xaml.Controls.TextBlock textBlock = new Windows.UI.Xaml.Controls.TextBlock();
// Set the text of the TextBlock
textBlock.Text = "LockCursorInMonitor";
// Get the style resources, cast them to the appropriate type for XAML Islands and add them to the TextBlock
textBlock.Style = (Windows.UI.Xaml.Style)Application.Current.Resources["HeaderTextBlockStyle"];
// Another way to get resources but this doesn't work too.
//textBlock.Style = (Windows.UI.Xaml.Style)this.FindResource("HeaderTextBlockStyle");
// Add the TextBlock to the stackpanel
sp.Children.Add(textBlock);
}
The Application.Current.Resources["HeaderTextBlockStyle"] way does nothing and doesn't throw an exception.
The this.FindResource("HeaderTextBlockStyle") way throws the next exception:
System.Windows.ResourceReferenceKeyNotFoundException: ''HeaderTextBlockStyle' resource not found.'
So how can I get these style resources in my WPF app?

One way to achieve this is to use the package ModernWPF but then you lose all the benefits of XAML Islands (if there are any. Everything I needed from XAML Islands is in ModernWPF and is easier to implement).
After installing and setting ModernWPF up you can simply use the <TextBlock Text="Header" Style="{StaticResource HeaderTextBlockStyle}"/> way and it just works.

Related

WPF complex binding for custom control with sub-class as settings

Right now I am trying to implement a custom control (which is of course way more complex than the demo solution I attached), and I kind of failed at passing a value down via binding.
First of all, the structure of the control:
Control (this is basically a wrapper which passes down properties and handles common functionalities)
Settings (this is a dependency property of the control and is a custom class as well)
Text (this is a dependency property of the settings class)
_renderer (this is a private field of the control which is responsible for rendering the control => in my real control it's just rendering a part of it, but for this example it's enough to just do it like that).
The goal of this is to pass the text from a control like a textbox or something down to the renderer which gets initialized with a reference to the settings.
The XAML which uses the control is written as follows:
<TextBox Text="Initial Text"
x:Name="TextSource"
Grid.Row="0" />
<local:CustomControl Grid.Row="1">
<local:CustomControl.Settings>
<local:CustomControlSettings Text="{Binding Path=Text, ElementName=TextSource, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</local:CustomControl.Settings>
</local:CustomControl>
When I use the same XAML, but give the settings a fixed value for the "Text" then everything works as expected, but as soon as I change it to a binding, I don't even get the initial value any more.
Code with is passing down the text:
Passing the settings to the renderer
private void OnLoaded(object sender, RoutedEventArgs e)
{
_renderer = new ControlRenderer();
_renderer.Initialize(_renderArea, Settings);
}
binding the settings text to the renderers internal text dependency property
SetBinding(TextProperty, new Binding{Path = new PropertyPath(CustomControlSettings.TextProperty), Source = settings});
Note: you can uncomment this without any effect, so this should not be the problem if you ask me.
And hereĀ“s a link to the demo solution I created.
After four hours of pain, later I found the solution. The problem is that the settings-object is not a part of the visual tree and therefore the dependency properties are not resolved.
So to be able to do things like this you need to add the settings to the visual tree. I did that by adding it to the canvas children inside of the CustomControl.

How to get an icon in stackPanel in a XAML file

I am new to XAML and C#
I have an icon created already in a project and and I have to use this icon whenever I select one of the option from the dropdown menu.
I made a stackpanel in XAML file
<StackPanel Name="stackPanelforIcon">
</StackPanel>
In the code behind file I have different cases for the dropdown menu.
case IconOnSelect:
?????? = IconList.NewIcon;
This NewIcon is the one already created and I am using the source also for this
using IconProject.Iconlists;
On writing IconList.NewIcon I am not getting any error, it is referenced correctly.
What should I write at ?????? to reference it. Is there any other way apart from using stackPanel to include an icon
A StackPanel cannot show an icon on it's own. You need a control for it, for example an Image.
<StackPanel Name="stackPanelforIcon">
<Image x:Name=theImage" />
</StackPanel>
Then you can use your Icon in your code behind like this:
this.theImage.Source = IconList.NewIcon;
You may need to convert your value, you never said what type it actually is.
Please note that using code-behind is not the preferred way with WPF. Using MVVM is way easier and more natural working with WPF, using code-behind you will fight WPF all the way. Using MVVM, this could be:
<StackPanel Name="stackPanelforIcon">
<Image Source="{Binding CurrentImage}" />
</StackPanel>
with your ViewModel having a property called CurrentImage that you would set when you want to change it. Don't forget to implement INotifyPropertyChanged for the changes to take effect though.

why content template of button does not have object?

i am just exploring windows phone runtime apps template. But i am seeing a weird thing.
I have Button defined in Xaml with ContentTemplate set in it. I wanted extract the Image control defined in the ContentTemplate of this button. But it is coming null.
Xaml code :-
<Button x:Name="PlayButton" Click="PlayButton_OnClick">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Name="Panel">
<Image x:Name="ControlImg"
Width="100"
/>
<TextBlock Text="text block" />
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
Here is button Click event :-
private async void PlayButton_OnClick(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
var ct = btn.ContentTemplate; // this part is also not showing controls in it when expending ct at runtime.
var img = btn.FindName("ControlImg") as Image; // coming null
var stckpnl = btn.FindName("Panel") as StackPanel;// coming null
}
Can anybody check this out why is this happening ?
Edit :- I have broken my problem and reach this very bottom simple level and after seeing this i am just not getting why is this happening ?
That is strange behavior. It should have stack Panel and image in control template. As a work around you can use ContentTemplateRoot to get the image and stackpanel. I have test this, it is working.
((StackPanel)btn.ContentTemplateRoot).Children[0] // image
Hope this helps
Edit:
For Details about why FindName is not working see the the Remarks section on on MSDN
. Here is some relevant quotes
Important In order to use the FindName method effectively, you should understand the concept of a XAML namescope, and how a XAML namescope is created at XAML load time and then referenced and possibly modified at run time. For more info see XAML namescopes.
The most common usage of FindName in your Windows Runtime code will be from within the generated InitializeComponent call for a XAML page. In this situation, FindName is invoked only after the XAML page is loaded. InitializeComponent provides the infrastructure such that any object that was instantiated by XAML loading can conveniently be accessed by your code-behind code. You can then reference the objects as a variable that shares the same name as the markup-declared x:Name.
A run-time API such as FindName is working against a run-time object tree of the app as it exists in memory. When part of this object tree is created from templates or run-time loaded XAML, a XAML namescope is typically not contiguous within that object tree. The result is that there might be a named object in the object tree that a given FindName scope cannot find. The discontinuities between XAML namescopes that you might encounter in typical application scenarios are when objects are created by applying a template, or when objects are created by a call to XamlReader.Load and subsequently added to the object tree.
As you are using DataTemplate so the xaml object tree is not contiguous so that is why FindName is failed to find the control from the xaml tree.
hope this explains...

Using RichTextBlock in FlipView in Metro Style App

I am using standard Visual Studio templates and I have a ItemsDetailPage that contains a FlipView with a RichTextBlock in its DataTemplate.
I want to set the RichTextBlock block to my custom Paragraphs generated in text. I think there is no way to bind RichTextBlocks Block in XAML so I am using code behind. In the Loaded event of RichTextBlock I set its Block, that works ok. But the problem is, the Loaded event gets called only once when the page is displayed. When I "flip" to another item, the selected item of the FlipView changes but the Loaded event does not get called again (I think this is ok).
I tried setting the RichTextBlock in the FlipViews SelectionChanged item but that does not work.
var ind = this.flipView.SelectedIndex;
var flipViewItem = this.flipView.ItemContainerGenerator.ContainerFromIndex(flipView.SelectedIndex);
if (flipViewItem != null)
{
var scroller = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
var tb = scroller.FindDescendantByName("richTextColumns").FindDescendantByName("richTextBlock") as RichTextBlock;
SetRichContent(tb, (flipView.SelectedItem as ArticleViewModel).HtmlContent);
}
The SetRichContent gets called, sets the RichTextBlocks Blocks but visually they do not change and after a few flips, the whole app crashes without any additional information.
So my question is, how do I get my own code called on the RichTextBlock with each flip (seleced item change)?
You can bind rich text boxes. Make sure your data context is set properly. We need to see more code to make an appropriate answer.
<RichTextColumns>
<RichTextColumns.ColumnTemplate>
<DataTemplate>
<RichTextBlockOverflow Width="400" Margin="50,0,0,0"/>
</DataTemplate>
</RichTextColumns.ColumnTemplate>
<RichTextBlock Width="400">
<Paragraph>
<Run Text="{Binding Content}"/>
</Paragraph>
</RichTextBlock>
</RichTextColumns>

Change background colour of TextBlock in C#

Currently porting an application to Windows Phone 7 I've encountered a problem that should be trivial
All I want is change the background colour of a TextBlock.
Using the WYSIWYG I can easily create a TextBlock, change the foreground and background colour.
So for a TextBlock using white text on black background I would use:
<TextBox Height="148" HorizontalAlignment="Left" Margin="106,0,0,0" Name="textBox1" Text="TextBox" VerticalAlignment="Top" Width="460" Background="Black" BorderBrush="Black" Foreground="White" />
But I need to do it in code (C#) and the Background doesn't appear to be a property of TextBlock.
How come it's something you can do using the resource editor, but not in code?
I've found various similar questions, but no definitive answer.
In Microsoft documentation (.Net), TextBlock does appear to have a Background property
Is there a way to do this in code without having to put the TextBlock inside a container (like Grid) which does have the Background property?
Thanks
JY
TextBlock is not inherited from Control, it doesn't have a Background property. The code you are showing is a TextBox not a TextBlock. TextBox inherites from Control and has a Background property. The simplest way is to wrap it with a Panel, or you can create a custom control for it.
Also, in silverilght sdk, you have a control called Label and it is inherited from Control. You can probably get the source code from there and implement it in your project.

Categories