简体   繁体   中英

XAML Win8 Databinding TwoWay with an Observable Collection

I am relatively new to Win8 App development and XAML (and this is my first proper stack overflow post so please go gently on me!).

With my project I am creating an order page which displays order header details and then a list of order lines. On the order lines I need the user to be able to update the Quantity (which is what I am struggling with).

I have the following class created:

public class OrderDetails 
{

    public class OrderDetailsLine : INotifyPropertyChanged
    {
        public string ItemNo { get; set; }
        public string ItemDescription { get; set; }

        private decimal quantity;
        public decimal Quantity 
        { 
            get
            {
                return quantity;
            }

            set
            {
                quantity = value;
                OnPropertyChanged();
            }
        }


        public decimal Price { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string caller = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                   new PropertyChangedEventArgs(caller));
            }
        }
    }

    public class OrderDetailsHeader : INotifyPropertyChanged
    {
        public string OrderNo { get; set; }
        public string CustNo { get; set; }
        public string CustName { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string County { get; set; }
        public string PostCode { get; set; }

        private string _externalDocNo;
        public string ExternalDocNo 
        { 
            get
            {
                return _externalDocNo;
            }
            set
            {
                _externalDocNo = value;
                OnPropertyChanged();
            }
        }

        public DateTime PostingDate { get; set; }

        private ObservableCollection<OrderDetailsLine> _Lines = new ObservableCollection<OrderDetailsLine>();
        public ObservableCollection<OrderDetailsLine> Lines
        {
            get
            {
                return this._Lines;
            }

            set
            {
                _Lines = value;
                OnPropertyChanged();
            }

        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string caller = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                   new PropertyChangedEventArgs(caller));

            }
        }
    }

In my XAML code I have a TextBox working with two way data binding against OrderDetails.OrderDetailHeader.ExternalDocNo.

However I also have a ListView with a DataTemplate, of which a TextBox is bound to OrderDetails.OrderDetailHeader.Lines.Quantity

<ListView 
  HorizontalAlignment="Left"  
  Grid.Row="1" 
  VerticalAlignment="Top" 
  x:Name="ItemsListView"
  Margin="39,20,0,0"
  Width="Auto">
  <ListView.ItemTemplate>
      <DataTemplate>
          <Grid VerticalAlignment="Center" Width="800">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20*" />
                <ColumnDefinition Width="40*" />
                <ColumnDefinition Width="20*" />
                <ColumnDefinition Width="20*" />
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="0" Margin="5" TextWrapping="NoWrap" 
                VerticalAlignment="Center"
                Text="{Binding ItemNo}" />

            <TextBlock Grid.Column="1" Margin="5" TextWrapping="Wrap"
                VerticalAlignment="Center"
                Text="{Binding ItemDescription}" />

            <TextBox Grid.Column="2" Margin="5" TextWrapping="NoWrap"
                HorizontalAlignment="Right"       
                VerticalAlignment="Center"
                Text="{Binding Quantity, Mode=TwoWay}" />

            <TextBlock Grid.Column="3" Margin="5" TextWrapping="NoWrap"
                HorizontalAlignment="Right"       
                VerticalAlignment="Center"
                Text="{Binding Price}" />


        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

The ItemsSource is set as follows in

   private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
   {    
      ...
      this.ExternalDoc.DataContext = orderDetails.orderDetailsHeader;
      this.ItemsListView.ItemsSource = orderDetails.orderDetailsHeader.Lines;

When I change the value in the TextBox for Quantity it does not call the PropertyChangedEventHandler - I cannot figure out why not!

The ExternalDoc textbox updates fine when I change it

<TextBox x:Name="ExternalDoc" HorizontalAlignment="Left" Grid.Row="1" TextWrapping="Wrap"  VerticalAlignment="Top" Height="27" Width="223" Margin="39,160,0,0" Text="{Binding ExternalDocNo, Mode=TwoWay}"/>

Any help would be greatly appreciated. Thanks

I'm not sur to understand exactly your question but if you change just quantity property of one line of your list it's normal the PropertyChangedEventHandler is not call. You bind an instance of ObservableCollection to the ItemSource property of your ListView. if you want to raise PropertyChangedEventHandler of Lines property you must change the instance of your ObservableCollection (to access at the setter). ObservableCollection allow WPF to "observe" modification in the list.

I try your sample code and I don't understand how you can get orderDetailsHeader since orderDetail. I try this code :

WpfApplication2.OrderDetails.OrderDetailsHeader header = new OrderDetails.OrderDetailsHeader(){
                Address = "tata",
                ExternalDocNo = "toto",
                Lines = new ObservableCollection<OrderDetails.OrderDetailsLine>()
            };
            header.Lines.Add(new OrderDetails.OrderDetailsLine()
            {
                ItemDescription = "toto",
                ItemNo = "titi",
                Price = 100,
                Quantity = 2
            });

            this.ExternalDoc.DataContext = header;
            this.ItemsListView.ItemsSource = header.Lines;

And with this code and your xaml the NotifyPropertyChangedEvent is raised when you changed quantity and ExteranlNoDoc.

There seems to be a problem when binding Text to a decimal property. Try changing the type of Quantity to a float and see if this works. More here:

http://social.msdn.microsoft.com/Forums/windowsapps/en-US/b0bfe9b9-7634-40d2-8d81-c664498cae6a/winrt-xaml-binding-text-to-decimal-causes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM