如何制作UI-MarkupExtension

bwa*_*all 7 .net c# wpf xaml markup-extensions

我有一个简单的UIElement,我想将其转换为MarkupExtension:

[MarkupExtensionReturnType(typeof(FrameworkElement))]
public class PinkRectangle : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    { 
        return new Rectangle {Height = 100, Width = 300, Fill = Brushes.HotPink };
    }
}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,它的效果都很好。唯一的例外是在列表中:

<local:WindowEx x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.winfx/200x/xaml"
    xmlns:local="clr-namespace:WpfApp1"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    MyProperty="{Binding local:PinkRectangle}"> <!--this one works.-->
    <local:WindowsEx.MyList>
        <!--<Grid/> If I comment this line in, it works-->
        <local:PinkRectangle/>
    </local:WindowsEx.MyList>

    <ContentPresenter Content="{Binding MyProperty}"/>
</local:WindowEx>
Run Code Online (Sandbox Code Playgroud)

Collection Syntax中,它说:

如果属性的类型是集合,则不需要在标记中将推断的集合类型指定为对象元素。而是将要成为集合中项目的元素指定为property元素的一个或多个子元素。每个此类项目在加载过程中都会被评估为一个对象,然后通过调用隐式集合的Add方法将其添加到集合中。

但是,xaml将上面的语法解释为,MyList = PinkRectangle而不是MyList.Add(PinkRectangle)But。但是,如果我先放入Grid,它会正确调用MyList.Add()。两种情况下告诉xaml调用MyList.Add()的正确语法是什么?

这是其余的代码,以创建一个最小的,可复制的示例

namespace WpfApp1
{
    // I use this class to directly set a few unusual properties directly in xaml.
    public class WindowEx : Window
    {
        //If I remove the set property, the error goes away, but I need the setter.
        public ObservableCollection<object> MyList {get; set; } = new ObservableCollection();

        public object MyProperty
        {
            get { return GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }
        public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(nameof(MyProperty), typeof(object), typeof(MainWindow), new PropertyMetaData(0));
     }

    public partial class MainWindow : WindowEx
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

-编辑-

我发现,如果我set{ }从MyList中删除了,问题就消失了,因为xaml不再认为有一个setter,但最终我需要能够设置MyList。

jsa*_*ics 2

可怜的 XAML 解析器对这一切感到非常困惑...:O) 通过消除歧义来帮助它:MyList在 XAML 中显式实例化。

在此输入图像描述

XAML:

<local:UserControlEx x:Class="WpfApp14.UserControl1"
             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:local="clr-namespace:WpfApp14"
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="450">

    <local:UserControlEx.MyList>
        <local:ObjectCollection>
            <local:CoolBlueRectangle/>
            <local:CoolBlueRectangle/>
            <local:CoolBlueRectangle/>
            <local:CoolBlueRectangle/>
            <local:CoolBlueRectangle/>
        </local:ObjectCollection>
    </local:UserControlEx.MyList>

    <Grid>
        <ItemsControl HorizontalAlignment="Left" 
                      ItemsSource="{Binding MyList}"/>
    </Grid>

</local:UserControlEx>
Run Code Online (Sandbox Code Playgroud)

在哪里,

public class ObjectCollection : ObservableCollection<object>
{
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,命名约定是您的标记类定义应使用扩展后缀。

public class CoolBlueRectangleExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)