【问题标题】:XAML - How Do I Bind an Element of a Derived <UserControl> to an Element of the Base <UserControl>?XAML - 如何将派生 <UserControl> 的元素绑定到基础 <UserControl> 的元素?
【发布时间】:2009-07-26 02:27:35
【问题描述】:

如何将派生&lt;UserControl&gt; 的元素绑定到基&lt;UserControl&gt; 的元素?

我已经定义了一个名为 Tile 的 UserControl 作为我的基类。这将是一个抽象基类,如果当我尝试实例化从它派生的对象时 XAML 不会犹豫...

无论如何,到目前为止 Tile 只包含一个依赖属性:OuterShape。它是一个 System.Windows.Shapes.Shape 对象(也是抽象的)。因此:所有图块都将具有某种与其相关联的视觉形状,用于渲染。但是有许多不同类型的 Tiles --- 有些带有 System.Windows.Shapes.Paths,有些带有 System.Windows.Shapes.Polygons,等等。

所以现在我正在研究第一个派生的 UserControl:PolyTile。顾名思义,这是一个使用 System.Windows.Shapes.Polygon 作为其“OuterShape”属性的 Tile。

我遇到的问题是我无法弄清楚如何将 XAML &lt;Polygon&gt; 元素成功绑定到基类中的 Shape 属性。

/************
** Tile.cs **
************/
// This class contains a generic shape, and that's all.
// This class does NOT have a XAML file to go with it. It is purely code implemented.
public class Tile : System.Windows.Controls.UserControl
{
    public static readonly System.Windows.DependencyProperty OuterShapeProperty
        = System.Windows.DependencyProperty.Register(   "OuterShape",
                                                        typeof(System.Windows.Shapes.Shape),
                                                        typeof(Tile));
    public System.Windows.Shapes.Shape OuterShape
    {   get { return (System.Windows.Shapes.Shape)GetValue(OuterShapeProperty); }
        set { SetValue(OuterShapeProperty, (System.Windows.Shapes.Shape)value); }
    }
}

.......................

<!--*****************
*** PolyTile.xaml ***
******************-->
<local:Tile x:Name="__PolyTile__" x:Class="WPFApplication1.PolyTile"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFApplication1">
    <Grid Name="grdMain">
        <Polygon Name="OuterPoly" />
            <!--OuterPoly needs to be data-bound (OneWay)
            to the OuterShape property of the Tile UserControl.
            That way, when my derived class sets OuterShape to a new <Polygon> element,
            OuterShape will show up on the screen as a <Polygon>-->
    </Grid>
</local:Tile>

.......................

/****************
** PolyTile.cs **
****************/
// This class encapsulates a tile that is in the shape of a specified <Polygon> element.
/// <summary>
/// Interaction logic for PolyTile.xaml
/// </summary>
public partial class PolyTile : Tile // Derived from Tile
{
    public PolyTile()
    {
        InitializeComponent();

        System.Windows.Data.BindingExpressionBase BindExp;
        PolyConverter polyConverter = new PolyConverter();

        System.Windows.Data.Binding PolyBinding = new System.Windows.Data.Binding("OuterPoly");
        PolyBinding.Source = __PolyTile__;
        PolyBinding.Mode = System.Windows.Data.BindingMode.OneWayToSource;
        PolyBinding.Converter = polyConverter;
        BindExp = __PolyTile__.SetBinding(Tile.OuterShapeProperty, PolyBinding);
    }



    // The framework won't convert a base object into a derived object without an explicit cast ...
    // ... in this case, that means I have to make a custom DataConverter.
    [System.Windows.Data.ValueConversion(typeof(System.Windows.Shapes.Polygon), typeof(System.Windows.Shapes.Shape))]
    protected class PolyConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {    return value;    }
        // OneWayToSource binding: Thus the Convert method is never used.
        // Rather, ConverBack is used to cast the base <Shape> into a derived <Polygon>

        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value.GetType() == typeof(System.Windows.Shapes.Polygon))
                return value;
            else
                return System.Windows.DependencyProperty.UnsetValue;
        }
    }
}

我看不到在 XAML 中设置此绑定的任何可能方法。 (虽然我对 DataContexts 的理解还不够好,不能说我已经想到了一切……)

因此,我尝试在后台代码中手动设置绑定。我尝试了许多不同的方法来组织绑定路径以及源和目标元素。每次我遇到致命异常或 PathError 或 UpdateSourceError 类似的东西。

有谁知道我做错了什么?
非常感谢任何建议!

【问题讨论】:

    标签: wpf data-binding xaml inheritance dependency-properties


    【解决方案1】:

    你可以通过几种方式做到这一点

    你可以使用相对来源:-

      <TextBlock
         Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ParentUserControl}}, Path=MyProperty}" />
    

    或者您可以使用元素名称绑定,我认为它更易于阅读。 (您必须在用户控件上使用 x:Name 语法来命名 xaml 文件中的整个控件。

      <TextBlock
         Text="{Binding ElementName=childUserControl, Path=MyProperty}" />
    

    here 是我写的一个小测试项目来测试这个

    【讨论】:

    • 这几乎回答了我的问题。您能否稍微改写一下这段代码,以便将子 TextBox 控件绑定到父控件的 TextBox 属性?我正在尝试绑定控件本身-而不仅仅是控件的属性,例如“文本”
    【解决方案2】:

    可以使用 XAML 对象语法来完成。

    重要的是要注意默认数据上下文完美地工作,如果你试图变得非常明确,就会出现问题。 例如: 如果您将ElementName="__PolyTile__" 添加到绑定中,则绑定将失败。

    这个解决方案似乎也不需要数据转换器。这使得代码更容易遵循,尽管可能会以一点类型安全为代价。

    <!--*****************
    *** PolyTile.xaml ***
    ******************-->
    <local:Tile x:Name="__PolyTile__" x:Class="WPFApplication1.PolyTile"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFApplication1">
    
        <local:Tile.OuterShape>
            <Binding Path="OuterPoly" Mode="OneWayToSource" />
        </local:Tile.OuterShape>
    
        <Grid Name="grdMain">
            <Polygon Name="OuterPoly" />
        </Grid>
    
    </local:Tile>
    

    【讨论】:

      猜你喜欢
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      相关资源
      最近更新 更多