I have the following scenario:
Create a new class library project called Lib1
1.1. Add a new control called control1, Themes/generic.xaml file and specify
the default style of control1.
Create a new class library project called lib2.
2.1.Add a new control called control2, Themes/generic.xaml file and specify
the default style of control2. In the dafaultStyle of control2 I use control1.
My question is: Do I have to copy/paste the defaultStyle xaml of control1 into the
generic.xaml of lib2, to use control1 with its style applied in control2?
The default style lookup for a Control is always done in the assembly that the Control is defined in. So if Control1 is defined in Lib1.dll, the default style will always be looked for in generic.xaml in Lib1.dll. It doesn't matter where the Control is being used from.
Just to make sure I understand your answer correctly, I will restate it in my own words:
You want to have a Silverlight class
library (Lib1) that houses a control
(Control1).
You want to have a
Silverlight class library (Lib2)
that houses a control (Control2).
You want to have the control use their respective generic.xaml files for respective control styles.
Control2 is to include Control1 in its style definition, without redefining its style in the generic.xaml file from Lib2.
If this is correct, I will describe my answer below:
Yes, this is possible as Keith Mahoney said here. I will go into detail on his answer and an example.
Each Silverlight class library generates a Dynamic-link library (dll) when compiled. All the classes (controls) and resources (styles) are contained in these dll's. Thus, when you create a lib1 class library with a style resource for a control contained within, it will all be stored in the lib1 dll.
Below is my example of the solution:
Setting up the solution:
First, I created new solution (StackOverflow Example.sln). Then I added a new project to the solution of type Silverlight Class Library (Lib1 1.1). Please note that Silverlight does not always play nicely with spaces in the namespace, so you may want to (as I did) rename the namespace to Lib1. See "How-To's" section for details on how to do this. Next I added the second project to the solution of type Silverlight Class Library (Lib2 2.1). I again, changed the root namespace of this project to one without spaces. Finally, I added a Silverlight Application project to my solution (SLApplication). Please note that in adding the Silverlight application project, you will be prompted to add a web project or web page to your project for creating the Silverlight control. Either option will work, please use the best for your situation. I used the separate website option (default). Now, when we setup the two class libraries, we were given a default starter class1.vb file. Let's rename these file to Control1.vb (for Lib1 1.1) and Control2.vb (for Lib2 2.1) in the solution explorer. When we do this, Visual Studio 2008 asks us if we'd like it to rename the class to match this new name, Click 'Yes'. Next up, let's figure out how to setup the themes for each of our controls.
Setting up themes:
I will start with the first control library (Lib1 1.1). First, create a new folder under the root of the project; name it "Themes" (case doesn't matter). Under this folder, add a new item of type xml and name it generic.xaml. For help on how to do this, see the "How-To's" section. Open the generic.xaml file, if it isn't already open. Delete the xml declaration text that was automatically inserted for you, and use the following for your initial definition:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Styles go here. -->
</ResourceDictionary>
Now, since our Control1 control lives in this class library, we will need to add an xml namespace declaration (xmlns) (http://en.wikipedia.org/wiki/XML_namespace -sorry about the non link, my rep needs to be higher.) to our generic.xaml file. To do this, add the following line: xmlns:lib1="clr-namespace:Lib1" before the grater than symbol (>) in the top declaration. Once this is done, we can layout a simple style. Please note that we're setting the default background color to "Red" in order to differentiate the two controls. Please see below for the simple style for Control1:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib1="clr-namespace:Lib1">
<!-- Style for Control1 -->
<Style TargetType="lib1:Control1">
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="lib1:Control1">
<Grid x:Name="LayoutGrid" Background="{TemplateBinding Background}">
<TextBlock Text="Control 1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
With this let's start with the Control2. This will be very similar to the previous declaration for Lib1 1.1. If you haven't already done so, please add the Themes folder and the generic.xaml file as you did for the first library (Lib1 1.1). Now, for this project, you will need a reference to the Lib1 1.1 project. If you need help doing this, please see the "How To's" section. Once this is referenced, open the generic.xaml file, if it isn't already open. The definition of this file is almost identical; however, we will also be referencing the other projects namespace as well. See below:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2"
xmlns:lib1="clr-namespace:Lib1;assembly=Lib1">
<!-- Styles go here. -->
</ResourceDictionary>
Notice that now we are not only referencing our own namespace (lib2) but also referencing the other control's namespace (lib1) in the xml namespace declaration. Also notice that in the non-local control library, we also must reference the assembly name. Since we want to use the control (and its style) from lib one, we will need a place to use it in this project. For this, I have setup a grid with separate rows for each control. Please note that we're setting the default background color to "Blue" in order to differentiate the two controls. Please see below for Control2's definition:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2"
xmlns:lib1="clr-namespace:Lib1;assembly=Lib1">
<!-- Style for Control2 -->
<Style TargetType="lib2:Control2">
<Setter Property="Background" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="lib2:Control2">
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<lib1:Control1 Grid.Row="0" />
<Grid x:Name="Control2" Grid.Row="1" Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Text}" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This just sets up the fact that we want to have styles. We now need to tell Silverlight that we want these styles to be applied to our controls.
Using themes:
In our classes, we have to tell Silverlight that these are going to be custom user controls, to do this, we need to inherit from Control (or any other UIElement control - for this example, we will stay simple, and use Control). In order to tell the control to use a style defined in the generic.xaml, we need to do this in our constructor of each control.
For Control1:
Public Sub New()
MyBase.DefaultStyleKey = GetType(Control1)
End Sub
For Control2:
Public Sub New()
MyBase.DefaultStyleKey = GetType(Control2)
End Sub
Now all we have to do now, is tell our web site to use our new control(Control2).
Setting up the WebApplication:
You will need to reference both class libraries from your web project. See "How-To's" section for details on how to do this. Open up the Page.xaml file in your web application project (SLApplication). Your default should look something like this:
<UserControl x:Class="SLApplication.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
We will add to this the xml namespace declaration for our Silverlight class library (Lib2 2.1) so that we may reference Control2. Now that we have referenced our class library, we can use any controls that are declared within. If you try to use the namespace without building after you add it to your xmlns declaration, you may not see any declared classes (controls) within. To fix this, build once. Please also note, that Visual Studio 2008 is sometimes weird about custom libraries, and may generate an error that says the custom library is not defined. This is fixed with a re-launch of the solution (Close Visual Studio and reopen). The final code to show the Control2 (which contains Control1) is as follows:
<UserControl x:Class="SLApplication.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lib2="clr-namespace:Lib2;assembly=Lib2"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<lib2:Control2 />
</Grid>
</UserControl>
Now build, and run. If everything went well, you should see the following:
Screen Shot http://www.imagefrog.net/out.php/i40631_StackOverflowExample.jpg
The full project can be downloaded from Google Code:
http://code.google.com/p/stackoverflow-answers-by-scott/wiki/1366075
Zipped source:
http://stackoverflow-answers-by-scott.googlecode.com/files/1366075.zip
Enjoy!
How-To's:
Change project namespace
In the solution explorer expand the project on which you want to change the namespace, and double click on the "My Project". For Silverlight class library projects, you will have four tabs on the left, one of which is "Silverlight". Select this tab, if it is not already selected. Under the "Root namespace" textbox, change the namespace to your desired namespace.
Add 'generic.xaml' to project
In the solution explorer, right click on the project name. Click "Add", and then click "New Folder". This will create a folder under the root of the project. Name this folder "themes". Please note that case does not matter here. Right click on the "themes" folder, click "Add", then click "New Item...". A dialog box appears for you to select what item type you want to add. Click "XML File" under the Templates section. Change the name to generic.xaml under the name field (at the bottom of the dialog). Click Add.
Create a project reference
To create a project reference, right click on the project that needs the reference. Select "Add Reference..." from the menu. A dialog box will be displayed for you to choose the reference to add. Select the "Projects" tab at the top of this dialog. Select the desired project reference. If you do not see the project that you want to reference in this list, check that you have added the project to the solution.
Related
Inside my WPF Application I am including a ResourceDictionary from another Project.
<Application x:Class="namespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- This Line causes an Error -->
<ResourceDictionary Source="pack://application:,,,/Commons;Component/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Metadata override and base metadata must be of the same type or derived type.
The solution builds successful and runs.
Restarting Visual Studio doesn't fix it.
Cut and Paste the <ResourceDictionary Source="..." /> line causes another error as explained here in the Comments:
Value Cannot be Null. Parameter Name: item. Restarting Visual Studio will then bring back the old error.
Sadly I haven't found out how to reproduce this error, I can only tell you something more about the environment im using:
Visual Studio 2015 Professional, Version 14.0.25431.01 Update 3
And allthough I doubt, those are associated with my problem, here my installed Plugins:
Resharper Ultimate 2017.1.1
GitExtensions Version 2.49.03
Sinatr's comment hinted me to read more about theming.
ThemeInfo
Inside of a Custom Control Library theres automatically created a ThemeInfoAttribute inside AssemblyInfo.cs
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
Parameters
As it states in the autogenerated comments, the first parameter is to determine wheter there exist or where to find Theme specific resource dictionaries.
The second parameter defines wheter there exist or where to find the generic ResourceDictionary (Generic.xaml).
ResourceDictionaryLocation-Enumeration
The ResourceDictionaryLocation-Enumeration itself is used to specify the location of those dictionaries.
ResourceDictionaryLocation.None
No theme dictionaries exist.
ResourceDictionaryLocation.SourceAssembly
Theme dictionaries exist in the assembly that defines the types being themed.
This expects the ResourceDictionary to be located in a /Themes-Folder. Explanation later.
ResourceDictionaryLocation.ExternalAssembly
Theme dictionaries exist in assemblies external to the one defining the types being themed.
I am not going to explain how this works.
Why /Themes-Folder
Sadly I couldn't find too much about this. If someone has some more info please share.
Have you ever wondered, how styles of a lookless control are being applied?
If one created a lookless Control, he did as follows:
public class MyControl : ControlTemplate
{
static MyControl()
{
// This tells WPF to search for a Style for this type
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl)),
new FrameworkPropertyMetadata(typeof(MyControl)));
}
}
In short, Ressources in WPF are located, by searching up the Logical-Tree, then inside Application's Resources and finally inside sth. they call System-Area (this is my translation from German, if you know a better one pls tell).
So depending on ThemeInfo, MyControl propably had its Style inside a ResourceDictionary inside the /Themes-Folder, eg. /Themes/Generic.xaml. And that tells WPF to add the Ressources to the System-Area which finally results in automatically resolving the appropriate style.
Somewhere inside /Themes/Generic.xaml:
<Style TargetType="{x:Type MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MyControl}">
..
</ControlTemplate/>
</Setter.Value>
</Setter>
</Style>
That's why the above ThemeInfoAttribute requires Generic.xaml to be located in a /Themes-Folder. - And somehow, even if in my case the System-Area-Functionality isn't even used for this generic file, this causes those errors. But I wasn't able to find out why.
Sources:
ThemeInfoAttribute Constructor
ResourceDictionaryLocation Enumeration
Windows Presentation Foundation - Das Umfassende Handbuch, Rheinwerk Computing Version 4
I have a working application that has been written in C#, and I now want to extend that application to allow the user to switch between viewing the application, and viewing a built in web browser (inside the same application window).
I also have a separate working web browser, that has also been written in C#.
I have just added the functionality to the original application to include 'tabbed' displays, where the original application will be displayed on the first tab, and a built in web browser on the second tab.
The 'tabbed' displays for the application have been created using XAML markup in Visual Studio. I now want to add an instance of the Web browser that has also been written in C# to the second tab that I have created in the XAML markup.
It would be something like:
<TabControl>
<TabItem Header="Browser">
<StackPanel>
<!-- Call/ instantiate the browser here -->
</StackPanel>
</TabItem>
</TabControl>
But I have no idea how I call/ create an instance of the browser from within the XAML markup...
The browser has been created using C#:
namespace Agent
{
public partial class Browser : Form
{
public Browser()
{
...
}
}
}
Can anyone explain to me how a create an instance of Browser inside the ` of the XAML markup?
Edit
Ok, so I have edited my XAML markup as recommended in the answer that's been suggested- I now have:
<Window ...
xmlns:Agent="clr-namespace:Agent"
...>
<Grid>
...
<TabControl>
<TabItem Header="R">
<StackPanel>
...
</StackPanel>
</TabItem>
<TabItem Header="Browser">
<Agent:Browser x:Name="Browser" />
</TabItem>
</TabControl>
</Grid>
</Window>
I have also updated my Browser.cs class, so that it is now extending UserControl, rather than Form:
public partial class Browser : UserControl{
However, I am getting a compile error on the line:
<Agent:Browser x:Name="Browser" />
which says:
The name "Browser" does not exist in the namespace "clr-namespace:Agent".
But clearly Browser does exist in Agent, as shown by the code I've included here... In fact, when typing the line <Agent:Browser x:Name="Browser />, when I typed the :, Browser was one of the options that came up in the autocomplete menu...
What am I doing wrong here? Why doesn't the compiler think that Browser exists inside Agent?
The key to instantiating any object in XAML is to make sure the namespace is declared. You can provide any XML prefix and assign it to your CLR namespace (ref) and it will act like a using statement. For example:
<TabControl xmlns:agent="clr-namespace:Agent">
<TabItem Header="Browser">
<StackPanel>
<agent:Browser/>
</StackPanel>
</TabItem>
</TabControl>
NOTE: your object has to extend UIElement (or one of its children) for it to work in a XAML tree. If your control is a WinForms control you either need to find the equivalent XAML control or wrap it in a WindowsFormsHost (ref).
WPF vs. WinForms
The purpose of this section is to help recognize which platform code is by namespace, as well as some of the trade-offs. I've used both and can say from experience that they each have good points and... not so good points.
WinForms classes live in the System.Windows.Forms namespace, and are available by referencing the System.Windows.Forms.dll assembly.
WPF classes live in the System.Windows and System.Windows.Controls namespaces, and are available by referencing a set of DLLs
WinForms rendering is immediate. That means you are working against bitmaps and you are responsible for clearing and redrawing stuff yourself (usually you can just call Invalidate()). If you do heavy image bit manipulation, WinForms is easier to work with.
WPF rendering is declarative. That means more work is offloaded to your GPU and you just tell it how to draw stuff. You can also use GPU render shaders for special effects. WPF has a nicer look out of the box, but it has a reputation for making easy things difficult but impossible things possible.
WinForms is easier to learn, but has a dated look out of the box.
WPF is built around data binding, enabling the UI to update in response to property values automatically. It's also able to be completely restyled, although that is quite an undertaking.
If you are just getting started, I'd go ahead and bite the bullet to start the heavier learning curve for WPF. It will provide a basic understanding that transfers to other platforms like Windows Store apps, etc.
Firstly you need to place that tag inside of your UserControl opening tag like so:
<UserControl x:Class="View.testControl"
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:Agent="clr-namespace:Agent">
Then you can use it like this:
<TabControl>
<TabItem Header="R">
<StackPanel>
...
</StackPanel>
</TabItem>
<TabItem Header="Browser">
<Agent:Browser x:Name="Browser" />
</TabItem>
</TabControl>
EDIT
From what you told me in the comments you will need to create a Custom Control in your WPF project. To do that you need to:
Right Click your Project;
Select Add New Item;
From Installed (which is in the left column) select WPF;
From the list in the middle column select Custom Control;
Now you can create that control in your XAML with xmlns attribute.
Here is a great example from msdn on how to create custom controls
I'm trying to include icon font in my wpf application, but my icon never appears and only displays a rectangle.
Projet structure :
MyProject/
-- Fonts/
-- myFont.ttf
-- MyWindow.xaml
MyWindow.xaml
<Label Text="" FontFamily="/Fonts/#myfont" />
"myfont" is the name of the font (the one I see after "Font name" when I double click on the file). The file's Build Action is set as "Resource".
I also tried the following :
Using style
<Window.Resources>
<Style x:key="MyFont">
<Setter property="TextElement.FontFamily"/Fonts/#myfont" />
</Style>
</Window.Resources>
<Label Text="" Style="{StaticResource MyFont}" />
Using pack URI
<Window.Resources>
<Style x:key="MyFont">
<Setter property="TextElement.FontFamily" value="v/Fonts/#myfont" />
</Style>
</Window.Resources>
<Label Text="" Style="{StaticResource MyFont}" />
None of them work. Moreover, the last one (with pack URI) generates an error. Something like an "index out of range error" (I have VS in French so I can't tell what the message is in English).
Already tried to find a solution on the internet, but all I could find was using pack URI, or checking that the name of the font is correct or that Build Action is set to "Resource".
Thank you.
EDIT
I precise that I don't want to use Blend. I would like to manage to do it directly in code. Thank you.
Wpf supports embedded fonts - the easiest way to set these up is to assign a font to a visual element, such as a label via the font family property. I normally use blend (part of visual studio) which displays a font manager button. You can then embed the font in your application from there.
Otherwise MSDN have a page which details other options. https://msdn.microsoft.com/en-us/library/ms753303%28v=vs.110%29.aspx
If you edit the .csproj file for your project and add the item group...
<ItemGroup>
<BlendEmbeddedFont Include="Fonts\ahronbd.ttf">
<IsSystemFont>True</IsSystemFont>
<All>True</All>
<AutoFill>True</AutoFill>
<Uppercase>True</Uppercase>
<Lowercase>True</Lowercase>
<Numbers>True</Numbers>
<Punctuation>True</Punctuation>
</BlendEmbeddedFont>
</ItemGroup>
You will need a Fonts folder with that .ttf file in there as part of your solution folder. This isn't pretty, but it will work without relying on additional tools.
I am using GraphX in Winform project. I am trying to display labels besides the edges. I want to know what property do I have to set in order to display some text in the label.
I have tried setting the 'Text' property of DataEdge, and then calling
ShowAllEdgesLabels(true);
but it does not work this way. Going through the forums I have found that WPF has a way to bind this property to the visual control. The XAML code is as follows
<gxl:EdgeLabelControl x:Name="PART_edgeLabel" Content="{Binding Edge.Text, RelativeSource={RelativeSource TemplatedParent}}" />
Now the question is what is the equivalent of Winform to achieve this functionality.
I found a solution with the help of the admin at the host of GraphX (PantheR).
Basically, we need to add the hostControler for WPF in a windows form.
We need to add a custom XAML template in the resources folder.
We need to load the XAML as a new resource in the code, before we initialize the graph.
We need to add a line of code to merge the resources.
Then in the XAML code we do the binding as mentioned in the question. The code has been updated at the repository to reflect these changes.
The downfall of this solution is that, we need to provide a XAML resource file with the program, but thats just another resource (in my opinion).
For anyone that need some reference code from #ResVic's answer:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:graphx="http://schemas.panthernet.ru/graphx/"
xmlns:local="clr-namespace:YOUR_NAME_SPACE">
...
<Style TargetType="{x:Type graphx:AttachableEdgeLabelControl}">
<Setter Property="ShowLabel" Value="False" />
</Style>
...
</ResourceDictionary>
The Show case demo is protentially helpful for figuring out what stuff the lib could do and how to tweak it to work.
Is there a way to reuse a 3rd party control reference?
For example, I have this referenced in my App.xaml
xmlns:cust="clr-namespace:ThirdParty.Controls;assembly=ThirdParty.Controls"
I don't want to repeat this 3rd party control xml namespace on each page/control that needs a control from the library.
Is there anyway to centralize these references and use the prefix defined here? The possibility of each control having a different prefix is also worrisome. In asp.net you would put a reference in the web.config and it was available globally, I'm just looking to see if there is a similar method in WPF.
Two options I am thinking
1) Wrap that control into a UserControl and then use your UserControl in all the places.
2) Declare the third party control as a Resource somewhere and then use DynamicResource reference to that on your other places.
The second option can be implemented as bellow.
Where ever you want the third party control put a ContentControl like bellow
<ContentControl Template="{DynamicResource thirdPartyControlTemplate}" />
The ControlTemplate will be in the Resource file or at App.Xaml as bellow.
xmlns:thridParty="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1" >
<Application.Resources>
<ControlTemplate x:Key="thirdPartyControlTemplate" TargetType="{x:Type ContentControl}">
<thridParty:ThirdPartyControl />
</ControlTemplate>
</Application.Resources>
You can see that the namespace declaration will be always on this resource file and you will be able to use that Control control from any place
Take an example from the built-in control template for a Label:
<ControlTemplate TargetType="Label"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
Show Me The Template is an amazingly helpful resource for these kinds of things. HTH