绑定到ListView中的TextBox?

时间:2011-08-14 22:22:27

标签: .net wpf vb.net xaml ivalueconverter

我一直在寻找一个答案,差不多一个星期了,我似乎找不到办法做到这一点。我认为这是一件相对简单的事情......

我有一个ListView,一个GridViewColumn包含TextBox项。我想将一个Label放在ListView下面,并用所有TextBox中的项目总和填充它。每当有人更改任何TextBox中的值时,总和也应该改变。

我知道我需要使用转换器来获得总和...但我不知道如何正确绑定...

非常感谢任何帮助!

编辑:我最终以稍微不同的方式解决了这个问题。我将在下面发布我的解决方案。

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converters="clr-namespace:WpfApplication2"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <XmlDataProvider x:Key="myParties" XPath="Parties" Source="XMLFile1.xml" />
        <CollectionViewSource x:Key="myCollectionViewSource" Source="{StaticResource myParties}" />
        <converters:SumConverter x:Key="mySumConverter" />
    </Window.Resources>

    <StackPanel>
        <Button x:Name="Breakpoint" Click="bpClick" Content="Breakpoint"/>
        <ListView x:Name="myListView" 
                  HorizontalAlignment="Stretch" 
                  ItemsSource="{Binding Source={StaticResource myCollectionViewSource},XPath='Party',Mode=TwoWay}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="100" DisplayMemberBinding="{Binding XPath='@Contact'}" Header="Contact"/>
                    <GridViewColumn DisplayMemberBinding="{Binding XPath='@Qty'}" Header="Q"/>
                    <GridViewColumn DisplayMemberBinding="{Binding XPath='@Amount'}" Header="Amt"/>
                    <GridViewColumn x:Name="tbTot" Header="Tot">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <DockPanel>
                                    <TextBox Width="100" Text="{Binding XPath='@Tot'}" />
                                </DockPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>    
        </ListView>

        <Label Height="22">
            <Label.Content>
                <MultiBinding Converter="{StaticResource mySumConverter}">
                    <Binding ElementName="myListView" Path="Items"/>
                    <Binding ElementName="myListView" Path="Items.Count"/>
                </MultiBinding>
            </Label.Content>
        </Label>
    </StackPanel>
</Window>

XML文件:

<?xml version="1.0" encoding="utf-8" ?>
<Parties>
  <Party Contact="Jim Shmekel"
         Qty="1"
         Amount="55.00" 
         Tot="55.00"/>
  <Party Contact="Shmi Skywalker"
         Qty="1"
         Amount="20.00" 
         Tot="20.00"/>
  <Party Contact="Jon Ronson"
         Qty="1"
         Amount="23.00" 
         Tot="23.00"/>
</Parties>

SumConverter:

Imports System.Collections.ObjectModel
Imports System.Reflection

<ValueConversion(GetType(Object()), GetType(String))>
Public Class SumConverter : Implements System.Windows.Data.IMultiValueConverter

    Public Function Convert(ByVal values() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        Static lvItems As IList
        Static lvItem As Xml.XmlElement
        Dim nVal As Double

        Convert = 0
        lvItems = values(0)
        If lvItems Is Nothing Then Exit Function

        For Each lvItem In lvItems
            'Debug.Print(lvItem.GetAttribute("Tot"))
            If Double.TryParse(lvItem.GetAttribute("Tot"), nVal) Then
                Convert = Convert + nVal
            End If
        Next

    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetTypes() As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        ConvertBack = Nothing
    End Function
End Class

2 个答案:

答案 0 :(得分:1)

直截了当的解决方案(我肯定不是最好的)是绑定一个

ElementName = myListView, Path = Items

在转换器遍历项目中并使用VisualTreeHelper.GetChild()找出项目的基础TextBlock然后int.TryParse(textBlock.Text, out currentItemValue);

答案 1 :(得分:0)

我有点失望,因为我真的希望按照sllev建议的方式来解决这个问题。对我而言,这似乎是最合乎逻辑的做法。可能还有办法,但我还没弄清楚。

以下是我最终解决此问题的方法。基本上我所做的是将“Tot”列添加到我的DataSource(它在我的初始解决方案中不存在,尽管它在我上面的问题中)。我将TextBox绑定到该列,然后在ListView中的TextBox的LostFocus事件上刷新ListView。 Refresh()导致再次调用SumConverter。

希望这有助于其他人 - 这似乎是一个简单的请求,但我浪费了大量的时间。

MainWindow.xaml:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converters="clr-namespace:WpfApplication2"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <XmlDataProvider x:Key="myParties" XPath="Parties" Source="XMLFile1.xml" />
        <CollectionViewSource x:Key="myCollectionViewSource" Source="{StaticResource myParties}" />
        <converters:SumConverter x:Key="mySumConverter" />
    </Window.Resources>

    <StackPanel>
        <ListView x:Name="myListView" 
                  HorizontalAlignment="Stretch" 
                  ItemsSource="{Binding Source={StaticResource myCollectionViewSource},XPath='Party',Mode=TwoWay}">

            <ListView.View>
                <GridView>
                    <GridViewColumn Width="100" DisplayMemberBinding="{Binding XPath='@Contact'}" Header="Contact"/>
                    <GridViewColumn DisplayMemberBinding="{Binding XPath='@Qty'}" Header="Q"/>
                    <GridViewColumn DisplayMemberBinding="{Binding XPath='@Amount'}" Header="Amt"/>
                    <GridViewColumn x:Name="tbTot" Header="Tot">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <DockPanel>
                                    <TextBox LostFocus="TextBox_LostFocus" Width="100" Text="{Binding XPath='@Tot'}" />
                                </DockPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>    
        </ListView>

        <Label VerticalAlignment="Stretch">
            <Label.Content>
                <MultiBinding Converter="{StaticResource mySumConverter}">
                    <Binding ElementName="myListView" Path="Items"/>
                    <Binding ElementName="myListView" Path="Items.Count"/>
                </MultiBinding>
            </Label.Content>
        </Label>
    </StackPanel>
</Window>

MainWindow.xaml上的CodeBehind:

Class MainWindow 

        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
        End Sub

        Private Sub TextBox_LostFocus(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
            myListView.Items.Refresh()
        End Sub
    End Class

SumConverter.vb:

<ValueConversion(GetType(Object()), GetType(String))>
Public Class SumConverter : Implements System.Windows.Data.IMultiValueConverter

    Public Function Convert(ByVal values() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        Static lvItems As ItemCollection
        Static lvItem As Xml.XmlElement
        Dim nVal As Double

        Convert = 0
        lvItems = values(0)
        If lvItems Is Nothing Then Exit Function


        For Each lvItem In lvItems
            'Debug.Print(lvItem.GetAttribute("Tot"))
            If Double.TryParse(lvItem.GetAttribute("Tot"), nVal) Then
                Convert = Convert + nVal
            End If
        Next

    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetTypes() As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        ConvertBack = Nothing
    End Function
End Class