I am unable to make a ContentControl a region using Prism - c#

I'm building a prism application and I've setup the shell with a hamburgermenu from MahApps. Within the content of that Hamburgermenu I would like to have a region.
But when I try to make a region out of a ContentControl within "Hamburgermenu.Content" the region is not added.
However, if I try to make a region out of a ContentControl OUTSIDE the Hamburgermenu-control, it works perfectly.
<Controls:MetroWindow x:Class="SystemCreator.ClientApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SystemCreator.ClientApplication"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:converters="http://metro.mahapps.com/winfx/xaml/shared"
xmlns:prism="http://prismlibrary.com/"
xmlns:inf="clr-namespace:SystemCreator.ClientApplication.Infrastructure;assembly=SystemCreator.ClientApplication.Infrastructure"
xmlns:cdviews="clr-namespace:SystemCreator.CreateDatabase;assembly=SystemCreator.CreateDatabase"
xmlns:test="clr-namespace:TestModule;assembly=TestModule"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="{Binding Title}" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Themes/HamburgerMenuTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="MahApps.Metro.Styles.HamburgerMenu" TargetType="{x:Type Controls:HamburgerMenu}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Focusable" Value="False" />
<Setter Property="HamburgerMenuTemplate">
<Setter.Value>
<DataTemplate>
<!-- PackIconMaterial - Menu -->
<ContentControl Width="22"
Height="22"
Content="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z"
Style="{DynamicResource PathIconContentControlStyle}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="ItemContainerStyle" Value="{StaticResource HamburgerMenuItemStyle}" />
<Setter Property="KeyboardNavigation.ControlTabNavigation" Value="Local" />
<Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Local" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="Local" />
<Setter Property="OptionsItemContainerStyle" Value="{StaticResource HamburgerMenuItemStyle}" />
<Setter Property="PaneBackground" Value="{DynamicResource MahApps.Metro.HamburgerMenu.PaneBackgroundBrush}" />
<Setter Property="PaneForeground" Value="{DynamicResource MahApps.Metro.HamburgerMenu.PaneForegroundBrush}" />
<Setter Property="Template" Value="{StaticResource HamburgerMenuTemplate}" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
<DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type
Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding Icon}"
Focusable="False"
IsTabStop="False" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Controls:HamburgerMenu x:Name="HamburgerMenuControl"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
HamburgerWidth="48"
DisplayMode="CompactInline"
VerticalScrollBarOnLeftSide="False"
ItemTemplate="{StaticResource MenuItemTemplate}"
OptionsItemTemplate="{StaticResource MenuItemTemplate}"
Style="{StaticResource MahApps.Metro.Styles.HamburgerMenu}"
Width="Auto"
>
<Controls:HamburgerMenu.HamburgerMenuHeaderTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Foreground="White"
Text="Menu" />
</DataTemplate>
</Controls:HamburgerMenu.HamburgerMenuHeaderTemplate>
<!--Content-->
<Controls:HamburgerMenu.Content>
<ContentControl prism:RegionManager.RegionName="{x:Static inf:ApplicationConstants.MainContent}" />
</Controls:HamburgerMenu.Content>
</Controls:HamburgerMenu>
</Grid>
</Controls:MetroWindow>
Since the region is not added while inside the Hamburgermenu, the navigation is not working. Do anyone have an idea on what i might have done wrong?

The attached property (RegionManager.RegionName) does only work for controls created immediately. Lazily created controls will not be detected, because the region manager is done looking for regions.
You need to add the region manually, in the menu's code behind (constructor), like this:
RegionManager.SetRegionName( theNameOfTheContentControlInsideTheMenu, WellKnownRegionNames.MenuRegion );
RegionManager.SetRegionManager( theNameOfTheContentControlInsideTheMenu, theRegionManager );
You'll have to assign a name to the content control hosting the region and somehow acquire the region manager (ServiceLocator.Current.GetInstance<IRegionManager>()).

Related

WPF binding mahapps metro icons in template - Tag binding not working

