链接依赖属性

发布于 2024-12-21 08:41:45 字数 847 浏览 4 评论 0原文

假设我有一个自定义控件,它包装另一个控件(例如 MyCustomButton)。我公开了一个属性 Content,它包装了内部控件:

    public object Content
    {
        get { return innerControl.Content; }
        set { innerControl.Content = value; }
    }

为了让使用者绑定到此属性,我需要为其定义一个 DependencyProperty:

 public static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof (object), typeof (MyCustomButton));

但现在我需要我的属性定义来使用 GetValue/SetValue:

    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

所以我不不再包装内部控件的值。

我可以定义 PropertyMetadata 来处理 DependencyProperty 的 PropertyChanged 事件,但随后我需要一堆管道代码来保持值同步并防止更改时无限环回。

更新:我不能仅仅从 Button 派生,因为我的 UserControl 还有各种其他问题。

有更好的方法吗?

Let's say I have a custom control which wraps another control (for example MyCustomButton). I expose a property Content, which wraps the inner control:

    public object Content
    {
        get { return innerControl.Content; }
        set { innerControl.Content = value; }
    }

In order for a consumer to bind to this property, I need to define a DependencyProperty for it:

 public static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof (object), typeof (MyCustomButton));

but now I need my property definition to use GetValue/SetValue:

    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

so I'm not wrapping the value of the inner control anymore.

I can define PropertyMetadata to handle the PropertyChanged event of the DependencyProperty, but then I need a bunch of plumbing code to keep the values in sync and prevent infinite loopbacks on changed.

UPDATE: I can't just derive from Button because my UserControl has various other concerns.

Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦在深巷 2024-12-28 08:41:45

那么,根据您使用用户控件包装按钮的具体原因,您可以定义一个继承自按钮的自定义控件。然后,您可以简单地重写要定义自定义控件行为的方法和属性,而不是包装按钮并公开所需的包装方法和属性。这样,您将获得按钮的所有功能,而无需重新发明轮子。

这是一个谷歌链接,可以引导您完成它(我发现的第一个链接 - 有很多): http://knol.google.com/k/creating-custom-controls-with-c-net#

如果用户控件有其他问题,这可能不是一个给你的选择,但我提供这个答案是因为您提到的唯一目的是包装按钮。如果所讨论的控件只是意味着更具体类型的包装/继承控件(即您的情况下的按钮),我个人倾向于创建自定义控件并继承,而不是用户控件和包装。

编辑:根据更新的问题...

您可以按照这些思路做一些事情。这是用户控件客户端的 XAML:

<Grid>
    <local:MyControl ButtonContent="Click Me!"/>
</Grid>
</Window>

这是用户控件本身的 XAML:

 <UserControl x:Class="GuiScratch.MyControl"
             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:GuiScratch"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

        <StackPanel>
            <ContentControl Content="Asdf"/>
            <Button Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyControl}},Path=ButtonContent}"/>
        </StackPanel>

    </Grid>
</UserControl>

并且,这是后面的代码:

public partial class MyControl : UserControl
{

    public static readonly DependencyProperty ButtonContentProperty = 
    DependencyProperty.Register("ButtonContent", typeof(object), typeof(MyControl), 
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

    public object ButtonContent
    {
        get { return (object)GetValue(ButtonContentProperty); }
        set { SetValue(ButtonContentProperty, value); }
    }

    public MyControl()
    {
        InitializeComponent();
    }
}

因此,您根本不需要通过代码处理绑定。您的客户端 XAML 绑定到您的依赖项属性,就像用户控件本身的 XAML 一样。通过这种方式,它们共享依赖属性设置。我在我的小草稿本中运行了这个,结果就是(至少我的理解)你正在寻找的东西。主窗口将用户控件显示为带有文本“Asdf”的堆栈面板,然后是带有文本“Click Me!”的按钮。

Well, depending on the particulars of why you're wrapping a button with a user control, you could define a custom control that inherits from button. Then, instead of wrapping the button and exposing the wrapped methods and properties that you want, you can simply override methods and properties whose behavior you want to define the custom control. This way, you'll get all of the functionality of button without the need to reinvent the wheel.

Here's a google link that walks you through it (one of the first that I found - there are plenty): http://knol.google.com/k/creating-custom-controls-with-c-net#

If the user control has other concerns, this may not be an option for you, but I'm offering this answer because the only purpose that you've mentioned for it is wrapping the button. I'd personally favor creating a custom control and inheriting rather than a user control and wrapping if the control in question is simply meant to be a more specific kind of wrapped/inherited control (i.e. button in your case).

Edit: In light of updated question...

You could do something along these lines. Here is the XAML of the client of your user control:

<Grid>
    <local:MyControl ButtonContent="Click Me!"/>
</Grid>
</Window>

Here is the XAML for the user control itself:

 <UserControl x:Class="GuiScratch.MyControl"
             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:GuiScratch"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

        <StackPanel>
            <ContentControl Content="Asdf"/>
            <Button Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyControl}},Path=ButtonContent}"/>
        </StackPanel>

    </Grid>
</UserControl>

And, here is the code behind:

public partial class MyControl : UserControl
{

    public static readonly DependencyProperty ButtonContentProperty = 
    DependencyProperty.Register("ButtonContent", typeof(object), typeof(MyControl), 
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

    public object ButtonContent
    {
        get { return (object)GetValue(ButtonContentProperty); }
        set { SetValue(ButtonContentProperty, value); }
    }

    public MyControl()
    {
        InitializeComponent();
    }
}

So, you don't need to handle the binding at all through code. Your client XAML binds to your dependency property, as does the XAML of the user control itself. In this fashion, they share the dependency property setting. I ran this in my little scratchpad, and the result is (at least my understanding of) what you're looking for. The main window displays the user control as a stack panel with the text "Asdf" and then a button with the text "Click Me!"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文