I have this class:
public class EditorKey
{
public Type TargetType { get; set; }
public DataTemplate Template { get; set; }
}
Now, I want to create an instance of this class in XAML. Since in UWP we don't have the x:Type markup extension, I'm specifying the type directly as a string, with the correct prefix with TargetType="model:Customer"
<Page
x:Class="App8.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="using:App8"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<ContentControl>
<model:EditorKey TargetType="model:Customer" />
</ContentControl>
</Page>
Running this, I get a runtime exception:
Failed to create a 'App8.EditorKey' from the text 'model:Customer'.
How can I map the string to the actual Type?
The usual way of doing it in UWP is to simply supply the reference as a string:
<model:EditorKey TargetType="model:Customer" />
If this doesn't work, try specifying the full namespace, rather than defining an xmlns.
Example:
<model:EditorKey TargetType="App8.Customer" />
Note: As of time of writing, there's an issue where the above will crash in Release mode. As a workaround, you can create a Markup extension:
[MarkupExtensionReturnType(ReturnType = typeof(Type))]
public sealed class TypeExtension : MarkupExtension
{
public Type Type { get; set; }
/// <inheritdoc/>
protected override object ProvideValue() => Type;
}
And use it like so:
<model:EditorKey TargetType="{local:Type Type=model:Customer"/>
Related
While it is easy to implement the xaml definition of a child window/page using x:TypeArguments, such as
// ParentWindowClass.cs
public abstract class ParentWindowClass<T> : Window { ... }
// ChildWindowClass
public class ChildWindowClass : ParentWindowClass<double> { ... }
<ParentWindowClass x:Class="MyNamespace.ChildWindowClass" x:TypeArguments="sys:Double">
How can we define the xaml code for a generic class if we want to allow any type to be used as type parameter? For example:
// GenericDialog.xaml.cs
public partial class GenericDialog<T> : Window
{
T SomePublicProperty { get; }
public GenericDialog()
{
InitializeComponent();
// The name 'InitializeComponent' does not exist in the current context
// (This is because x:Class is incomplete in the xaml file)
}
}
<!-- GenericDialog.xaml -->
<Window x:class="MyNamespace.GenericDialog">
<!-- x:TypeArguments doesn't apply here because it can be used for any type -->
The end goal is the following use cases that all reuse the same xaml:
new GenericDialog<int>().Show()
new GenericDialog<DateTime>().Show()
I am trying to add a generic Type to my XAML .cs file so it can be re-used with another classes/types. This is where I got so far:
public class PageElementRenderer<T> : PageFunction<T>
{
public PageElementRenderer()
{
}
}
.cs behind XAML:
public partial class PageElementRenderer_Derived : PageElementRenderer<SomeClass>
{
public PageElementRenderer_Derived() : base()
{
}
}
XAML:
<local:PageElementRenderer
x:Class="Application.PageElementRenderer_Derived"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Application">
I get an error:
Using the generic type 'PageElementRenderer' requires 1 type arguments
However, if I remove T type parameter from my pageElementRenderer class, everything works fine. Did I miss something?
Thanks guys, adding x:TypeArguments="local:SomeClass" solved the problem!
Hello StackOverflow community,
I got a question regarding the inheritance of the WPF windows.
If you create a new window it inherits from System.Windows.Window - so let's just say: I want that every window that I use have following code in his constructor:
MinHeight = Height;
MinWidth = Width;
So my first attempt was that I create a new class called BaseWindow and put the code block into the constructor of BaseWindow (this method I also often used for forms application and it worked there).
namespace MyProject.Classes
{
public class BaseWindow : System.Windows.Window
{
public BaseWindow()
{
MinHeight = Height;
MinWidth = Width;
}
}
}
My BaseWindow class is now existing and now I let my window wndLogin inherit from the BaseWindow - so something like that:
using MyProject.Classes;
namespace MyProject
{
public partial class wndLogin : BaseWindow
{
public wndLogin()
{
InitializeComponent();
InitializeWindow();
}
private void InitializeWindow()
{
// Initializing window specific stuff
}
}
}
I noticed that this class is partial, so I also changed the inheritance on the other part of the class in the file wndLogin.g.i.cs - it says there, that this file is an auto generated file and should not be edited.
namespace MyProject {
/// <summary>
/// wndLogin
/// </summary>
public partial class wndLogin : System.Windows.Window, System.Windows.Markup.IComponentConnector {
// auto generated stuff here
}
}
When I edit it anyway it replaces my custom inheritance with the standard inheritance → System.Windows.Window after debugging the project.
Is there a way to disable this automatic generated code or to tell Visual Studio that it should use an other class for inheritance?
Thanks in advance! :-)
Don't hand-edit wndLogin.g.i.cs, it is generated automatically (as you found out).
In order to do this, you need to also change the XAML file to use your window:
<local:BaseWindow x:Class="MyNamespace.Window1"
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:MyNamespace"
mc:Ignorable="d"
Title="Window1">
<Grid>
</Grid>
</local:BaseWindow>
Notice the <local:BaseWindow ... instead of Window. If your BaseWindow class is in an entirely different namespace, you'll need to specify that in the xaml:
<baseWindowNs:BaseWindow x:Class="MyNamespace.Window1"
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:MyNamespace"
xmlns:baseWindowNs="clr-namespace:MyProject.Classes"
mc:Ignorable="d"
Title="Window1">
<Grid>
</Grid>
</baseWindowNs:BaseWindow>
The key line being the namespace qualifier: xmlns:baseWindowNs="clr-namespace:MyProject.Classes", and then use your namespace name in place of local from the first sample.
The only other change needed is the WindowName.xaml.cs file to inherit from the new base class:
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : BaseWindow
{
public Window1()
{
InitializeComponent();
}
}
Alternatively (and more in-line with WPF MVVM conventions) you could create a base view model that has those properties and bind your window class Height and Width to those viewmodel properties. Personally that is how I would approach this rather than create a new base class for windows.
I'm new in WPF and I'm doing following code below as:
public partial class MainView : ViewModelControl
{
public MainView()
{
InitializeComponent();
this.DataContext = new ViewModel1();
}
}
As you can see I have my own class ViewModelControl. I have the following code below fro ViewModelControl class as:
public partial class ViewModelControl : Window, IViewModelControl
{
public virtual void bindFirstDataContext()
{
}
public virtual void bindSecondDataContext()
{
}
}
I Modify the following XAML as:
<Window x:Class="WpfApplication1.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainView" Height="262" Width="316">
Now the issue is that its show's error "Partial declarations of 'WpfApplication1.View.MainView' must not specify different base classes". It's not working as before as When I implement it with Window class as by default. Where I'm doing wrong?
Base class for partial class declarations should be same. You have changed Window in code behind to ViewModelControl so that needs to be updated in XAML as well.
Change XAML declaration to this:
<local:ViewModelControl
x:Class="WpfApplication1.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Namespace"> <-- HERE replace Namepsace with
actual namespace of class
ViewModelControl.
....
</local:ViewModelControl/>
You need to change your XAML:
<src:ViewModelControl x:Class="WpfApplication1.Interface.MainView"
xmlns:src="clr-namespace:WpfApplication1.Interface" ...>
</src:ViewModelControl>
This will work, be carefull in the class attribute, write the fullname of your class ("namespace"."name of the class")
After "xmlns:src="clr-namespace:" you need to write the namespace where ViewModelControl is.
It need to be like that because MainView doesn't inherit directly from Window so you can't put a class name in the class attribute of a Window if it's not a direct child of window.
With this change it should work I tried it, if you still have some problem look again the namespace names it's easy to get confused.
I have this code behind:
CustomUserControl.xaml.cs
namespace MyProject
{
public partial class CustomUserControl<T> : UserControl
{
...
}
}
and this xaml:
CustomUserControl.xaml
<UserControl x:Class="MyProject.CustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
</Grid>
It doesn't work since the x:Class="MyProject.CustomUserControl" doesn't match the code-behind's generic class definition. Is there some way to make this work?
You can create generic "code-behind" file without XAML-file:
public class CustomUserControl<T>: UserControl
{ }
and than derive from it providing specific class as a parameter:
public partial class SpecificUserControl : CustomUserControl<Presenter>
{
public SpecificUserControl()
{
InitializeComponent();
}
}
XAML:
<application:CustomUserControl
x:TypeArguments="application:Presenter"
xmlns:application="clr-namespace:YourApplicationNamespace"
...
Unfortunately, it seems that Visual Studio designer doesn't support such generics until Visual Studio 2012 Update 2 (see https://stackoverflow.com/a/15110115/355438)
Haven't found my solution anywhere else so far.
The main difference is, that I have got one .xaml file
for the generic user control class and not one for each actual user control.
GenericUserControl.xaml.cs
using System.Windows.Controls;
namespace TestGenericUserControl
{
public abstract partial class GenericUserControl : UserControl
{
// If you use event handlers in GenericUserControl.xaml, you have to define
// them here as abstract and implement them in the generic class below, e.g.:
// abstract protected void MouseClick(object sender, MouseButtonEventArgs e);
}
public class GenericUserControl<T> : GenericUserControl
{
// generic properties and stuff
public GenericUserControl()
{
InitializeComponent();
}
}
// To use the GenericUserControl<T> in XAML, you could define:
public class GenericUserControlString : GenericUserControl<string> { }
// and use it in XAML, e.g.:
// <GenericUserControlString />
// alternatively you could probably (not sure) define a markup extension to instantiate
// it directly in XAML
}
GenericUserControl.xaml
<UserControl x:Class="TestGenericUserControl.GenericUserControl"
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">
<Grid>
<Label Content="hello" />
</Grid>
</UserControl>
Unfortunately XAML does not support generic code behind, thou you can walk around this.
See links below:
http://forums.silverlight.net/forums/p/29051/197576.aspx
Can I specify a generic type in XAML (pre .NET 4 Framework)?
May be generic controls will be supported natively in future versions of Visual Studuo with
XAML 2009.
I ended up with an extra helper class, this is not a UserControl. It does the job well for a simple custom UserControl that needs a Generic Type.
So the UserControl, for instance UCMoveObject, has an InitFunction that returns to me the Helper instance:
// In the UCMoveObjects UserControl Class.
public UCMoveObjectsHelper<T> InitUCMoveObject<T>(List<T> argAllList, List<T> argSelectedList)
{
return new UCMoveObjectsHelper<T>(this, argAllList, argSelectedList);
}
Then in the helper class I place all the code for making the user control work.
public class UCMoveObjectsHelper<T>
{
public UCMoveObjectsHelper(UCMoveObjects argUserControl, List<T> argAllList, List<T> argSelected)
{
_ucMoveObjects = argUserControl;
// Example reaching the usercontrol
_ucMoveObjects.listBox.SelectionChanged += LbAll_SelectionChanged;
// Do whatever I want with T
}
public List<T> ReturnSelected()
{
// Code that return a List<T>;
}
}
In the MainWindow.xaml i place a usercontrol in the window. Then in code I do the following:
_ucMovingObjectsHelper = ucMovingObjects.InitUCMoveObject<TblUsers>(tempListAll, tempListSelected);
And later in my code I can call:
var tempSelectedList = _ucMovingObjectsHelper.ReturnSelected();