How to bind properties in a ListView?

Daljit Singh 261 Reputation points
2020-01-23T13:44:53.84+00:00

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?

Universal Windows Platform (UWP)
0 comments No comments
{count} votes

Accepted answer
  1. Daljit Singh 261 Reputation points
    2020-01-26T21:30:27.12+00:00

    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.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Roy Li - MSFT 31,766 Reputation points Microsoft Vendor
    2020-01-24T03:03:53.107+00:00

    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://learn.microsoft.com/answers/idea/1637/can-not-insert-xmlxaml-code-in-post.html to insert Xaml code.

    Best regards,
    Roy