I have a Window in WPF which simply contains a Frame element. The Frame displays a Page; which Page is displayed changes based on user interaction.
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
I would like all Pages that appear in that Frame to share a common Resource Dictionary so that they may all be styled in a common way.
Right now I have something like this in every page that this Window loads:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
I was hoping that I might just be able to set the resource dictionary on the Window, and they would "inherit" those resources, but that does not appear to be the case. I tried something like this, but the styles found in MenuStyle.xaml are not applied the the controls inside the Page loaded by the Frame:
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
Is there are way to define styles at the Window level such that all pages loaded in child Frames will use those styles?
Note: I do not want to apply these styles to ALL windows in my application, so putting this ResourceDictionary in my App.xaml does not appear to be a valid solution.
If you want to write it once to avoid code duplicates, you can write it in code behind. On frame ContentRendered you can write a code to add resource to the page which is being loaded.
<Frame Name="fr_View" ContentRendered="fr_View_ContentRendered"/>
private void fr_View_ContentRendered(object sender, System.EventArgs e)
{
ResourceDictionary myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("Dictionary1.xaml", UriKind.Relative);
(fr_View.Content as System.Windows.Controls.Page).Resources.MergedDictionaries.Add(myResourceDictionary);
}
Take a look at this link:
Set up application resources from code
Related
I was going through some code in our product and saw some colleagues using ResourceDictionary.MergedDictionaries in a way I had not seen it used before:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<toolTips:ToolTips />
<styles:ControlStyles />
<icons:IconDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
tooltips:ToolTips and all the other elements in the MergedDictionaries are ResourceDictionaries.
The regular way of using these according to the internet is to use <ResourceDictionary Source="uri to your xaml file"/>.
So is there any practical difference between both?
If this way works why isn't it used more often as it plays well with code completion?
I've used ResourceDicionary this way only once on a big project and it was benefical in my situation.
Suppose that you have ResourceDictionary in MyDictionary.xaml file.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
</ResourceDictionary>
You can add an x:Class attribute to the ResourceDictionary element and specify the fully qualified name of the code-behind class.
Let's create MyDictionary.xaml.cs with class MyDictionary (name can be different from the name of the xaml file).
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
}
A class must be a partial class. The constructor must be added to the class and InitializeComponent method must be called. The InitializeComponent method will be automatically generated for the class if you set the x:Class attribute in MyDictionary.xaml
Now you can reference MyDictionary in MergedDictionaries
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
If you add some DataTemplate into MyDictionary.xaml you can create event handlers in code-behind (handlers will be automatically generated by VS)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
<DataTemplate x:Key="MyTemplate">
<Button Click="Button_Click"/>
</DataTemplate>
</ResourceDictionary>
Code-behind:
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
// custom logic
// edit another element, etc.
}
}
If the class is inherited from the ResourceDictionary class then other resources can be accessed from the code-behind.
Example of usage of data template defined in MyDictonary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource MyTemplate}"/>
</Grid>
From my point of view the biggest advantages are that you can encapsulate logic into separated files (it's easy to maintain and add new features in big projects) and avoid referencing ResourceDictionaries by <ResourceDictionary Source="uri to your xaml file"/>.
Why can't my custom ListView have it's own xaml file? I have a custom Button and it works with a xaml file with no issues, but not my ListView. The main reason I want to use this approach (rather than be forced to create a Style that is place in the Generic.xaml file) is because I would like to take advantage of the Resources element and place all resources related to the listview within the xaml file:
public sealed partial class MyListView : ListView
{
public MyListView()
{
this.InitializeComponent();
}
}
And here is the associated xaml file:
<ListView
x:Class="App1.MyListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<ListView.Resources>
<!-- I would like to place all related resources here instead of having
them placed in external locations, and then have to open different files to find them. -->
</ListView.Resources>
</ListView>
Although I would expect this should work as well, it seems that this problem is present and it is recommended to use the templated control instead.
I suppose the problem is that assigning the compiler is unable to generate the valid assignment to the Items property of the control, which it is trying to construct from the content of the element. Even when the element is closed immediately it seems to be an issue.
Why not place resources on the Page or inside ListView, rather than deriving your own control?
<Page
x:Class="ListViewResources.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ListViewResources"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Place all related resources here instead of having them placed in external locations, and then have to open different files to find them. -->
</Page.Resources>
<ListView x:Name="MyListView">
<ListView.Resources>
<!-- Or place related resources here -->
</ListView.Resources>
</ListView>
</Page>
Originally I had my MainWindow(.xaml) that had a stackpanel and a frame. Within the stackpanel were three navigation buttons and the frame had one of the three Pages (based on which navigation button the user clicked). However, it seems that since I'm not doing a web app, that using Frame (and Pages?) is not the right way to go about it. So I changed the stackpanel and frame to a single tabcontrol (with tabs being what were the three buttons before). I also changed the Pages to usercontrols.
However, I'm having trouble finding a way to put the Pages (now UserControls) into the content of the tabitem, without using a Frame. I'm trying to do all of this within the MainWindow xaml.
my MainWindow.xaml:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="454" Width="573">
<Grid>
<TabControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="tabControl1">
<TabItem Header="Basics" Name="basicsTab">
//What can I use here instead of Frame?
</TabItem>
<TabItem Header="Words" Name="wordsTab">
<Grid>
<Frame Source="WordsPage.xaml"/>
</Grid>
</TabItem>
...
</TabControl>
</Grid>
</Window>
Am I going about this the wrong way? I think that I'm suppose to use some sort of databinding, maybe? Although, the more I look at things on data binging, the more I just get confused on that as well.
edit: here is my BasicsPage.xaml
<UserControl x:Class="ConstructedLanguageOrganizerTool.BasicsPage"
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"
mc:Ignorable="d" x:Name="basicsPage" Height="349" Width="334">
<Grid>
// Grid Row and Column defs here
//Number of textboxs and textblocks here.
</Grid>
</UserControl>
You just need to create an instance of UserControl and put it inside TabItem.
Say BasicsPage is your UserControl you want to put inside TabItem. All you have to do this:
<TabItem Header="Basics" Name="basicsTab">
<local:BasicsPage/>
</TabItem>
Define local namespace at root window where BasicsPage is defined in something like:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ConstructedLanguageOrganizerTool"> <-- HERE
I am creating a WPF application which behaves like a 'Windows Wizard', when I press a button in MainWindow it should navigate to say Page2.
For Page2 I added a new WPF page from VisualStudio. Is there any way for this new page to inherit some attributes from main window, like background,dimension,title,etc since most of the attributes are same.
you can use ResourceDictionaries for stuff like Color Attributes etc.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="LimeColor">#FFA4C400</Color>
<SolidColorBrush Color="{StaticResource LimeColor}" x:Key="Lime" />
</ResourceDictionary>
App.xaml
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/YourDictionary.xaml" />
</Application.Resources>
For the correct Source see: Pack URIs in WPF
Page and Window
for example:
<Grid Background="{StaticResource Lime}">
Or you can define Styles and Templates in WPF for any ControlTypes.
For further information : Control Customization on MSDN
Below is the Code , in which i want to change the theme color of the MahApps.Metro pakage.
it can be changed by changing the ResourceDictionary Source pack of MahApps.
[/MahApps.Metro;component/Styles/Accents/Blue.xaml ]
say example its /Blue.xaml now ... we can change colors of the window. to /Red.xaml , /Yellow.xaml etc
So how can i change the color of the window asynchronously in every 5 seconds? is this possible in wpf ?
i am new to wpf and clueless.
<controls:MetroWindow x:Class="NginX.Choose"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="NginX" Height="350" Width="350" ShowMaxRestoreButton="False">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
</Grid>
</controls:MetroWindow>
You can replace the Application's resource dictionary by doing:
Application.Current.Resources.Clear()
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml")
});
Put this in a timer and cycle through Red.xaml, Blue.xaml etc