【问题标题】:WPF XAML - Property update in nested controlsWPF XAML - 嵌套控件中的属性更新
【发布时间】:2014-06-13 14:53:19
【问题描述】:

我有一个以这种方式公开名为HeaderText 的字符串属性的控件:

public partial class HeaderControl : UserControl
{
    public static DependencyProperty HeaderTextProperty;    

    [Category("Header Properties")]
    public string HeaderText
    {
        get { return (string)GetValue(HeaderTextProperty); }
        set { SetValue(HeaderTextProperty, value); }
    }

    static HeaderControl()
    {
        HeaderTextProperty = DependencyProperty.Register("HeaderText", typeof(string), typeof(HeaderControl), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    }

    public HeaderControl()
    {
        this.DataContext = this;
        InitializeComponent();
    }
}

HeaderControl 的 Xaml:

<UserControl x:Class="Col.HMI.Controls.HeaderControl"
     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">

<Border Background="{Binding Path=HeaderBackground}" >
    <TextBlock Text="{Binding Path=HeaderText}" Foreground="White" TextAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Stretch" FontFamily="Segoe UI Light" FontSize="36" Margin="5"/>
</Border>

我想在另一个用户控件中使用这个HeaderControl,这样:

OtherControl 的 Xaml:

<controls:HeaderControl Grid.Row="0" HeaderText="DEMO" />

这可以毫无问题地工作。 但是如果我将HeaderText 属性绑定到OtherControl ViewModel 中的字符串属性,这样:

    <controls:HeaderControl Grid.Row="0" HeaderText="{Binding Path=SummaryTitle}" />

绑定不起作用。

这是 OtherControl ViewModel 中的 SummaryTitle 属性:

public string SummaryTitle
{
    get 
    { 
        return _summaryTitle; 
    }
    set 
    { 
        _summaryTitle = value; OnPropertyChanged("SummaryTitle"); 
    }
}

PS:我有其他控件绑定到 OtherControl 视图模型,它们运行良好。

【问题讨论】:

    标签: wpf xaml mvvm binding


    【解决方案1】:

    您通过这样做在构造函数中将 HeaderControl 的 DataContext 设置为自身:

    this.DataContext = this;
    

    这意味着,当您将某些绑定应用到 HeaderControl 中的任何属性时,绑定引擎会尝试在此控件中找到绑定的属性(在您的情况下为 SummaryTitle),但它不会找到并且会失败。

    因此,要解决您的问题,请不要在构造函数中将 HeaderControl 的 DataContext 设置为自身,Binding 引擎将尝试在正确的 DataContext 中查找属性。

    将您的 HeaderControl 构造函数更新为以下内容,绑定应该开始工作:

    public HeaderControl()
    {
        InitializeComponent();
    }
    


    更新

    您在这里尝试做的是,您希望在您的 UserControl 中有名为 HeaderText 的 DependencyProperty,以便可以通过 DataBinding 设置它的值,然后在您的 UserControl 中使用该值更新 TextBlock 的值的 DependencyProperty。

    您可以通过两种方式实现:

    1) 通过更新 TextBlock Binding 以使用 ElementNme 和 Path 语法,XAML 将如下所示:

    <UserControl x:Class="WpfApplication1.HeaderControl"
                 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"
                 x:Name="_This">
        <Grid>
            <TextBlock Text="{Binding ElementName=_This, Path=HeaderText}" FontSize="24" />
        </Grid>
    </UserControl>
    

    使用这种方法,每当属性 HeaderText 通过绑定或显式设置值发生更改时。

    2) 通过监听HeaderText 属性的属性值更改事件,然后相应地更新TextBlock

    对于这种方法,您的 HeaderControl.xaml 将如下所示:

    <UserControl x:Class="WpfApplication1.HeaderControl"
                 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>
            <TextBlock x:Name="TextBlockInUserControl"/>
        </Grid>
    </UserControl>
    

    和 HeaderControl.xaml.cs

    public partial class HeaderControl : UserControl
    {
        public static readonly DependencyProperty HeaderTextProperty;
    
        [Category("Header Properties")]
        public string HeaderText
        {
            get { return (string)GetValue(HeaderTextProperty); }
            set { SetValue(HeaderTextProperty, value); }
        }
    
        static HeaderControl()
        {
            HeaderTextProperty = DependencyProperty.Register("HeaderText", typeof (string), typeof (HeaderControl),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnHeaderTextPropertyChanged));
        }
    
        private static void OnHeaderTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var headerControl = (HeaderControl) dependencyObject;
            headerControl.UpdateTextBlock((string) dependencyPropertyChangedEventArgs.NewValue);
        }
    
        void UpdateTextBlock(string text)
        {
            TextBlockInUserControl.Text = text;
        }
    
        public HeaderControl()
        {
            InitializeComponent();
        }
    }
    

    【讨论】:

    • 如果我正确理解 OP,SummaryTitle 属性不在HeaderControl 内。因此,您的答案似乎不正确。
    • @fmunkert 我想,这就是我提到的:SummaryTitle 不是 HeaderControl 的一部分,但 BindingEngine 会尝试在 HeaderControl 中找到它,因为他将 DataContext 设置为自身。因此,在我的回答中,我要求 OP 不要在其构造函数中将 HeaderControl 的 DataContext 设置为自身,以便 Binding 引擎将在正确的 DataContext 中查找 SummaryTitle。
    • 我误解了你的回答;我的印象是你想表达完全相反的意思。很抱歉。
    • @fmunkert 没问题。为了更清楚,我更新了我的答案。
    • 这不起作用。删除 this.DataContext = this 绑定不起作用,如果我手动设置标题(如 HeaderText="foo")它也不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2013-08-16
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多