gpt4 book ai didi

c# - 在充当容器的 WPF 控件中,如何放置内容?

转载 作者:行者123 更新时间:2023-11-30 15:58:13 25 4
gpt4 key购买 nike

我正在编写一个 WPF 控件,它是一个容器,就像 BorderScrollViewer 是容器一样。它称为 EllipsisButtonControl,应该在其内容的右侧放置一个省略号按钮。这是我打算如何使用它的示例:

<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>

这是 EllipsisButtonControl 的 XAML:

<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
x:Name="ContentControl"
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"
d:DesignHeight="30" d:DesignWidth="300">

<Grid>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<ContentPresenter Grid.Column="0" Content="{Binding ElementName=ContentControl, Path=Content}" />

<Button Grid.Column="1" Command="{Binding ElementName=ContentControl, Path=Command}" Margin="3,0" Width="30" Height="24" MaxHeight="24" VerticalAlignment="Stretch" Content="..." />

</Grid>

</ContentControl>

下面是代码:

using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
public partial class EllipsisButtonControl
{
public EllipsisButtonControl()
{
InitializeComponent();
}

public static string GetCommand(DependencyObject obj)
{
return (string)obj.GetValue(CommandProperty);
}

public static void SetCommand(DependencyObject obj, string value)
{
obj.SetValue(CommandProperty, value);
}

public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached(
name: "Command",
propertyType: typeof(ICommand),
ownerType: typeof(EllipsisButtonControl),
defaultMetadata: new UIPropertyMetadata());
}
}

这行不通。它使设计器崩溃并返回 System.Runtime.Remoting.RemotingException

我认为 EllipsisButtonControl XAML 的 ContentPresenter 上的绑定(bind)是错误的,但我不知道如何使其正确。使该行引用控件内容的适当语法是什么? (例如使用示例中定义的TextBlock)

编辑:

poke 在下面提供了一个全面的答案(包括工作代码),但是为了其他可能会分享我最初误解的人的利益,让我在这里总结一下关键概念:容器控件本身不能“放置内容”。它通过定义一个修改调用 XAML 呈现内容的方式的模板来达到预期的效果。其余的解决方案遵循该前提。

最佳答案

<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>

这确实设置了用户控件的 Content。但用户控件的 XAML 中的以下内容也是如此:

<ContentControl …>
<Grid>

</Grid>
</ContentControl>

调用 XAML 在这里具有优先权,因此无论您在该用户控件的 XAML 中做什么,实际上都会被忽略。

这里的解决方法是设置用户控件的模板。模板,在本例中是控件的控件模板,决定了控件本身的呈现方式。用户控件的最简单模板(也是它的默认模板)就是在那里使用 ContentPresenter,但是当然,您想要围绕它添加一些东西,所以我们必须覆盖模板。这通常看起来像这样:

<ContentControl …>
<!-- We are setting the `Template` property -->
<ContentControl.Template>
<!-- The template value is of type `ControlTemplate` and we should
also set the target type properly so binding paths can be resolved -->
<ControlTemplate>

<!-- This is where your control code actually goes -->

</ControlTemplate>
</ContentControl.Template>
</ContentControl>

现在这是完成这项工作所需的框架。但是,一旦进入控件模板,就需要使用正确的绑定(bind)类型。由于我们写的是模板,想绑定(bind)父控件的属性,所以我们需要在绑定(bind)中指定父控件为相对源。但最简单的方法是使用 TemplateBinding标记扩展。使用它,可以像这样在上面的 ControlTemplate 中放置一个 ContentPresenter:

<ContentPresenter Content="{TemplateBinding Content}" />

为了让内容呈现器正常工作,这应该是您在这里所需的全部内容。

但是,既然您使用了控件模板,当然您还需要调整其他绑定(bind)。特别是绑定(bind)到您的自定义依赖属性 Command。这通常看起来与绑定(bind)到 Content 的模板相同,但由于我们的控件模板针对类型 ContentControlContentControl 没有您的自定义属性,我们需要在此处明确引用您的自定义依赖属性:

<Button Command="{TemplateBinding local:EllipsisButtonControl.Command}" … />

一旦我们有了它,所有的绑定(bind)都应该可以正常工作。 (如果你现在想知道:是的,绑定(bind)总是针对类型的静态依赖属性)


因此,总而言之,您的自定义内容控件应如下所示:

<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
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:WpfApplication1"
d:DesignHeight="30" d:DesignWidth="300" mc:Ignorable="d">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">

<Grid>
<ContentPresenter Grid.Column="0"
Content="{TemplateBinding Content}" />

<Button Grid.Column="1" Content="…"
Command="{TemplateBinding local:EllipsisButtonControl.Command}" />
</Grid>

</ControlTemplate>
</ContentControl.Template>
</ContentControl>

关于c# - 在充当容器的 WPF 控件中,如何放置内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43623601/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com