我将一些业务对象绑定到WPF ItemsControl。它们使用自定义IValueConverter实现来显示,该实现用于为DataTemplate中的Path对象生成Geometry,如下所示:
<ItemsControl x:Name="Display"
Background="White"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding ElementName=ViewPlaneSelector,
Path=SelectedItem.VisibleElements}"
>
<ItemsControl.Resources>
<!-- This object is just used to get around the fact that ConverterParameter
can't be a binding directly (it's not a DependencyProperty on a DependencyObject -->
<this:GeometryConverterData
x:Key="ConverterParameter2"
Plane="{Binding ElementName=ViewPlaneSelector,
Path=SelectedItem}" />
<DataTemplate DataType="{x:Type o:SlenderMember}">
<Path Stroke="Blue" StrokeThickness=".5"
Data='{Binding Converter={StaticResource SlenderMemberConverter},
ConverterParameter={StaticResource ConverterParameter2}}'
ToolTip="{Binding AsString}">
</Path>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
请注意,ItemsControl的项目是从ViewPlaneSelector(ComboBox)SelectedItem.VisibleElements属性中提取的。我需要在SlenderMemberConverter中使用相同的ViewPlaneSelector.SelectedItem来弄清楚如何显示这个元素。我试图通过在参考资料部分创建中间的GeometryConverterData对象来将它引用到转换器中。此对象仅用于解决无法直接绑定到ConverterParameter属性的问题(如注释中所述)。以下是GeometryDataConverter类的代码:
class GeometryConverterData : FrameworkElement {
public static readonly DependencyProperty PlaneProperty =
DependencyProperty.Register("Plane", typeof(ViewPlane),
typeof(GeometryConverterData), null, ValidValue);
public static bool ValidValue(object o){
return true;
}
public ViewPlane Plane {
get{
return GetValue(PlaneProperty) as ViewPlane;
}set{
SetValue(PlaneProperty, value);
}
}
}
我添加了ValidValue函数进行调试,看看这个属性绑定了什么。它只会始终设置为null。我知道ViewPlaneSelector.SelectedItem并不总是为null,因为ItemsControl有项目,而且它的项目是从同一对象的同一属性中提取的......所以给出了什么?如何将这个ComboBox引用到我的ValueConverter中。
或者,或者,为什么我正在做的愚蠢和过于复杂。我和许多人一样有罪,有时候必须以某种方式完成某些事情,然后在有更清洁,更简单的解决方案的情况下自杀以使其成为现实。
答案 0 :(得分:1)
答案 1 :(得分:1)
抱歉,但你做错了。
你的整个论坛帖子都是一个接一个的代码味道 1.您正在使用价值转换器将商业实体转换为视觉对应物。这是我书中的代码味道 2.您正在考虑向业务逻辑发送UI控件 3.对上帝诚实,有人在这里说“MultiBindings”(并且超越正确)我的头部内爆,现在我的大脑曾经是一个黑洞。
有关我对价值转换器,触发器,多重绑定和其他实际LOB开发最差实践的宗教信仰的更多信息 - 请随时阅读WPF Disciples上的以下主题。
然而,让我们专注于让你解开。 你需要一个 - ViewModel 。
以下是您需要放入ViewModel的内容:
1.控件不会相互绑定。从圣经时代开始,这是一种令人憎恶的憎恶。每当控件上的某些东西发生变化时(ComboBox.SelectedItem,TextBox.Text,无论如何)都会直接将它绑定到ViewModel。因此,不是绑定到PlaneSelector.SelectedItem和PlaneSelector.SelectedItem.VisibleElements,而是将selectedItem绑定回ViewModel。
2.在ViewModel中转换业务数据和相应的可视化表示。因此,让视图模型返回几何数据。
这是一个粗略的草案,介绍了一个超级简单的ViewModel如何做到:
public class myFormViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void InvokePropertyChanged(string propertyName)
{
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null) changed(this, new PropertyChangedEventArgs(propertyName));
}
private object _planeSelectedItem;
public object PlaneSelectedItem
{
get { return _planeSelectedItem; }
set
{
_planeSelectedItem = value;
InvokePropertyChanged("PlaneSelectedItem");
}
}
public IEnumerable<KeyValuePair<string, Geometry>> VisibleElements
{
get
{
foreach(var slenderMember in PlaneSelectedItem.VisibleElements)
{
yield return new KeyValuePair<string, Geometry>(slenderMember.AsString, ToGeometry(slenderMember));
}
}
}
}
这里大概是你的控制部分应该是这样的:
<ComboBox SelectedItem="{Binding PlaneSelectedItem, Mode=TwoWay}" />
<ItemsControl x:Name="Display"
Background="White"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding VisibleElements}">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Path Stroke="Blue" StrokeThickness=".5"
Data="{Binding Value}" ToolTip="{Binding Key}">
</Path>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
显然,这里有一些丢失的代码(设置this.DataContent = new myFormViewModel(),使用KeyValuePairs,设置ComboBox ItemsSource等)。但这里的核心是简化这些疯狂的绑定恶作剧。
而不是试图破解XAML的行为就像代码 - 只需使用代码。 它会让你的生活变得更加简单。
答案 2 :(得分:0)
您始终可以在“输出”窗口中查看绑定错误。它始终以System.Windows.DataError ...
开头答案 3 :(得分:0)
我不太确定,但您是否尝试在ConverterParameter中使用DynamicResource,如
<Path Stroke="Blue" StrokeThickness=".5"
Data='{Binding Converter={StaticResource SlenderMemberConverter},
ConverterParameter={DynamicResource ConverterParameter2}}'
ToolTip="{Binding AsString}">
</Path>