I have a navbar with several buttons in it. The buttons all use the same style, defined in a ResourceDictionary.
I am trying to add an icon from Mahapps to each button. Each button will need a different kind of icon, which I'd like to set on the view.
In order to achieve this, I need to be able to pass the icon kind to the template via some property of the button.
I am unable to pass the icon kind to the template.
I am testing this on a new project (WPF netcore3.1)
I have seen other posts (post1, post2) that suggest using a rectangle rather than iconPacks, and binding the Visual property of the rectangle using the Tag property of the button:
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source="/IconStyle.xaml" />
</Application.Resources>
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<Button Style="{StaticResource IconStyle}" Foreground="Red">
<Button.Tag>
<iconPacks:Modern Kind="Home" Width="24" Height="24" />
</Button.Tag>
</Button>
</StackPanel>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<Style x:Key="IconStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=Button}}">
<Rectangle Width="24" Height="24" Fill="{Binding Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{Binding Tag}" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="10 0 10 0" VerticalAlignment="Center" Text="John Doe"
FontSize="24" FontWeight="Normal" FontFamily="Segoe UI Light" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But doesn't display any icons at all for me.
Any suggestions?
With the IconPacks you don't need the OpacityMask usage. Instead you can work with the PackIconModern control or any other control from the IconPacks package.
Here is an example with only the PackIconModern control from the MahApps.Metro.IconPacks.Modern NuGet package (v4.11.0).
The button style:
<Style x:Key="IconStyle" TargetType="{x:Type Button}">
<Setter Property="Padding" Value="10 5" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="FontSize" Value="24" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI Light" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconModern
Kind="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Tag, Mode=OneWay}"
Width="24"
Height="24"
VerticalAlignment="Center" />
<TextBlock Margin="10 0 0 0"
VerticalAlignment="Center"
Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
With that style you can the do something like that:
<Grid>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" Margin="5 10">
<Button Style="{StaticResource IconStyle}"
Foreground="Crimson"
Content="John Doe"
Tag="{x:Static iconPacks:PackIconModernKind.Home}" />
<Button Style="{StaticResource IconStyle}"
Foreground="ForestGreen"
Content="Works..."
Tag="{x:Static iconPacks:PackIconModernKind.Cloud}" />
</StackPanel>
</Grid>
The namespace for the IconPacks control is xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks".
If you need more icons from another package the simply add the NuGet package and use this control then. It's also possible to use the main IconPacks package which contains all icon controls and a control which can handle all possible icon kind enumerations. You will find more information at the wiki of the repository ion GitHub (MahApps.Metro.IconPacks).

WPF Panel where only one item is visible at a time (alternative to QML's StackLayout)?

I have several controls and I want to show them only one at a time.
In QML there is a type StackLayout which does that. But I haven't found a similar control in WPF.
I want to achieve the following:
<controls:StackLayout ControlIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
Then, from my ViewModel I want to dynamically change which control is shown.
Answers:
Direct answer to my question
Better way of solving my problem
In this case, I would go with a ContentControl templated based on the type of content you give it in your view model (rather than based on index). As the property changes, the appropriate template will be selected and displayed.
XAML
Resources define data templates for each kind of content in the control
<Window.Resources>
<DataTemplate DataType="{x:Type local:ContentXyz}">
<controls:ControlXyz/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ContentAbc}">
<controls:ControlAbc/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding Content}"/>
ViewModel
The Content property holds the view model for the active control. When user actions or data changes require to display a different control, set it to the appropriate view model.
public IContent Content
{
get => this.content;
set => this.SetProperty(ref this.content, value);
}
And viewmodel classes for your inner user controls need to implement IContent (which is just a marker interface to describe the view model can be used in this place).
More
Also, frameworks like Prism help you compose views in more complex ways, giving you tools like automatic view discovery - see their documentation for more.
But, I'm afraid that "abusing" ListBox for achieving my goal is not a good idea, because ListBox handles "Ctrl+LeftMouseCLick" which will deselect the item.
The ListBox needs to be hidden. It will not render.
Only its SelecteItem will be rendered.
Example for explanation:
<Window x:Class="StackLayout.StackLayoutWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackLayout"
mc:Ignorable="d"
Title="StackLayoutWindow" Height="450" Width="800">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Visibility="Collapsed">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
<ContentPresenter Grid.Row="1" Grid.Column="1"
Content="{Binding SelectedItem, ElementName=listBox}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</Window>
Do you know if it is possible to create a custom user control which will contain the list and ContentPresenter so it can be used in the way I specified in my question?
In this case (as far as I understood the task), it makes no sense.
It is enough to override the default ListBox template.
In the example, to shorten the code, the template is specified in the Window resources.
But it is better to transfer it to the dictionary and connect it to the App.
<Window x:Class="StackLayout.StackLayoutTemplateWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackLayout"
mc:Ignorable="d"
Title="StackLayoutTemplateWindow" Height="450" Width="800">
<FrameworkElement.Resources>
<SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
<SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
<Style x:Key="ListBoxStyle.StackLayout" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<!--<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>-->
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Border}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</FrameworkElement.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Style="{DynamicResource ListBoxStyle.StackLayout}"
Grid.Row="1" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
</Grid>
</Window>
Optionally, you can easily create a Custom Control from the ListBox with this template.
Although I do not see the point in this.
Thanks to #EldHasp's answer I have found a much simpler solution:
<ListBox x:Class="MyProject.StackLayout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</ControlTemplate>
</ListBox.Template>
</ListBox>
And it can be used in the following way:
<controls:StackLayout SelectedIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
By the way, using the way you have proposed I have found that it is possible to implement the StackLayout much simpler
You can think of many options for implementation.
WPF is a very flexible tool.
And the task itself is relatively simple.
Here's an example of a Sharpe implementation:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace StackLayout
{
public class StackLayout : ListBox
{
public StackLayout()
=> Loaded += OnStackLayoutLoaded;
public static void OnStackLayoutLoaded(object sender, RoutedEventArgs e)
{
ListBox listBox = (ListBox)sender;
Border border = (Border)VisualTreeHelper.GetChild(listBox, 0);
ContentPresenter presenter = new ContentPresenter();
Binding snapsToDevicePixelsBinding = new Binding()
{
Path = new PropertyPath(SnapsToDevicePixelsProperty),
Source = listBox
};
Binding selectedItemBinding = new Binding()
{
Path = new PropertyPath(SelectedItemProperty),
Source = listBox
};
presenter.SetBinding(SnapsToDevicePixelsProperty, snapsToDevicePixelsBinding);
presenter.SetBinding(ContentPresenter.ContentProperty, selectedItemBinding);
border.Child = presenter;
}
}
}
In my example, the default ListBox border is preserved, but if desired, you can also remove it.
BUT once again I would like to draw your attention to the fact that you have most likely chosen the wrong path for the realization of your task as a whole.

