[英]WPF binding not being set to UserControl DependencyProperty
[英]WPF in a usercontrol set a controltemplate's content to the value of a dependencyproperty
我对WPF还是很陌生,(现在已经使用了3周),所以我可能会缺少一些愚蠢的东西,或者不了解自己在做什么!
我试图创建一个模态类型的弹出窗口,该窗口将覆盖整个应用程序或它所在的当前控件。我希望此控件是半透明的,以便用户仍然可以看到其背后的内容,但无法使用它。 然后,他们将能够完成模式窗口中的所有内容,然后再继续。
我不想在不同的地方重复代码,所以我的目标是拥有一个可以在XAML中使用的通用控件,而每次都只需添加所需的内容。 也就是说,褪色,透明度,背景色都在一个地方处理,我只需要为其特定实例添加特定功能即可。
到目前为止,我已经创建了一个名为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>
我为控件提供了如下代码:
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;
}
}
}
我可以将其添加到另一个用户控件中,如下所示:
<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”上设置断点,则可以看到传入的新内容,但它永远不会在运行时显示。
我不知道我是不是要解决所有这些错误,是否有可能,或者是否只需要tweeking。 对此,任何有关此类情况的建议都将不胜感激。
虽然这不是直接解决问题的方法,但是您应该将内容放入控件中,而不要使用依赖项属性,因为可读性要好得多。 代替使用UserControl,创建扩展ContentControl的类:
public class jonblind : ContentControl
{
[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;
}
}
然后使用样式指定内容
<Style TargetType="control:jonblind">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="control:jonblind">
<Grid>
<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 Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
最后-使用它
<control:jonblind IsContentVisible="{Binding Path=ShowBlind}">
<StackPanel>
<TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" />
<Button Content="hide me!" Command="{Binding Path=alternateblind}" />
</StackPanel>
</control:jonblind>
(此示例改编自该线程: 如何创建具有NAMED内容的WPF UserControl )
这是WPF中的一种常见模式,许多内置控件都使用它,它们来自ContentControl(1个子内容),HeaderedContentControl(2个子内容)或ItemsControl(n个孩子的集合)。 通常,Content属性(在运行时将被替换为占位符的东西)应为object类型。 在这种情况下,您也可以摆脱变更处理程序,而仅依靠数据绑定。
[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中。
<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)的样子:
<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时,可以轻松完成所需的操作。
对于遇到与此问题类似但在其他地方找不到答案的任何人:
如果要将子控件的属性绑定到用户控件中的依赖项属性,然后再将其绑定到UI中的该依赖项属性,如下所示:
<Page>
<my:usercontrol MyCustomPoperty="{Binding MyData}"/>
</Page>
您必须执行以下操作(花我几个小时来弄清楚):
<UserControl x:Class="my.usercontrol">
<TextBox Text="{Binding MyCustomProperty}">
</UserControl>
在构造函数后面的代码中:
public usercontrol()
{
InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
}
这会将您组成的控件的DataContext设置为usercontrol,因此这些控件可以绑定到自定义的Dependency属性,同时保留您的UI设置的DataContext(此示例中的页面)。
现在,您的UI更新了用户控件的MyCustomProperty,而后者又更新了绑定到它的用户控件中的TextBox。
资料来源: http : //blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.