FrameworkElement是ContentControl

时间:2016-08-04 12:25:50

标签: c# wpf binding styling contentcontrol

我从一个复杂的实际项目中创建了一个较小的测试项目,但想法是一样的。两者都有同样的问题。

我有两个类,A和B.A是一种ContentControl,B是一种FrameworkElement。 A具有依赖属性Bee(B的类型)。 B具有依赖属性Text(字符串的类型)。 A的默认值为null,B的默认值为" B There!"。

我在测试窗口(Window.Resources)中使用样式将B&#39的Text属性设置为默认值以外的其他属性。

<Window.Resources>
    <Style TargetType="local:B">
        <Setter Property="Text" Value="YO!!!"/>
    </Style>
</Window.Resources>

当我将A.Content设置为B的新实例时,一切都像魅力一样,因为系统处理所有事情。即当我在Visual Studio的设计器中更改样式设置器的值时,它会更改相应的属性值(B.Text)。数据绑定也很好。

<local:A.Content>
    <local:B/>
</local:A.Content>

我真正需要的是......

由于我无法控制的原因,我无法使用A.Content,因此我创建了一个新的B实例并将其设置为A.Bee属性。在这种情况下,隐式样式和数据上下文继承不起作用。即当我更改样式设置器的值时,没有任何反应,数据绑定也不起作用。

<local:A.Bee>
    <local:B/>
</local:A.Bee>

在A.Bee属性值更改回调中我使用AddLogicalChild,AddVisualChild和数据绑定将B实例放入树中并使数据绑定工作。即当A.Bee设置时,下面发生(简化)......

private static void BeeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    A instanceOfA = d as A;
    B newValue = e.NewValue as B;

    Binding b = new Binding("DataContext");
    b.Source = instanceOfA;

    BindingOperations.SetBinding(newValue, B.DataContextProperty, b);

    instanceOfA.AddLogicalChild(newValue);
    instanceOfA.AddVisualChild(newValue);
}

这解决了数据绑定问题。不确定这是否是正确的方法,但它的工作原理。如果有更好的方法,请告诉我。但是,样式仍然无法在Visual Studio的设计器中使用。

如何在Visual Studio的设计器中更改样式设置器的值时,如何绑定样式值以便更改属性值?

在使用AddLogicalChild之前,newValue的资源没有样式,所以我想我在正确的轨道上但不完全在那里,但是......

如果有人想测试/修改它,我可以在项目中添加链接。

这是测试解决方案的链接(Visual Studio 2013):FEStyleTesting

简而言之,我希望将A.Bee属性设置为B类的实例,就像使用B类实例设置A.Content属性一样。即使用Visual Studio Designer时,数据上下文和样式将继承到B类的实例。

Debugging designer

在图像中,我正在调试设计器,正如您所看到的,可以在调用AddLogicalChild之后从资源中找到样式设置器,但由于某种原因,样式未应用于设计器中...在设计师中,还有InstantietedElementViewNode属性的第三个设置器。即在运行时它没有。也许它是设计师为每个控件添加的东西......前两个setter是在XAML中定义的(忘了为图片展开它们)。

只是为了澄清,在测试应用程序中,想法是使用消息框进行测试。即我不需要改变视觉外观(使用Content属性时会这样做)。只需在XAML中更改样式设置器值时调用回调。

以下是测试此问题的步骤:

  1. 打开解决方案。
  2. 确保没有打开源标签页。
  3. 重建解决方案以防万一。
  4. 打开MainWindow.xaml(双击它)。
  5. 点击&#34;确定&#34;如果出现消息框,则按钮。
  6. 确保第一项作业在&#34;这些作品不能正常工作&#34;没有注释,其他三个被注释掉了。 (由于某种原因,无法在此列表中获取源代码......)
  7. 现在将Text属性的样式设置器的值更改为例如&#34; YO 2 !!!&#34;
  8. A&#34; TextChanged&#34;编辑值后应出现消息框(但不是)。
  9. B是故意从ContentControl(而不是FrameworkElement)派生的,因此我可以在使用A.Content属性时验证数据绑定和样式继承。 ContentControl派生自FrameworkElement,因此结果应该相同。 FrameworkElement用于我的大型项目。

    Debugging style value change.

    在调试设计师时,我改变了#34; YO !!!&#34;到&#34; YO2 !!!&#34;然后在XAML中显式更改了B.Color。然后在ColorChanged回调中,我查看了B实例的资源,发现该值已相应更改。因此,当我在XAML中更改样式值时,样式值会更新,但由于某些原因它们不会更改属性值(文本仍然是#34; YO !!!&#34;)...因此,没有调用回调

    我想知道是什么原因造成的......

    我可能找到了可能的解决方案。我注意到即使我调用AddLogicalChild,A.LogicalChildren也没有包含B对象。然后我经历了可覆盖的方法并遇到了可覆盖的LogicalChildren属性。

    这是我的版本:

    protected override IEnumerator LogicalChildren
    {
        get
        {
            List<object> list = new List<object>();
    
            while (base.LogicalChildren.MoveNext() == true)
            {
                try
                {
                    list.Add(base.LogicalChildren.Current);
                }
                catch
                {
                    // If Current fails, break.
                    break;
                }
            }
    
            list.Add(Bee);
    
            return list.GetEnumerator();
        }
    }
    

    不确定这是否是&#34;终极&#34;解决方案,但现在每次更改样式设置器值时,都会调用我的属性更改回调。好吧,生活和学习......更好地测试一下。

1 个答案:

答案 0 :(得分:0)

因此问题的答案是覆盖LogicalChildren属性以包含嵌套对象。这也将消除BindingOperations绑定到DataContext的需要。仍然需要AddLogicalChild。不确定AddVisualChild但是比抱歉更安全......