1

在编程过程中,我遇到了以下问题:

  1. 可观察集合本身是否实现了 CollectionChanged 事件?(因为不同的书籍提到它确实如此,但谷歌显示不同)

  2. 我有以下代码,我希望我的 UI 通过绑定来更新(代码适用于 windowsPhone 7.1)此外,绑定适用于我的 observable 集合中的单个项目,但是当我尝试向我的集合中添加一个新对象时, CollectionChanged 事件不会触发。

    命名空间 Phone.lib.ViewModel { 公共类 DeviceViewModel : ViewModelBase {

        DeviceModelInfo InfoList = new DeviceModelInfo();
    
        public DeviceViewModel()
        {
        }
    
        public DeviceViewModel(int index)
        {
            // Here I add a new item to the collection, But the ui only shows: Beckhoff, ver....
            InfoList.Add(new DeviceInfo("name1", "name2", "name3"));
        }        
    }
    
    public class DeviceModelInfo : ObservableCollection<DeviceInfo>
    {
        public DeviceModelInfo() : base()
        {
            Add(new DeviceInfo("Beckhoff", "Ver. 1A2B3C", "Stopped"));      
        }
    }
    
    public class DeviceInfo : ViewModelBase
    {
        private string devicename;
        private string deviceid;
        private string devicestatus;
    
        public DeviceInfo(string first, string second, string third)
        {
            devicename = first;
            deviceid = second;
            devicestatus = third;
        }
    
        public string DeviceName
        {
            get { return devicename; }
            set 
            { 
            devicename = value;
            RaisePropertyChanged("DeviceName");
            }
        }
    
        public string DeviceID
        {
            get { return deviceid; }
            set { deviceid = value; }
        }
    
        public string DeviceStatus
        {
            get { return devicestatus; }
            set { devicestatus = value; }
        }
    
    }
    

注意:该类继承自 viewmodel 基础,其中具有 Inotify 更改接口。

我的 Xaml 中的代码:

<phone:PhoneApplicationPage 
x:Class="WindowsPhone.View.Device_Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="clr-namespace:Phone.lib.ViewModel;assembly=Phone.lib"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">

<!-- Static Resource area for binding -->
<phone:PhoneApplicationPage.Resources>
    <ViewModel:DeviceModelInfo x:Key="deviceinfo"></ViewModel:DeviceModelInfo>
    <ViewModel:DeviceModelSensor x:Key="devicesensors"></ViewModel:DeviceModelSensor>
    <ViewModel:DeviceModelActuator x:Key="deviceactuators"></ViewModel:DeviceModelActuator>
</phone:PhoneApplicationPage.Resources>

<!-- LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="Kremer app" Style="{StaticResource PhoneTextNormalStyle}"/>
    </StackPanel>

    <!--ContentPanel - place additional content here-->


    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource deviceinfo}}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,0,0,17" Width="432" Height="100">
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=DeviceName, Mode=TwoWay}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceID, Mode=TwoWay}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceStatus, Mode=TwoWay}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox Height="261" HorizontalAlignment="Left" Margin="-4,138,0,0" Name="Sensor_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource devicesensors}}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,0,0,17" Width="432" Height="78">
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=SensorName}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=SensorType}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox Height="261" HorizontalAlignment="Left" Margin="-4,429,0,0" Name="Actuator_ListBox" ItemsSource="{Binding Source={StaticResource deviceactuators}}" VerticalAlignment="Top" Width="460">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Height="78" Margin="0,0,0,17" Width="432">
                        <TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=ActuatorName}" TextWrapping="Wrap" />
                        <TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=ActuatorType}" TextWrapping="Wrap" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

</Grid>

我希望有人能够帮助我解决这个问题,因为我已经在这里待了两天了。

另外,我为我的“糟糕”英语道歉,但英语不是我的母语

干杯-巴特

编辑:做了一个小测试

