【问题标题】:How to bind data correctly to a ListBox so it would update [C#/WPF/MVVM]如何将数据正确绑定到 ListBox 以便更新 [C#/WPF/MVVM]
【发布时间】:2016-02-05 19:39:59
【问题描述】:

我在更新 WPF 中的绑定数据时遇到了严重问题。 基本上,我的应用中有一些数据,这些数据在属性更改时不会更新,我无法修复它。

在我的应用程序中,我尝试使用 MVVM 模式,因此有一个具有 X、Y 属性的模型:

public class Сross : INotifyPropertyChanged
{
    private double x;
    private double y;

    public double X
    {
        get { return x; }
        set
        {
            x = value;
            RaisePropertyChanged("X");
        }
    }

    public double Y
    {
        get { return y; }
        set
        {
            y = value;
            RaisePropertyChanged("Y");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

...有一个 ViewModel,其中包含一个 ObservableCollection of Crosses:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    Crosses = new ObservableCollection<Cross>()
    {
        new Cross ()
        {
            X = 300,
            Y = 200
        },
        new Cross ()
        {
            X = 400,
            Y = 300
        }
    };

    private ObservableCollection<Cross> crosses;
    public ObservableCollection<Cross> Crosses
    {
        get
        {
            return crosses;
        }
        set
        {
            crosses = value;
            RaisePropertyChanged("Crosses");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

...还有一个 View,其中有一个 ListBox,数据绑定到这个 ObservableCollection of Crosses。

<Page x:Class="CharMaker.App.MainPageView">
    <Page.DataContext>
         <local:MainWindowViewModel />
    </Page.DataContext>

    ....

    <ListBox>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True" Background="#01FFFFFF" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>

        <ListBox.ItemsSource>
             <Binding Path="Crosses" Mode="TwoWay" />
        </ListBox.ItemsSource>

        <ListBox.ItemContainerStyle>
             <Style TargetType="ListBoxItem">
                  <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}" />
                  <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}" />
             </Style>
         </ListBox.ItemContainerStyle>
    </ListBox>
</Page>

此代码的工作原理是,当您在 ListBox 字段中移动 Cross 项(具有基于 Thumb 控件的 DataTemplate)时,它的 Canvas.Left(或 Top)正在发生变化,它会更新 Cross 的 X 和 Y 属性项目,反之亦然。

  <DataTemplate DataType="{x:Type model:Cross}">
                            <Thumb DragDelta="Thumb_DragDelta"
                           IsEnabled="{Binding IsSelected,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
                                <Thumb.Template>
                                    <ControlTemplate TargetType="Thumb">
                                        <Canvas Margin="0">
                                            <Line X1="-5" X2="5" Y1="-5" Y2="5"  Stroke="#FF2E61AB" StrokeThickness="1.5" 
                                             x:Name="FirstLine" />

                                            <Line X1="-5" X2="5" Y1="5" Y2="-5"  Stroke="#FF2E61AB" StrokeThickness="1.5" 
                                             x:Name="SecondLine" />
                                        </Canvas>
                                        <ControlTemplate.Triggers>
                                            <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
                                                <Setter TargetName="FirstLine" Property="Stroke" Value="Red"/>
                                                <Setter TargetName="SecondLine" Property="Stroke" Value="Red"/>
                                            </DataTrigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Thumb.Template>
                            </Thumb>
                        </DataTemplate>

问题在于,在加载列表框后(并且十字架出现在屏幕上的适当位置),当我移动它们时,它们不会更改 ViewModel 中的 X 和 Y 属性。如果我在 ObservableCollection Crosses 中更改 X 和 Y,它们不会在屏幕上移动。 值得一提的是,我做了一个带有 TextBoxes 的 ListBox 进行测试,它也绑定了 Crosses 集合的 X、Y 属性:

<ListBox Grid.Row="2" Grid.ColumnSpan="4" ItemsSource="{Binding Crosses}">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type model:Cross}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="1*"/>
                </Grid.ColumnDefinitions>

                <TextBox Grid.Column="0" Text="{Binding X, Mode=TwoWay}" />
                <TextBox Grid.Column="1" Text="{Binding Y, Mode=TwoWay}" />
             </Grid>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>

有趣的是,在这个 ListBox 中,数据绑定工作得很好! 当我移动十字时,TextBox 中的值会发生变化,而当 TextBox 中的值发生变化时,十字会移动到位置。

但在同一时间(如果我暂停应用程序),我看到 ViewModel 中的 Observable Collection Crosses 中的值与第一次加载时的值相同。

请帮我找出问题所在! 提前谢谢!

【问题讨论】:

  • 当 X,Y 改变时,调试视图会显示什么?视图中是否发现任何绑定错误?
  • 你的十字架数据模板是什么样的?
  • @JeongKim 调试视图显示,即使在移动十字架之后,X 和 Y 仍然是初始化期间加载的值。但是在屏幕上我看到它们被移动了,带有坐标的文本框显示了实际值。
  • @Peter 我在描述中添加了 DataTemplate
  • @Lark3D 奇怪的是它在这里工作得很好(在主窗口上移动十字架会反射回收藏中的十字架项目,反之亦然)。 Thumb_DragDelta 很简单: var t = sender as Thumb; if (t != null) { var c = t.DataContext as Cross; if (c != null) { c.X += e.Horizo​​ntalChange; c.Y += e.VerticalChange; }

标签: c# wpf binding listbox


【解决方案1】:

经过大量小时的调试,我似乎找到了问题所在。

我有一个 DataContext 设置为 MainViewModel 的 Page,该 Page 是 MainWindow 的一个子级,它的 DataContext 属性也设置为 MainViewModel。 我没有意识到,Page 和 MainWindow 都创建了自己的 MainViewModel 实例。 所以我有两个实例,当一个正在工作和更新时,另一个只是让我感到困惑。

愚蠢的错误,我知道。 无论如何,感谢您提供帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多