如何将数据正确绑定到列表框,以便更新[C#/WPF/MVVM]

如何将数据正确绑定到列表框,以便更新[C#/WPF/MVVM],c#,wpf,binding,listbox,C#,Wpf,Binding,Listbox,我在更新WPF中绑定的数据时遇到了严重的问题。 基本上,我的应用程序中有一些数据,当属性改变时,这些数据不会更新,我也无法修复 在我的应用程序中,我尝试使用MVVM模式,因此有一个属性为X,Y的模型: public class Сross : INotifyPropertyChanged { private double x; private double y; public double X { get { return x; }

我在更新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,其中包含一个可观察到的十字集合:

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));
    }
}
public类MainWindowViewModel:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
交叉=新的可观测集合()
{
新十字架()
{
X=300,
Y=200
},
新十字架()
{
X=400,
Y=300
}
};
私人可观测采集交叉;
公共可观测收集交叉点
{
得到
{
回程交叉;
}
设置
{
交叉=值;
RaisePropertyChanged(“交叉”);
}
}
私有void RaisePropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
…还有一个视图,其中有一个列表框,数据绑定到这个可见的交叉集合

<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字段中移动交叉项(它有一个基于Thumb控件的DataTemplate)时,它的Canvas.Left(或Top)正在更改,它会更新交叉项的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>

问题是,在加载listbox(并且十字出现在屏幕上的适当位置)后,在我移动它们时,它们不会更改ViewModel中的X和Y属性。如果我改变X和Y在可观察的收集交叉点上,它们不会在屏幕上移动。 值得一提的是,我制作了一个带有文本框的列表框进行测试,它还绑定到Crosss集合的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>

有趣的是,在这个列表框中,数据绑定工作得很好! 当我移动十字时,文本框中的值会发生变化,当文本框中的值发生变化时,十字会移动到位置

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

请帮我弄清楚,问题出在哪里!
提前谢谢你

经过几个小时的调试,我似乎发现了问题

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

愚蠢的错误,我知道。
无论如何,谢谢你的帮助

经过几个小时的调试,我似乎发现了问题

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

愚蠢的错误,我知道。
无论如何,谢谢你的帮助

当X,Y发生变化时,调试视图向您显示了什么?视图中是否发现绑定错误?交叉点的数据模板是什么样子?@JeongKim Debug view显示,即使移动交叉点,X和Y仍然是初始化期间加载的值。但在屏幕上,我看到它们被移动了,带有坐标的文本框显示了实际值。@Peter我在description@Lark3D奇怪的是,它在这里工作得很好(移动主窗口上的十字会反射回集合中的十字项目,反之亦然)。
Thumb\u DragDelta
简单如下:var t=发送方作为Thumb;if(t!=null){var c=t.DataContext作为交叉;if(c!=null){c.X+=e.HorizontalChange;c.Y+=e.VerticalChange;}当X,Y被更改时,调试视图向您显示了什么?在视图中发现了任何绑定错误吗?十字的DataTemplate是什么样子的?@JeongKim调试视图显示,即使在移动十字后,X和Y仍然是初始化期间加载的值。但在屏幕上,我看到它们被移动,并且文本框带有坐标显示实际值。@Peter我在description@Lark3D奇怪的是,它在这里工作得很好(在主窗口上移动十字会反射回集合中的十字项目,反之亦然)