我自己运行了一个小调试测试,看看添加操作是否添加到正确的集合中,因此增加计数值

        public DeviceViewModel(int index)
        {
        // Here I add a new item to the collection, But the ui only shows: Beckhoff, ver....

        Debug.WriteLine("number of added items " + InfoList.Count.ToString());
        InfoList.Add(new DeviceInfo("1", "2", "3"));
        Debug.WriteLine("number of added items " + InfoList.Count.ToString());
        InfoList.Add(new DeviceInfo("1", "2", "3"));
        InfoList.Add(new DeviceInfo("1", "2", "3"));
        InfoList.Add(new DeviceInfo("1", "2", "3"));
        Debug.WriteLine("number of added items " + InfoList.Count.ToString());
        }  

输出:

新增项目数 1

新增项目数 2

新增项目数 5

编辑 2 (19-03-2012)

上周五我试图让它像你建议的那样工作。但不知何故 XAML 找不到 InfoList,我不知道为什么。也许我在 XAML 本身或背后的代码或 DeviceViewModel 中做错了什么。所以这就是我目前所拥有的:

设备视图模型:

namespace Phone.lib.ViewModel
{
    public class DeviceViewModel : ViewModelBase
    {

        public DeviceModelInfo InfoList  = new DeviceModelInfo();

        public DeviceViewModel()
        {
            //DeviceModelInfo InfoList  = new DeviceModelInfo();
            InfoList.Add(new DeviceInfo("1", "2", "3"));

        }

        public DeviceViewModel(int index)
        {

        }
    }

    public class DeviceModelInfo : ObservableCollection<DeviceInfo>
    {
        public DeviceModelInfo() : base()
        {
            Add(new DeviceInfo("Beckhoff", "Ver. 1A2B3C", "Stopped"));
            //this.CollectionChanged += (e, s) => { Debug.WriteLine("event Fired " + e.ToString()); };
        }

    }

    public class DeviceInfo : ViewModelBase
    {


        private string devicename;
        private string deviceid;
        private string devicestatus;

        public DeviceInfo(string first, string second, string third)
        {

            devicename = first;
            deviceid = second;
            devicestatus = third;

        }

        public string DeviceName
        {
            get { return devicename; }
            set 
            { 
                devicename = value;
                RaisePropertyChanged("DeviceName");
            }
        }

        public string DeviceID
        {
            get { return deviceid; }
            set { deviceid = value; }
        }

        public string DeviceStatus
        { 
            get { return devicestatus; }
            set { devicestatus = value; }
        }
    }

页面背后的代码:

namespace WindowsPhone.View
{
    public partial class Device_Page : PhoneApplicationPage
    {

        private DeviceViewModel _DV;

        public Device_Page()
        {

            InitializeComponent();
            _DV = new DeviceViewModel();
            DataContext = _DV;

        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            string selectedIndex = "";
            if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
            {
                int index = int.Parse(selectedIndex);

                //_DV = new DeviceViewModel(index);
                //DataContext = _DV;

                Debug.WriteLine("index:" + index.ToString());
            }
        }

    }
}

XAML 代码:

<phone:PhoneApplicationPage 
x:Class="WindowsPhone.View.Device_Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="clr-namespace:Phone.lib.ViewModel;assembly=Phone.lib"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">


<!-- Static Resource area for binding -->
<phone:PhoneApplicationPage.Resources>
    <ViewModel:DeviceViewModel x:Key="deviceinfo"></ViewModel:DeviceViewModel>
    <ViewModel:DeviceModelSensor x:Key="devicesensors"></ViewModel:DeviceModelSensor>
    <ViewModel:DeviceModelActuator x:Key="deviceactuators"></ViewModel:DeviceModelActuator>
</phone:PhoneApplicationPage.Resources>

<!-- LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="Kremer app" Style="{StaticResource PhoneTextNormalStyle}"/>
    </StackPanel>

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding InfoList}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,0,0,17" Width="432" Height="100">
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=DeviceName, Mode=TwoWay}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceID, Mode=TwoWay}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceStatus, Mode=TwoWay}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox Height="261" HorizontalAlignment="Left" Margin="-4,138,0,0" Name="Sensor_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource devicesensors}}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,0,0,17" Width="432" Height="78">
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=SensorName}" />
                        <TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=SensorType}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox Height="261" HorizontalAlignment="Left" Margin="-4,429,0,0" Name="Actuator_ListBox" ItemsSource="{Binding Source={StaticResource deviceactuators}}" VerticalAlignment="Top" Width="460">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Height="78" Margin="0,0,0,17" Width="432">
                        <TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=ActuatorName}" TextWrapping="Wrap" />
                        <TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=ActuatorType}" TextWrapping="Wrap" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

