用户控件中的WPF将控件模板的内容设置为依赖项属性的值 [英] WPF in a usercontrol set a controltemplate's content to the value of a dependencyproperty

查看:118
本文介绍了用户控件中的WPF将控件模板的内容设置为依赖项属性的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对WPF还是很陌生,(现在已经使用了3周),所以我可能缺少一些愚蠢的东西,或者不了解自己在做什么!

I am pretty new to WPF, (using it for 3 weeks now), so I might be missing something stupid or not understanding what I am doing!

我我正在尝试创建一个模态类型的弹出窗口,该窗口将覆盖整个应用程序或它所在的当前控件。我希望此控件是半透明的,以便用户仍可以看到背后的内容,但无法使用它。然后,他们将能够完成模式窗口中的所有内容,然后再继续。

I am trying to create a modal type popup window that would cover either the whole application or current control it is in. I want this control to be semi transparent so the user can still see the content behind but not be able to use it. They will then be able to complete what ever is in the modal window before continuing.

我不想在不同的地方重复代码,所以我的目标是我可以在XAML中使用的通用控件,而每次只需添加我需要的内容。即褪色,透明度,额外的背景色都在一个地方处理,我只需要为该实例添加特定功能。

I do not want to have to repeat code in different places so my goal is to have a generic control that I can use in my XAML and only have to add the content I need each time. I.e. the fading, transparency, background colour extra are all handled in one place and I only have to add the specific functionality for that instance of it.

到目前为止,我已经创建了一个名为jonblind的usercontrol:

So far I have created a usercontrol called jonblind:

<UserControl x:Class="ShapInteractiveClient.View.SampleTests.jonblind"
         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="300" d:DesignWidth="300">


<Grid x:Name="blindGrid" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
      Opacity="0.82">
    <Grid.Background>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0" MappingMode="RelativeToBoundingBox">
            <GradientStop Color="#FFA8CBFE" Offset="1"/>
            <GradientStop Color="Red"/>
            <GradientStop Color="#FFE1EDFE" Offset="0.147"/>
        </LinearGradientBrush>
    </Grid.Background>

    <ContentControl x:Name="contentTemplateArea" />

</Grid>

</UserControl>

我为控件提供了以下代码:

I have a code behind for the control as follows:

public partial class jonblind : UserControl
{
    public jonblind()
    {
        InitializeComponent();
        SetVisibility(this);
    }

    [Category("jonblind")]
    public bool IsContentVisible
    {
        get { return (bool)GetValue(IsContentVisibleProperty); }
        set { SetValue(IsContentVisibleProperty, value); }
    }

    public static readonly DependencyProperty IsContentVisibleProperty = DependencyProperty.Register("IsContentVisible", typeof(bool), typeof(jonblind),
        new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsOverlayContentVisibleChanged)));

    private static void OnIsOverlayContentVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        jonblind blind = d as jonblind;
        if(blind != null)
            SetVisibility(blind);
    }

    private static void SetVisibility(jonblind blind)
    {
        blind.blindGrid.Visibility = blind.IsContentVisible ? Visibility.Visible : Visibility.Hidden;
    }



    [Category("jonblind")]
    public ContentControl ContentAreaControl
    {
        get { return (ContentControl)GetValue(ContentAreaControlProperty); }
        set { SetValue(ContentAreaControlProperty, value); }
    }

    public static readonly DependencyProperty ContentAreaControlProperty = DependencyProperty.Register("ContentAreaControl", typeof(ContentControl), typeof(jonblind),
        new FrameworkPropertyMetadata(new PropertyChangedCallback(OnContentAreaControlChanged)));

    private static void OnContentAreaControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        jonblind blind = d as jonblind;
        if (blind != null && e.NewValue != null && e.NewValue is ContentControl)
        {
            blind.contentTemplateArea = e.NewValue as ContentControl;
        }
    }
}

我可以将其添加到另一个用户控件如下:

I can add it to another usercontrol as follows:

<UserControl.Resources>
<ContentControl x:Key="testcontrol">
        <StackPanel>
            <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" />
            <Button Content="hide me!" Command="{Binding Path=alternateblind}" />
        </StackPanel>
    </ContentControl>
</UserControl.Resources>

