Custom WPF / XAML Canvas

I am trying to create and use a custom canvas. Here is the XAML (MyCanvas.xaml):

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:Core="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Namespace="clr-namespace:MyNamepace" xmlns:Properties="clr-namespace:MyNamepace.Properties" Core:Class="MyNamepace.MyCanvas">
    <Canvas.Resources>
        <Namespace:ImagesConverter Core:Key="ImagesConverter"/>
    </Canvas.Resources>
    <Image Source="{Binding Source={Core:Static Properties:Resources.Background}, Converter={StaticResource ImagesConverter}}" Stretch="Fill"/>
</Canvas>

      

Here is the code declaration (MyCanvas.xaml.cs):

public partial class MyCanvas : Canvas

      

When I try to use it like this:

<Namespace:MyCanvas Core:Name="Layout" Loaded="OnLoaded">
    <Namespace:MyUserControl Core:Name="Control1" Namespace:MyCanvas.Left="50" MyProperty="50">
        <Namespace:MyCanvas.Top>
            <MultiBinding Converter="{StaticResource MathConverter}" ConverterParameter="(x - y) / 2">
                <Binding ElementName="Layout" Path="ActualHeight"/>
                <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
            </MultiBinding>
        </Namespace:MyCanvas.Top>
    </Namespace:MyUserControl>
    <Namespace:MyUserControl Core:Name="Control2" Namespace:MyCanvas.Left="744" Namespace:MyCanvas.Top="42" MyProperty="150"/>
</Namespace:MyCanvas>

      

I am getting two different errors:

The Content property can only be set once. ==> Does Canvas inherit?!?!?!

The item "Top" is not recognized or is not available. ==> Doesn't this inherit Canvas again?!?!?! The item "Left" is not recognized or is not available. ==> Does Canvas inherit again?!?!?!

EDIT: this is what I am so far ... still getting "Content" already installed!

MyCanvas.xaml

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:Core="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Namespace="clr-namespace:MyNamespace" xmlns:Properties="clr-namespace:MyNamespace.Properties" Core:Class="MyNamespace.MyCanvas">
    <Canvas.Background>
        <ImageBrush ImageSource="{Binding Source={Core:Static Properties:Resources.Background}, Converter={StaticResource ImagesConverter}}" Stretch="Fill"/>
    </Canvas.Background>
    <Canvas.Resources>
        <Namespace:ImagesConverter Core:Key="ImagesConverter"/>
    </Canvas.Resources>
</Canvas>

      

MyCanvas.xaml.cs

public class MyCanvas : Canvas
{
    // ...
}

      

MainWindow.xaml

<Namespace:MyCanvas Core:Name="MyCanvas" Loaded="OnLoaded">
    <Namespace:MyUserControl ...
    <Namespace:MyUserControl ...
    <Namespace:MyUserControl ...
</Namespace:MyCanvas>

      

+3


source to share


2 answers


Left

and the attached propertiesTop

are found . This means they are not inherited by your class.

You need to change your custom control declaration so that instead of Canvas.Left

and Canvas.Top

:

<Namespace:MyUserControl Core:Name="Control2" Canvas.Left="744" Canvas.Top="42" 
                         MyProperty="150"/>

      

The problem with the content is that you are installing it twice as indicated in the error message.

  • In MyCanvas.xaml

    you set the value Image

    .
  • When you use this parameter, you are setting it on custom controls.


To fix this, you need to add ItemsControl

in MyCanvas

and declare it as a control that represents content:

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:Core="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Namespace="clr-namespace:MyNamepace" xmlns:Properties="clr-namespace:MyNamepace.Properties" Core:Class="MyNamepace.MyCanvas">
    <Canvas.Resources>
        <Namespace:ImagesConverter Core:Key="ImagesConverter"/>
    </Canvas.Resources>
    <Image Source="{Binding Source={Core:Static Properties:Resources.Background}, Converter={StaticResource ImagesConverter}}" Stretch="Fill"/>
    <ItemsControl Content="{Binding Path=LocalContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Namespace:MyCanvas}}}" />
</Canvas>

      

In your class file:

[ContentProperty("LocalContent")]
public partial class MyCanvas : Canvas
{
    public static readonly DependencyProperty LocalContentProperty =
        DependencyProperty.Register(
            "LocalContent", 
            typeof(UIElementCollection), 
            typeof(MyCanvas ), 
            new PropertyMetadata(default(UIElementCollection)));
}

      

+4


source


Adding to Daniel's answer, you should understand that WPF introduces the concept of Dependency Properties and Dependency Objects. In short, just as objects in C # can have properties, dependency objects in WPF can have dependency properties. The way it works is slightly different, although the C #.

For dependency properties (such as attached properties), WPF manages a separate table with entries indicating which objects have which properties. In other words, this means that any object can have any property, WPF simply adds a record to the table that sets the specified property of the object. For example, Canvas.Left, being defined by Canvas, can be implemented by any control. WPF just inserts the entry into the dependency table and now you have Canvas.Left / Canvas.Top properties in your image. This means much less memory because the object fetches a property (when an entry is added) rather than having a property just because it comes from a specific class.



The way it works programmatically is you use DependencyObject.SetValue / GetValue (all WPF objects derived from DependencyObject see: http://miteshsureja.blogspot.com/2011/06/wpf-class-hierarchy.html - in fact, remember this graph because it will help you better understand how WPF works under the hood) and this adds / reads from a record to the above table. When you define a dependency property, you, your C # providers, should really redirect these methods, because WPF (and not the object itself) has to manage those values ​​(since WPF is capable of data binding and what not, because it does manage values and just transfers them to other objects as optional). For an example of creating a dependency property, seehttp://msdn.microsoft.com/en-us/library/ms752914.aspx . The concept of dependency properties is very simple, but you should at least know about it in order to understand the many functionalities of WPF.

+3


source







All Articles