Button Style is not applying XAML

So I have been learning WPF for a little while now and I am starting to use styles to make my forms look a little better.
The issue I am running into is for some reason my button style will not be applied anywhere. I am pretty sure I am overwriting the default button style. All of my other styles are working just fine I just can't figure this one out. Here is my code.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Employee_Time_Entry">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Colors.xaml" />
<ResourceDictionary Source="Fonts.xaml" />
<ResourceDictionary Source="Texts.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Regular button -->
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}">
<Setter Property="Background" Value="{StaticResource BackgroundOrangeBrush}" />
<Setter Property="Foreground" Value="{StaticResource ForegroundLightBrush}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="{StaticResource FontSizeLarge}" />
<Setter Property="FontFamily" Value="{StaticResource LatoRegular}" />
<Setter Property="Padding" Value="50 10" />
<Setter Property="Margin" Value="0 10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="border"
CornerRadius="10"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the form code where the button will not apply the style.
<Page x:Class="Employee_Time_Entry.Views.Login"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Employee_Time_Entry"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500"
Title="Login">
<Border>
<Border.Background>
<ImageBrush ImageSource="/Backgrounds/BlueWaveBackground.jpg"/>
</Border.Background>
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Center">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" TextBlock.TextAlignment="Center" >
<Border Background="{StaticResource ForegroundLightBrush}"
CornerRadius="10"
Padding="15 10 15 15"
Width="250"
Margin="50 50 50 0">
<StackPanel>
<TextBlock Text="Sign In" Padding="0 0 0 10" FontSize="{StaticResource FontSizeLarge}" FontFamily="{StaticResource LatoBold}"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<StackPanel>
<TextBlock HorizontalAlignment="Left" Margin="0 10 5 0" Text="User Name:" Style="{StaticResource DefaultTextBox}"/>
<TextBlock HorizontalAlignment="Left" Margin="0 15 5 0" Text="Password:" Style="{StaticResource DefaultTextBox}"/>
</StackPanel>
</Grid>
<Grid Grid.Column="1">
<StackPanel>
<TextBox/>
<PasswordBox/>
<Button Content="Login"
Margin = "10 10"/>
</StackPanel>
</Grid>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</Border>
Here is a picture of my form
You need to make sure the resource file is referenced either application wide or within the page you want to apply it.
To apply the resources from the file to a specific page, you need to add it to the page resources.
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Assembly.Namespace;component/MyResourceFileName.xaml"
x:Name="Dict" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
To apply the resource to your entire application, you would do the same but to your app.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Assembly.Namespace;component/MyResourceFileName.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
It should be noted that your button style will not display any content. Your style only has a Border which cannot display content. Make sure you add a ContentPresenter inside of the Button
Bind the style to your button, Like this
<Button Style="{StaticResource /the name of your style here/}" Content="Login" Margin = "10 10"/>
On your button style
<Style TargetType="{x:Type Button}" x:Key="/nameyourstyle/" BasedOn="{StaticResource BaseStyle}">
.....

How to apply App.XAML style to current window

