XAML - 如何绑定派生的的元素 到基本的元素?
如何将派生
的元素绑定到基础
的元素?
我定义了一个名为 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
元素绑定到基类中的 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 类似的情况时。
有谁知道我做错了什么?
任何意见是极大的赞赏!
How do I bind an element of a derived <UserControl>
to an element of the base <UserControl>
?
I have defined a UserControl called Tile as my base class. This would be an abstract base class, if XAML wouldn't balk when I tried to instantiate an object derived from it ...
Anyway, so far Tile only contains a single dependency property: OuterShape. It is a System.Windows.Shapes.Shape object (also abstract). Thus: all tiles will have some kind of visual shape associated with them, for rendering. But there are many different types of Tiles --- some with System.Windows.Shapes.Paths, some with System.Windows.Shapes.Polygons, etc.
So now I am working on the first derived UserControl: PolyTile. As the name implies, this is a Tile that uses a System.Windows.Shapes.Polygon as its "OuterShape" property.
The problem I am running into is that I can't figure out how to successfully bind the XAML <Polygon>
element to the Shape property in the base class.
/************
** 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;
}
}
}
I don't see any possible way to set this binding in XAML. (Although I don't understand DataContexts well enough to say that I've thought of everything ...)
Therefore, I tried setting the binding manually in the back-code. I've tried many different ways of organizing the binding path and source and target elements. Every time I get a fatal exception or a PathError or an UpdateSourceError something similar.
Does anyone know what I am doing wrong?
Any advice is greatly appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以通过几种方式来执行此操作,
您可以使用相对源: -
或者您可以使用元素名称绑定,我认为这更容易阅读。 (您必须在用户控件上使用 x:Name 语法来命名 xaml 文件中的整个控件。
这里是我写的一个小测试项目来测试这个
you can do this a couple of ways
you can use relative source: -
or you can use element name bindings, which i think are easier to read. (you have to use the x:Name syntax on the user control to name the whole control in the xaml file.
here is a little test project i wrote to test this
可以使用 XAML 对象语法来完成。
需要注意的是,默认数据上下文工作得很好,如果您尝试变得非常明确,就会出现问题。 例如:如果将
ElementName="__PolyTile__"
添加到绑定,绑定将会失败。该解决方案似乎也不需要数据转换器。 这使得代码更容易理解,尽管可能会牺牲一点类型安全性。
It can be done using XAML object-syntax.
It is important to note that the default data context works perfectly, and problems will arise if you attempt to get very explicit. For example: The binding will fail if you add
ElementName="__PolyTile__"
to the binding.It also appears that the data-converter is not required in this solution. That makes the code much easier to follow, though perhaps at the cost of a little type-saftey.