question

DaljitSingh-1549 avatar image
0 Votes"
DaljitSingh-1549 asked ·

How to bind properties in a ListView?

Ok so I am a bit confused the way model-view dynamics work in UWP. Coming from Qt, things seemed a bit complicated. In my project, what I have done is the following:

  1. I have create a custom control (the delegate for my view) called CanvasPage, in which I created a DependencyProperty called DpiScale

  2. Then I have created a new class called PageObject, this class will contain the data for my ListView, then I added a DependencyProperty called PageDpiScale in it.

  3. In Xaml (in my main page), I have created a ListView as follows:

My PageObject looks like the following:



 public class PageObject : DependencyObject
 {
     private int _index;
     private int _pageWidth = 1000;
     private int _pageHeight = 2000;

     public int PageWidth { get { return _pageWidth; } set { _pageWidth = value; } }
     public int PageHeight { get { return _pageHeight; } set { _pageHeight = value; } }

     // Using a DependencyProperty as the backing store for PageDpiScale.  This enables animation, styling, binding, etc...
     public static readonly DependencyProperty PageDpiScaleProperty =
         DependencyProperty.Register("PageDpiScale", typeof(float), typeof(PageObject), new PropertyMetadata(0));
     public float PageDpiScale
     {
         get { return (float)GetValue(PageDpiScaleProperty); }
         set
         {
             SetValue(PageDpiScaleProperty, value);
             //Debug.WriteLine(this.ToString() + " PageDpiScale property changed " + value);
         }
     }

 }

For some reason the editor doesn't let me paste my xaml code so I attached a screenshot:
Xaml ListView Template


Now in my main page I have an observable collection:

     private ObservableCollection canvasPageList; // list of PageObjects

The ListView displays correctly, however when I try to update the property PageDpiScale of my PageObjects, the change is not propagated in my CanvasPage controls:

             foreach(var page in canvasPageList)
             {
                 page.PageDpiScale = dpiScale;
             }

I can see that property in PageObject classes is being updated, but nothing seems to happen in CanvasPage classes (the UI).
How can I make this work?




windows-uwpwindows-uwp-xaml
capture.png (10.9 KiB)
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

DaljitSingh-1549 avatar image
0 Votes"
DaljitSingh-1549 answered ·

Ok so I found the problem. It turns out that one cannot set custom setters in the definition of DependencyProperty, instead one must make use of PropertyChangedCallback and then use your custom logic in there. In my case, I was trying to change the DpiScale of my inner controls inside my CanvascControl inside the setter of the DependencyProperty.

· Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RoyLi-MSFT avatar image
0 Votes"
RoyLi-MSFT answered ·

Hello,

Welcome to Microsoft Q&A!

ObservableCollection Class will provides notifications to update UI when items get added, removed, or when the whole list is refreshed. But it doesn't when the item's property is changed.
So when you changed the property of the PageObject, the UI won't be updated.

In such a scenario, if you want to update UI when the item's property is changed. You need to implement INotifyPropertyChanged Interface for the PageObject.The INotifyPropertyChanged interface is used to notify clients that a property value has changed.

I've created a simple demo. You could refer to my sample code and modify it a little bit to meet your scenario.

Here is the code:

   public sealed partial class MainPage : Page
     {
         public ObservableCollection normalcollection;
    
         public MainPage()
         {
             this.InitializeComponent();
    
             normalcollection = new ObservableCollection();
             normalcollection.Add(new testmodel { Name = "A", Age = "123" });
             normalcollection.Add(new testmodel { Name = "B", Age = "456" });
             normalcollection.Add(new testmodel { Name = "C", Age = "789" });
             normalcollection.Add(new testmodel { Name = "D", Age = "147" });
             normalcollection.Add(new testmodel { Name = "E", Age = "258" });
             normalcollection.Add(new testmodel { Name = "F", Age = "369" });
    
             MyListView.ItemsSource = normalcollection;
         }
    
         private void Button_Click(object sender, RoutedEventArgs e)
         {
             int i = 0;
            //change property of the item. And UI will be updated.
             foreach (var model in normalcollection)
             {
                 testmodel data = (testmodel)model;
                 data.Age = i.ToString();
                 i++;
             }
         }
     }
    
     //model class that implements INotifyPropertyChanged interface
     public class testmodel : INotifyPropertyChanged
     {
         protected string _Name;
         protected string _Age;
    
         public string Name
         {
             get
             {
                 return _Name;
             }
             set
             {
                 _Name = value;
                 NotifyPropertyChanged("Name");
             }
         }
    
         public string Age
         {
             get
             {
                 return _Age;
             }
             set
             {
                 _Age = value;
                 NotifyPropertyChanged("Age");
             }
         }
    
         public event PropertyChangedEventHandler PropertyChanged;
    
         private void NotifyPropertyChanged(String propertyName = "")
         {
             if (PropertyChanged != null)
             {
                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
             }
         }
     }


For more information about data binding and INotifyPropertyChanged interface, you could refer to this document: Data binding in depth

By the way, it's a known issue that Microsoft Q&A could not post Xaml code. You could try these ways here: https://docs.microsoft.com/answers/idea/1637/can-not-insert-xmlxaml-code-in-post.html to insert Xaml code.

Best regards,
Roy



· 1 · Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you that's helpful. Now I have another question: I thought the point of DependencyProperty was exactly to not require to implement the INotifyPropertyChanged interface, so shouldn't all the properties in my PageObject (which is derived from DependencyObject) should automatically be updated?

0 Votes 0 · ·