WPF依赖项属性绑定中断并始终使用默认值

时间:2014-02-13 15:47:04

标签: c# .net wpf xaml prism

我有一个依赖属性定义如下。它在Childusercontrol的xaml.cs中定义。它总是使用 RGB的默认值(255,0,0)即。红色

public Color ForeColor
{
    get {return (Color)this.GetValue(ForeColorProperty); }
    set {this.SetValue(ForeColorProperty, value);}
}

public static readonly DependencyProperty ForeColorProperty = DependencyProperty.Register("ForeColor", typeof(Color), typeof(Childusercontrol), new PropertyMetadata(Color.FromRgb(255,0,0), OnCurrentForeColorPropertyChanged));

private static void OnCurrentForeColorPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{    
    Childusecontrol control = source as Childusecontrol;
    Color fcolor= (Color)e.NewValue;
}

该值通过xaml从父usercontrol传递为

<UC:Childusercontrol ForeColor="{Binding ChildForeColor}"/>
  

ChildForeColor是ParentUserControl的ViewModel中Color类型的属性,定义如下。

 private Color _ChildForeColor;
    public Color ChildForeColor 
    {
    get
    {
    return _ChildForeColor ;
    }
    set
    {
    if (_ChildForeColor  != value)
    {
    _ChildForeColor  = value;
    RaisePropertyChanged(()=> ChildForeColor );
    }
    }
    }

ChildForeColor属性在parentusercontrol的构造函数中设置如下。

  

作为构造函数参数传递的值为蓝色

public Parentusercontrol(System.Drawing.Color ForeColor)
{
ChildForeColor  = Color.FromRgb(ForeColor.R, ForeColor.B, ForeColor.G);
}

但是,Parent控件的InitializeComponent(); xaml.cs会清除依赖属性的值,因此只使用默认值。

我是否必须更改依赖属性的定义?如何解决这个错误?

2 个答案:

答案 0 :(得分:1)

这对我来说非常好!

  1. ChildControl

    我给了UserControl一个Xaml的名字,即

    <UserControl ... (all normal namespaces)... x:Name="Child">
        <Border>
           <Border.Background>
                <SolidColorBrush Color="{Binding ForeColor, ElementName=child}"/>
            </Border.Background>
        </Border>
    </UserControl>
    

    属性“ForeColor”是您自己定义的依赖属性。此控件也可以完美地运行。

  2. ParentControl

    我和ChildControl一样。即给它一个名字。

    <UserControl ... (Usual NS)... x:Name="parent">
        <Border BorderThickness="2">
            <local:ChildUserControl Margin="5" ForeColor="{Binding ChildForeColor, ElementName=parent}"/>
            <Border.BorderBrush>
                <SolidColorBrush Color="{Binding ChildForeColor, ElementName=parent}"/>
            </Border.BorderBrush>
        </Border>
    </UserControl>
    

    这也适用于测试C#Class外观如下

    public ParentUserControl(System.Drawing.Color c)
    {
        InitializeComponent();
        Color c2 = Color.FromRgb(c.R, c.G, c.B);
        ChildForeColor = c2;
    
    }
    
    private Color _ChildForeColor = Color.FromRgb(0, 255, 0);
    public Color ChildForeColor
    {
        get { return _ChildForeColor; }
        set
        {
            if (value != _ChildForeColor)
            {
                _ChildForeColor = value;
                OnPropertyChanged(() => ChildForeColor);
            }
        }
    }
    

    我已经为_ChildForeColor分配了一个仅用于测试的值,但这不是必需的。但请注意,如果运行NotifyPropertyChanged事件,则在InitializeComponent()之前不会发生这种情况。我想这是因为还没有任何东西被初始化来听取变化。因此,您有2个选项。删除OnPropertyChanged并在InitializeComponent之前指定颜色,或使用OnPropertyChanged但仅在InitializeComponent之后指定颜色。第一个解决方案仍然有效,因为在组件运行之前更改了属性值并查找该值。

  3. 使用构建控件的窗口

    由于您已经分配了一个带变量的构造函数,因此这有点棘手。所以我的代码如下:

    public Control ParContent
    {
        get { return (ContentControl)GetValue(ParContentProperty); }
        set { SetValue(ParContentProperty, value); }
    }
    
    //Register Dependency ParContent Property
    public static readonly DependencyProperty ParContentProperty = DependencyProperty.Register("ParContent", typeof(ContentControl), typeof(MainWindow), new PropertyMetadata( ));
    
    public MainWindow()
    {
       InitializeComponent();  
       ParContent = new ParentUserControl(System.Drawing.Color.Blue);
    }
    

    和Xaml

    <Window ...Title="MainWindow" Height="478.784" Width="736.87" x:Name="win">
        <Grid>
            <local:ChildUserControl HorizontalAlignment="Left" Height="100" Margin="122,298,0,0" VerticalAlignment="Top" Width="100"/>
            <ContentControl x:Name="Parent" Content="{Binding ParContent,ElementName=win}" HorizontalAlignment="Left" Margin="106,49,0,0" VerticalAlignment="Top" Height="79" Width="93"/>
        </Grid>
    </Window>
    
  4. 正如我所说,这对我来说非常好,并且所有属性都保留了它们的价值。

