在ListView中更改TextBox的文本不会更新ObservableCollection <string>源

时间:2018-08-05 04:41:29

标签: c# wpf data-binding

我有一个非常复杂的ListViews结构。在此结构内部是TextBoxes,其中包含我的ViewModel中的值。当我在某些文本框中更改值时,ViewModel中的属性不会更新。 ViewModel中的“ AllTexts”属性仍然仅包含“ Hello”字符串。

基本上,我想显示用户的字符串结构,然后让用户更改此结构。他完成修改后,我要保存他的更改。 “ Hello”字符串仅用于测试。

我的ViewModel:

class MainWindowViewModel
    {
        public ObservableCollection<ObservableCollection<ObservableCollection<string>>> AllTexts { get; set; }

        public int SelectedGroupIndex { get; set; }

        public int SelectedColumnIndex { get; set; }

        public ICommand AddGroup { get; private set; }

        public ICommand AddColumn { get; private set; }

        public MainWindowViewModel()
        {
            this.AllTexts = new ObservableCollection<ObservableCollection<ObservableCollection<string>>>();
            this.SelectedGroupIndex = -1;
            this.SelectedColumnIndex = -1;
            this.AddGroup = new Command(this.AddGroupCommandHandler);
            this.AddColumn = new Command(this.AddColumnCommandHandler);
        }

        private void AddGroupCommandHandler()
        {
            var tempColumn = new ObservableCollection<string>() { "Hello", "Hello", "Hello", "Hello", "Hello" };
            var tempGroup = new ObservableCollection<ObservableCollection<string>>();
            tempGroup.Add(tempColumn);
            this.AllTexts.Add(new ObservableCollection<ObservableCollection<string>>(tempGroup));
        }

        private void AddColumnCommandHandler()
        {
           if (this.SelectedGroupIndex >= 0 && this.SelectedGroupIndex < this.AllTexts.Count)
           {
                var tempColumn = new ObservableCollection<string>() { "Hello", "Hello", "Hello", "Hello", "Hello" };
                this.AllTexts[this.SelectedGroupIndex].Add(tempColumn);
           }
        }
    }

我的视图:

<Window.Resources>
        <ResourceDictionary>
            <local:MainWindowViewModel x:Key="vm" />
        </ResourceDictionary>
    </Window.Resources>

    <Grid Margin="10,10,10,10" VerticalAlignment="Top">
        <Grid.RowDefinitions>
            <RowDefinition Height="300" />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

        <ListView Grid.Row="0"
            ItemsSource="{Binding AllTexts, Source={StaticResource vm}, Mode=TwoWay}"
            Background="Red"
            SelectedIndex="{Binding SelectedGroupIndex, Source={StaticResource vm}}">
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ListView
                        Background="Yellow"
                        ItemsSource="{Binding Path=., Mode=TwoWay}"
                        SelectedIndex="{Binding SelectedColumnIndex, Source={StaticResource vm}}">
                        <ListView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ListView
                                    Background="Green"
                                    ItemsSource="{Binding Path=., Mode=TwoWay}">
                                    <ListView.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation="Vertical" />
                                        </ItemsPanelTemplate>
                                    </ListView.ItemsPanel>
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <TextBox Text="{Binding Path=., Mode=TwoWay, NotifyOnSourceUpdated=True}"
                                                     VerticalContentAlignment="Center"
                                                     HorizontalContentAlignment="Center"
                                                     Width="100" Height="40"/>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>


        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,20,0,0">
            <Button Content="Add Group" Width="120" Height="30"
                Command="{Binding AddGroup, Source={StaticResource vm}}" />
            <Button Content="Add Column" Margin="20,0,0,0" Width="120" Height="30"
                Command="{Binding AddColumn, Source={StaticResource vm}}" />
        </StackPanel>

        <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,20,0,0">
            <TextBlock Width="120" Height="30" FontSize="20"
                Text="{Binding SelectedGroupIndex, Source={StaticResource vm}}" />
            <TextBlock Width="120" Height="30" Margin="20,0,0,0" FontSize="20"
                Text="{Binding SelectedColumnIndex, Source={StaticResource vm}}" />
        </StackPanel>
    </Grid>

有人可以帮我吗? 谢谢。

1 个答案:

答案 0 :(得分:1)

您的ViewModel必须通知View有关更改,否则View保留ViewModel的原始值

在这种情况下,string无法通知对其所做的更改。只有其封闭的可观察集合可以通知其对自身所做的更改(例如添加或删除),并且不会对其元素进行进一步监视。

因此,您需要一个可观察的字符串:

public class MyString : DependencyObject
{
    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(MyString), new PropertyMetadata(""));
}

要在集合中使用:

public ObservableCollection<ObservableCollection<ObservableCollection<MyString>>> AllTexts { get; set; }

我还向MyString类添加了以下行,以便测试代码并能正常工作。

public static MyString Hello { get { return new MyString { Value = "Hello" }; } }

很明显,这是它的用法:

 var tempColumn = new ObservableCollection<MyString>() { MyString.Hello, MyString.Hello, MyString.Hello, MyString.Hello, MyString.Hello };

在xaml中,还有一些不必要的东西可以消除:

对两个ItemsSource="{Binding}"使用ListView,对Text="{Binding Value}"使用TextBox。 (在任何一种情况下都不需要显式TwoWay