如何将对另一个控件的引用作为IValueConverter参数传递?

时间:2009-09-17 13:26:46

标签: c# .net wpf data-binding

我将一些业务对象绑定到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中。

或者,或者,为什么我正在做的愚蠢和过于复杂。我和许多人一样有罪,有时候必须以某种方式完成某些事情,然后在有更清洁,更简单的解决方案的情况下自杀以使其成为现实。

4 个答案:

答案 0 :(得分:1)

你做不到。放弃......

没有禁忌。等等:)。使用MultiBinding而不是绑定。至少看起来你正试图做一些它让你做的事情。

希望这有帮助。

答案 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>