I am trying to apply validation error template and defining style in App.XAML.
<Application x:Class="MY.UI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BP.NES.UI"
>
<Application.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border BorderBrush="#FFCB2E2E" BorderThickness="1" Background="#11FF0000" IsHitTestVisible="False" x:Name="errorBorder"/>
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup AllowsTransparency="True" HorizontalAlignment="Right" HorizontalOffset="0" VerticalOffset="0" PopupAnimation="Fade" Placement="Left"
PlacementTarget="{Binding ElementName=errorBorder}" IsOpen="{Binding ElementName=placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<Polygon VerticalAlignment="Center" Points="0,4 4,0 4,8" Fill="#FFCB2E2E" Stretch="Fill" Stroke="#FFCB2E2E"
StrokeThickness="2" />
<Border Background="#FFCB2E2E" CornerRadius="4" Padding="4">
<TextBlock HorizontalAlignment="Center" Foreground="White" FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
</Application>
Now in My Main Window I have following code:
<Window x:Class="MY.UI.View.MainWindow"
xmlns:local="clr-namespace:MY.UI.View"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
xmlns:vm="clr-namespace:MY.UI.ViewModel"
xmlns:rules="clr-namespace:MY.UI.Validations"
>
<Grid x:Name="MainGrid">
<TextBox Grid.Row="1"
x:Name="CellphoneNumberTextBox"
Grid.Column="1"
VerticalAlignment="Stretch"
Margin="10,0,0,10"
IsEnabled="{Binding ElementName=PereferenceRadio,Path=IsChecked}"
Text="{Binding CurrentEnrolmentDetail.CellNumber,NotifyOnValidationError=True,ValidatesOnNotifyDataErrors=True,UpdateSourceTrigger=PropertyChanged}">
</TextBox>
</Grid>
</Window>
If I move style to Window.Resources, it just works fine ,but when I have this in App.XAML , does not work. Is this due to difference in namespace?
Set a style key in App.Xaml and use the key in your Textbox.
Example:
App.Xaml
<Style x:Key="HeaderStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
Window:
<Window x:Class="WpfTutorialSamples.Styles.ExplicitStyleSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExplicitStyleSample" Height="150" Width="300">
<StackPanel Margin="10">
<TextBlock>Header 1</TextBlock>
<TextBlock Style="{StaticResource HeaderStyle}">Header 2</TextBlock>
<TextBlock>Header 3</TextBlock>
</StackPanel>
</Window>
Or Override using BasedOn functionality
Try this if you don't have interest to create style key
App.Xaml
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<!-- ... -->
</Style>
I have declared my base styles in a ResourceDictionary in App.xaml, if i override them in a specific window like this, it usually works.
If all TextBox will remain similar thought application than use following in resource file.
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Background" Value="Blue"/>
</Style>
Else create key in App.xaml and use in the TextBox's where required as shown below:
<Style x:Key="TextboxBackgroundColor" TargetType="TextBox">
<Setter Property="Background" Value="Cyan"/>
</Style>
<TextBox x:Name="txtText" Style="{StaticResource TextboxBackgroundColor}" />

wpf ResourceDictionary not applied to ContentControl

I have a wpf application, here i've made a contentcontroller that has a label and a button. this will be used as an overlay when something is loading.
the .cs file
namespace VLC.WPF.Controls
{
public class LoadingOverlay : ContentControl
{
}
}
the .xaml file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VLC.WPF.Controls">
<Style TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
all of this will be used like this
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<controls:LoadingOverlay.Resources>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</controls:LoadingOverlay.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>
in various usercontrols, it's functioning correctly but the styly doesn't appear to load.
What could be wrong here? the code looks alright so i think it should be loading but it isn't.
in your style try adding the TargetType to your ControlTemplate like this
<ControlTemplate TargetType="local:LoadingOverlay">
What I don't understand is why are you setting the styling in the UserControl Resources and not using Keys to reference styles in your ResourceDictionary. It would keep your overall code much cleaner and you wouldn't have to change each control if you have to make a minor change later... for example:
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And when you call the control in your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
and if you find you need to alter the style for another page, instead of doing an inline style for the control - after the originally defined style try this:
<Style x:Key="overlayTwo" TargetType="local:LoadingOverlay" BasedOn="{StaticResource overlayOne}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
This style uses all the information you have already defined and adds another data trigger, or you could override what is there, change other elements in style such the font size or colors.
Then, you just have to use this key when defining your control
<local:LoadingOverlay Style="{DynamicResource overlayTwo}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
Sorry for the long winded answer, but I see this being a potential problem if you have a lot of these controls on different pages and by not keeping all of your styling in the ResourceDictionary
P.S. If your content is going to be the same that could also be part of the style like below
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And then you only need on your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}"/>
You actually override the style within the LoadingOverlay resources.
Replace <Style TargetType="controls:LoadingOverlay"> by the following <Style TargetType="{x:Type controls:LoadingOverlay}" BasedOn="{StaticResource {x:Type controls:LoadingOverlay}}"> and voila!
The resource must be defined before the UI element that will be using it. If a control uses a style resource, that style must be higher in the visual tree.
Move the style to the UserControl resources
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>

Categories