答案 1 :(得分:0)

可能的解决方案:

  1. 确保父级的childForeColor具有分配给它的颜色,尤其是在使用普通属性时。

  2. 如果您在Parent控件中使用普通属性,请确保在Initialize(我猜您已订阅)之后更改颜色时调用INotifyPropertyChange

  3. 或许使用FrameworkPropertyMetadata,然后添加标志AffectsRender - 不要认为这是问题,但值得一试

  4. 使用绑定模式 - 虽然我不认为这是真正的问题

  5. 如果您正在使用2个x控件,其中1个属性最有可能从其他属性继承,请使用Inherited属性 - http://msdn.microsoft.com/en-us/library/ms753197(v=vs.110).aspx

  6. 底线我怀疑父母的“ChildForeColor”可能导致问题,因为上面的内容对我来说乍一看似乎没问题。

    修改

    尝试执行以下操作。在xaml中为您的父控件命名为x:name =“Parent”,然后在绑定模式下执行此操作

    <UC:Childusercontrol ForeColor="{Binding ChildForeColor, ElementName="Parent"}"/>
    

    如果问题出在绑定上,这应该解决任何绑定问题。

    但是你说“父控件的xaml.cs会清除依赖属性的值,因此只使用默认值。”这表明问题不是绑定,也不是我可以收集的子控件...

    我还假设你已经完成了代码,所以在你点击这个

    之后
    ChildForeColor  = Color.FromRgb(ForeColor.R, ForeColor.B, ForeColor.G);
    

    ChildForeColor显示正确,然后如果重写OnInitialized()并在base.OnInitialized(e)之后计算ChildForeColor的值;已经运行的ForeColor仍未改变?

    有了这个,我还假设你没有从构造函数中删除InitializeComponent(); ,以及InitializeComponent();来自ChildForeColor = ....!在你的构造函数中,你没有显示InitializeComponent()的位置,我认为这只是为了方便阅读。

    如果此时ForeColor保持不变并且假设为base.OnInitialized是在OnInitialized中运行的第一个方法。然后初始化不是问题,那么替代建议是将ChildForeColor更改为适当的依赖属性:

    public Color ChildForeColor
        {
            get { return (Color)GetValue(ChildForeColorProperty); }
            set { SetValue(ChildForeColorProperty, value); }
        }
    
        //Register Dependency ChildForeColor Property
        public static readonly DependencyProperty ChildForeColorProperty = DependencyProperty.Register("ChildForeColor", typeof(Color), typeof(ParentControl), new FrameworkPropertyMetadata());
    

    并查看是否会改变它。