<SampleTests:jonblind IsContentVisible="{Binding Path=ShowBlind}" ContentAreaControl="{StaticResource testcontrol}" />

如果我在 OnContentAreaControlChanged上设置了一个断点,我可以看到正在传递的新内容,但是永远不会在运行时显示它。

If I put a break point on "OnContentAreaControlChanged" I can see the new content being passed in but it will never display it at runtime.

我不知道我是否会出错,是否有可能,或者是否只需要tweeking。对此,任何有关此类情况的建议都将不胜感激。

I don't know if I am going about this all wrong, if it is even possible or if it just needs tweeking. Any and all advice on this and dealing with this kind of scenario would be greatly appreciated.

推荐答案

这是WPF中的一种常见模式,很多ContentControl派生的内置控件都使用了这种模式(子内容),HeaderedContentControl(2个子内容)或ItemsControl(n个孩子的集合)。通常,Content属性(在运行时将被替换为占位符的东西)应为object类型。在这种情况下,您也可以摆脱更改处理程序而只依赖数据绑定。

This is a common pattern in WPF that is used by a lot of the built in controls deriving from ContentControl (1 piece of child content), HeaderedContentControl (2 pieces of child content), or ItemsControl (a collection of n children). In general, the Content properties (the stuff that will be substituted into placeholders at runtime) should be of type object. You can also get rid of the change handler and just rely on data binding in this situation.

[Category("jonblind")]
public object ContentAreaControl
{
    get { return GetValue(ContentAreaControlProperty); }
    set { SetValue(ContentAreaControlProperty, value); }
}

public static readonly DependencyProperty ContentAreaControlProperty = 
    DependencyProperty.Register("ContentAreaControl", typeof(object), typeof(jonblind),
    new FrameworkPropertyMetadata(null));

使用此新的Content属性,您可以使用ContentPresenter设置绑定,该绑定仅用作传入的内容的占位符。这在从ContentControl派生的自定义控件中进行设置更加容易,在该控件中ContentPresenter可以在ControlTemplate内自动连接到Content。

With this new Content property you can then set up a Binding using a ContentPresenter, which simply acts as a placeholder for your Content that's passed in. This is even easier to set up in custom controls derived from ContentControl where the ContentPresenter can be wired up to the Content automatically inside a ControlTemplate.

<UserControl x:Class="ShapInteractiveClient.View.SampleTests.jonblind"
         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="300" d:DesignWidth="300">

<Grid x:Name="blindGrid" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
      Opacity="0.82">
    <Grid.Background>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0" MappingMode="RelativeToBoundingBox">
            <GradientStop Color="#FFA8CBFE" Offset="1"/>
            <GradientStop Color="Red"/>
            <GradientStop Color="#FFE1EDFE" Offset="0.147"/>
        </LinearGradientBrush>
    </Grid.Background>

    <ContentPresenter Content="{Binding Path=ContentAreaContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />

</Grid>
</UserControl>

通常,将UIElement实例声明为Resources是一个坏主意(最好将其放置在Template Resources中)但是我们可以像对待其他控件一样轻松解决该问题。这样的用法就更像ContentControl(如Button)的样子:

In general it's a bad idea to declare UIElement instances as Resources (prefer placing them inside Template Resources instead) but we can get around that issue easily by treating this like any other control. The usage is then much more like what a ContentControl (like Button) looks like:

<SampleTests:jonblind IsContentVisible="{Binding Path=ShowBlind}">
    <SampleTests:jonblind.ContentAreaControl>
        <StackPanel>
            <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" />
            <Button Content="hide me!" Command="{Binding Path=alternateblind}" />
        </StackPanel>
    </SampleTests:jonblind.ContentAreaControl>
</SampleTests:jonblind>

作为自定义ContentControl而不是UserControl,您可以获得更多好处,但是一些增加的复杂性和对概念的更好理解通常有助于使其正确运行。开始使用UserControl时,可以轻松完成所需的操作。

You can get even more advantages from doing this as a custom ContentControl instead of a UserControl, but there is some added complexity and a better understanding of the concepts is generally helpful to make it work correctly. While you're starting out sticking with a UserControl can make it simpler to get what you need done.

这篇关于用户控件中的WPF将控件模板的内容设置为依赖项属性的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