How to use a C# custom subclass in XAML? - c#

Here is my issue : I would like to use a subclass of SurfaceInkCanvas in my MyWindow.
I created a C# class like this :
namespace MyNamespace
{
public class SubSurfaceInkCanvas : SurfaceInkCanvas
{
private MyWindow container;
public SubSurfaceInkCanvas()
: base()
{
}
public SubSurfaceInkCanvas(DrawingWindow d) : base()
{
container = d;
}
protected override void OnTouchDown(TouchEventArgs e)
{
base.OnTouchDown(e);
}
}
}
And I would like to use it in my XAML window. Is it something like this ?
<MyNamespace:SubSurfaceInkCanvas
x:Name="canvas"
Background="White"
TouchDown="OnTouchDown"/>
Am I totally on the wrong way ?

You need to import an Xml Namespace in order to use classes...
<Window x:Class="Namespace.SomeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> ... </Window>
Notice how the namespaces are imported. The default one (no prefix) can be whatever you want, but it's probably best to leave that to Microsoft's presentation namespace. Then there is the "x" namespace, which is the base xaml namespace (of course you could change the prefix, but you should leave it as it is).
So, in order to add your own namespace to it there are two ways of doing it (one if it's local).
CLR-Namespaces: xmlns:<prefix>="clr-namespace:<namespace>;Assembly=<assemblyName>"
URI-Namespaces: xmlns:<prefix>="<uri>"
In your case you'd probably want to set the prefix as "local" and use the CLR Namespace (since it is all you can use).
Import: xmlns:local="clr-namespace:MyNamespace;Assembly=???"
Usage: <local:SubSurfaceInkCanvas ... />
Alternatively, if these classes are inside of an external library, you can map your CLR-Namespaces to XML-Namespaces... see this answer for an explenation on that.

You need to add the namespace (xmlns:myControls), try like this:
<Window ...
xmlns:myControls="clr-namespace:MyNamespace;assembly=MyNamespace"
...>
<myControls:SubSurfaceInkCanvas x:Name="canvas"
Background="White"
TouchDown="OnTouchDown"/>
</Window>

Related

WPF - Get text from static Dictionary Singleton

I got the localization for my project in an external class library, because I want only one Lang.csv file for my translations.
For this I got a static instance Translator.TI with an indexer in the namespace TimeTracking.Lang and my WPF Application is in the namespace TimeTracking.View in the main project (so different projects, but same basic namespace).
namespace TimeTracking.Lang
{
public class Translator
{
public static readonly Translator TI = new Translator();
private readonly Dictionary<string, Translation> _translations;
public string this[string key]
{
get { ... }
}
...
}
}
Now I want to load my translations from this static singleton instance into the view.
<Window
...
xmlns:p="clr-namespace:TimeTracking.Lang;assembly=TimeTrackingShared"
Title="{x:Static p.Translator.TI[TimeTracking]}"
>
...
</Window>
Question: Is this possible and how? And if not: Could I do this by using a class property targeting the static singleton?
It is not possible to use indexer with {x:Static} extension. You could achieve this with Binding, for example:
Title="{Binding Source={x:Static p:Translator.TI}, Path='[TimeTracking]'}"
It is also a good idea to implement INotifyPropertyChanged interface in your Translator class to avoid binding memory leaks and to enable property change notifications.

How to define an constructor argument accessible from Xaml

Xamarin's ListView defines a 1-argument constructor as follows:
public ListView([Parameter("CachingStrategy")] ListViewCachingStrategy cachingStrategy)
As a result, CachingStrategy can be used in Xaml:
<ListView CachingStrategy="RecycleElement" .../>
I'm wondering how I can do the same thing. The following code, as is, does not compile because ParameterAttribute is internal to Xamarin.Forms:
public ItemListControl([Parameter("IsReadOnly")] bool isReadOnly)
I copied class ParameterAttribute from Xamarin.Forms, and the above compiled, but had no effect on Xaml processing. Here is the class, for reference:
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class ParameterAttribute : Attribute
{
public ParameterAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
Is there anything I'm missing?
To make things simpler, I would recommend creating a BindableProperty for IsReadOnly. But you can always use x:Arguments to pass in parameters to constructor:
<local:ItemListControl ...>
<x:Arguments>
<x:Boolean>true</x:Boolean>
</x:Arguments>
</local:ItemListControl>
EDIT - 1
There is one hack that you can use - (I wouldn't recommend as this could change anytime with an update in XAMLC compilation) - but you can make sure to keep the namespace same as the one used internally while defining the parameter attribute.
namespace Xamarin.Forms
{
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class ParameterAttribute : Attribute
{
public ParameterAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
}
And XAML usage would look like:
<local:ItemListControl IsReadOnly="true" .. />
EDIT - 2
This hack only seems to work if XAMLCompilation is applied to host control/page.

C# web browser constructor

I am trying to add a web browser to an existing C# application, but, having not used C# in about 6 years, I am quite unfamiliar with how it works.
I am trying to add the browser to a partial class (again, something I am not familiar with) using the following code:
public partial class WebBrowser : WebBrowserBase{
public WebBrowser(){
...
}
...
}
However, I am getting a compile error on the constructor that says:
'WebBrowserBase' does not contain a constructor that takes 0 arguments
I Google'd this, and came across the following question on SO: C# Error: Parent does not contain a constructor that takes 0 arguments. I tried doing what was suggested in the answer to this, and changed my code to:
public partial class WebBrowser : WebBrowserBase{
public WebBrowser(int i) : base(i){
...
}
...
}
However, I then get a compile error that says:
'WebBrowserBase' does not contain a constructor that takes 1 arguments
So I'm guessing that this issue isn't to do with the number of arguments in the constructor... Can anyone explain what I'm doing wrong here?
If you have a look at WebBrowserBase Class it states that:
"This API supports the product infrastructure and is not intended to be used directly from your code."
And it seems that it doesn't have any public constructor - so you can't inherit from it. But if you don't want to create your own WebBrowser control (alter some of it's functionality), you should just use the default System.Windows.Forms.WebBrowser in a XAML View:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">
<WebBrowser HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Window>
In Inheritance,
If Derived class contains its own constructor which not defined in Base class then this error Occurs
For Example:
class FirstClass
{
public FirstClass(string s) { Console.WriteLine(s); }
}
class SecondClass : FirstClass
{
public SecondClass()
{
Console.WriteLine("second class");
}
}
Output: Error:-'myconsole.FirstClass' does not contain a constructor that takes 0 arguments
To Run without Error:
class FirstClass
{
public FirstClass()
{
Console.WriteLine("second class");
}
public FirstClass(string s) { Console.WriteLine(s); }
}
class SecondClass : FirstClass
{
public SecondClass()
{
Console.WriteLine("second class");
}
}

Inherited Window can not have a name?

I'm having trouble with naming my Window which is inherited from its Base Window,
when I try to give a name to my Window I get following error.
The type BaseWindow cannot have a Name attribute. Values types and types without a default constructor can be used as items within ResourceDictionary.
XAML :
<log:BaseWindow
x:Class="EtraabMessenger.MainWindow"
x:Name="main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:log="clr-namespace:EtraabMessenger.MVVM.View.Controls"
xmlns:VMCore="clr-namespace:EtraabMessenger.MVVM.VMCore"
VMCore:WindowClosingBehavior.Closing="{Binding DoCloseMainWindowCommand}"
Height="464" Width="279">
</log:BaseWindow>
EDIT : Here is my BaseWindow class
public abstract class BaseWindow : Window, INotifyPropertyChanged
{
protected BaseWindow()
{
// Note (Important) : This message should register on all windows
// TODO : I'm planning to move this registeration to BaseWindow class
Messenger.Register<bool>(GeneralToken.ClientDisconnected, DisconnectFromServer);
}
protected abstract void DisconnectFromServer(bool isDisconnected);
protected abstract void RegisterTokens();
protected abstract void UnRegisterTokens();
....
....
....
}
Any advice will be helpful.
Your base window apparently, as the error states, needs a public default contructor (one without arguments), it also may not be abstract because an instance of it needs to be created.

How can a WPF UserControl inherit a WPF UserControl?

The following WPF UserControl called DataTypeWholeNumber which works.
Now I want to make a UserControl called DataTypeDateTime and DataTypeEmail, etc.
Many of the Dependency Properties will be shared by all these controls and therefore I want to put their common methods into a BaseDataType and have each of these UserControls inherit from this base type.
However, when I do that, I get the error: Partial Declaration may not have different base classes.
So how can I implement inheritance with UserControls so shared functionality is all in the base class?
using System.Windows;
using System.Windows.Controls;
namespace TestDependencyProperty827.DataTypes
{
public partial class DataTypeWholeNumber : BaseDataType
{
public DataTypeWholeNumber()
{
InitializeComponent();
DataContext = this;
//defaults
TheWidth = 200;
}
public string TheLabel
{
get
{
return (string)GetValue(TheLabelProperty);
}
set
{
SetValue(TheLabelProperty, value);
}
}
public static readonly DependencyProperty TheLabelProperty =
DependencyProperty.Register("TheLabel", typeof(string), typeof(BaseDataType),
new FrameworkPropertyMetadata());
public string TheContent
{
get
{
return (string)GetValue(TheContentProperty);
}
set
{
SetValue(TheContentProperty, value);
}
}
public static readonly DependencyProperty TheContentProperty =
DependencyProperty.Register("TheContent", typeof(string), typeof(BaseDataType),
new FrameworkPropertyMetadata());
public int TheWidth
{
get
{
return (int)GetValue(TheWidthProperty);
}
set
{
SetValue(TheWidthProperty, value);
}
}
public static readonly DependencyProperty TheWidthProperty =
DependencyProperty.Register("TheWidth", typeof(int), typeof(DataTypeWholeNumber),
new FrameworkPropertyMetadata());
}
}
Ensure that you have changed the first tag in the xaml to also inherit from your new basetype
So
<UserControl x:Class="TestDependencyProperty827.DataTypes.DataTypeWholeNumber"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
>
becomes
<myTypes:BaseDataType x:Class="TestDependencyProperty827.DataTypes.DataTypeWholeNumber"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:myTypes="clr-namespace:TestDependencyProperty827.DataTypes"
>
So, to summarise the complete answer including the extra details from the comments below:
The base class should not include a xaml file. Define it in a single (non-partial) cs file and define it to inherit directly from Usercontrol.
Ensure that the subclass inherits from the base class both in the cs code-behind file and in the first tag of the xaml (as shown above).
public partial class MooringConfigurator : MooringLineConfigurator
{
public MooringConfigurator()
{
InitializeComponent();
}
}
<dst:MooringLineConfigurator x:Class="Wave.Dashboards.Instruments.ConfiguratorViews.DST.MooringConfigurator"
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:dst="clr-namespace:Wave.Dashboards.Instruments.ConfiguratorViews.DST"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</dst:MooringLineConfigurator>
I found the answer in this article: http://www.paulstovell.com/xmlnsdefinition
Basically what is says is that you should define an XML namespace in the AssemlyInfo.cs file, which can the be used in the XAML. It worked for me, however I placed the base user control class in a separate DLL...
There is partial class definition created by designer, you can open it easy way via InitializeComponent() method definition.
Then just change partial class iheritence from UserControl to BaseDataType (or any you specified in class definition).
After that you will have warning that InitializeComponent() method is hidden in child class.
Therefore you can make a CustomControl as base clas instead of UserControl to avoid partial definition in base class (as described in one comment).
I ran into the same issue but needed to have the control inherit from an abstract class, which is not supported by the designer. What solved my problem is making the usercontrol inherit from both a standard class (that inherits UserControl) and an interface. This way the designer is working.
//the xaml
<local:EcranFiche x:Class="VLEva.SIFEval.Ecrans.UC_BatimentAgricole"
xmlns:local="clr-namespace:VLEva.SIFEval.Ecrans"
...>
...
</local:EcranFiche>
// the usercontrol code behind
public partial class UC_BatimentAgricole : EcranFiche, IEcranFiche
{
...
}
// the interface
public interface IEcranFiche
{
...
}
// base class containing common implemented methods
public class EcranFiche : UserControl
{
... (ex: common interface implementation)
}

Categories