</Grid>



</phone:PhoneApplicationPage>
4

1 回答 1

2

1)ObservableCollection实现定义事件的INotifyCollectionChanged接口。CollectionChanged

2)当您添加一个新项目时,您会将DeviceViewModel其添加到 的新实例中DeviceModelInfo,因此与您在 XAML 中声明的实例不同

<ViewModel:DeviceModelInfo x:Key="deviceinfo"></ViewModel:DeviceModelInfo>

您必须绑定到DeviceModelInfo实例DeviceViewModel 或使用DeviceViewModelXAML 中声明的实例


编辑

在您的 XAML 中,这与键入“new DeviceModelInfo()”然后在控件的资源中注册该实例相同PhoneApplicationPage。并且您将您的 the 绑定ItemsSourceListBox该特定实例。

ItemsSource="{Binding Source={StaticResource deviceinfo}}"

现在在你的DeviceViewModel课堂上你InfoList这样声明

DeviceModelInfo InfoList = new DeviceModelInfo();

您创建 的实例DeviceModelInfo,因此InfoList与 XAML 中的实例/对象不同的实例/对象。

您必须 1)将您的绑定到您ItemsSourceListBox中的实例DeviceViewModel。为此,您必须首先公开InfoList,即最好通过属性将其公开(但这只是惯例,不是必需的)。然后确保DataContext您的控件设置为您正在使用的实例DeviceViewModel。然后你可以像这样设置绑定

ItemsSource="{Binding InfoList}"

假设InfoList是公开的

2)deviceinfo获取在您的 XAML 中创建的实例,如下所示:

DeviceViewModel deviceinfo = phoneApplicationPage.FindResource("deviceinfo") as DeviceViewModel;

假设您的控件实例被调用phoneApplicationPage。如果您在控件后面的代码中执行此操作,那么phoneApplicationPage将是this.

现在您可以将此实例 ( deviceinfo) 传递给您的DeviceViewModel.

从命名我假设您正在尝试使用 MVVM 模式,在这种情况下您应该使用1)


编辑

公开该领域就足够了。

现在您需要将其绑定ItemsSourceListBox. 这可以很简单

ItemsSource="{Binding InfoList}"

但这要求DataContext您的页面 ( )的属性PhoneApplicationPage设置为DeviceViewModel. 在不确切知道您当前如何实例化DeviceViewModel的情况下,我很难准确地解释您如何才能做到这一点。但我假设您在页面的代码隐藏中实例化DeviceViewModel,所以它看起来像这样:

public partial class PhoneApplicationPage : Page
{
    private DeviceViewModel _deviceViewModel;

    //...

    public PhoneApplicationPage()
    {
        InitializeComponent();

        // I assume you do something like this
        _deviceViewModel = new DeviceViewModel();

       // You need to set the DataContext to the DeviceViewModel instance you have created.
       DataContext = _deviceViewModel;
    }

    //...
}

一旦您确定已将DataContext设置为您的DeviceViewModel实例,您就可以更改 XAML 中的绑定,如上所述。所以你应该换行

<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource deviceinfo}}">

<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding ListInfo}">
于 2012-03-16T09:13:37.887 回答