XAML - How Do I Bind an Element of a Derived <UserControl> to an Element of the Base <UserControl>?
如何将派生
我已经定义了一个名为 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /************ ** 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); } } } |
.......................
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!--***************** *** 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> |
.......................
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /**************** ** 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 类似的东西。
有谁知道我做错了什么?
非常感谢任何建议!
你可以通过几种方式做到这一点
你可以使用相对来源:-
1 2 | <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ParentUserControl}}, Path=MyProperty}" /> |
或者您可以使用元素名称绑定,我认为它更易于阅读。 (您必须在用户控件上使用 x:Name 语法来命名 xaml 文件中的整个控件。
1 2 | <TextBlock Text="{Binding ElementName=childUserControl, Path=MyProperty}" /> |
这是我写的一个小测试项目来测试这个
可以使用 XAML 对象语法来完成。
重要的是要注意默认数据上下文完美地工作,如果你试图变得非常明确,就会出现问题。例如:如果将
这个解决方案似乎也不需要数据转换器。这使得代码更容易理解,尽管可能会以一些类型安全为代价。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!--***************** *** 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> |