0

I have a ListView with ItemTemplate. I want to bind one control background in ItemTemplate to 2 properties, one of properties is in ItemsSource and onother one is in my page. since UWP has no multibinding support, I bind it to one property in ItemSource and for another property in my page I want to handle it in my code behind.

<ListView >
<ListView.ItemTemplate>
          <DataTemplate>
                   <Border HorizontalAlignment="Stretch"
                           x:Name="myborder"
                           Padding="5,0,5,0"
                           Background="{Binding myProperty, Converter={StaticResource convertPropertyToBgColor },ConverterParameter=border}">
                                <StackPanel Padding="0,10,10,10"
                                            Background="{Binding myProperty, Converter={StaticResource convertPropertyToBgColor},ConverterParameter=stack}">
                                       <TextBlock Text="{Binding Text}">
                                </StackPanel>
                  </Border>
            </DataTemplate>
</ListView.ItemTemplate>
</ListView>

in the convertPropertyToBgColor I get the brush from Resources.

and in code behind when my second desired property is changed I Change My resources. so the brush I have used from resources get changed and because of that I want to call that converter again to refresh Background, I called updateLayout but it doesn't refresh my ListView and it doesn't call myConvereter again. How can I force ListView to recreate or refresh Items that it has made?

Maryam
  • 883
  • 10
  • 24

1 Answers1

0

Generally you class should implement INotifyPropertyChanged, then once you change the property, usually in its setter you also call OnPropertyChanged event which will update your UI. There are plenty examples of that, here is one.

The other way, may be to call Bindings.Update(), but normally you probably should use the method above.


To make my comments clearer - something like this is possible:

<StackPanel Orientation="Horizontal" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="myList" Width="200">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Border HorizontalAlignment="Stretch"
                       x:Name="myborder"
                       Padding="5,0,5,0"
                       Background="{Binding Path=DataContext.MyProperty, ElementName=myList}">
                    <StackPanel Padding="0,10,10,10">
                        <TextBlock Text="{Binding}"/>
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListView.ItemTemplate>
        <x:String>Element 1</x:String>
        <x:String>Element 2</x:String>
        <x:String>Element 3</x:String>
    </ListView>
    <Button Content="Change" Click="Button_Click"/>
</StackPanel>

code behind:

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    private SolidColorBrush myPropety = new SolidColorBrush(Colors.Red);
    public SolidColorBrush MyProperty
    {
        get { return myPropety; }
        set { myPropety = value; RaiseProperty(nameof(MyProperty)); }
    }

    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = this;
    }
    private void Button_Click(object sender, RoutedEventArgs e) => MyProperty = new SolidColorBrush(Colors.Blue);
}
Romasz
  • 29,662
  • 13
  • 79
  • 154
  • My itemsSource is a independent class that I used in different Pages . you mean I should go to that class and change it? that property is in this page, so that class doesn't understand it has changed – Maryam Feb 18 '17 at 07:40
  • @Maryam Implement in that class *INotifyPropertyChanged*, then define method for example: `void RaiseProperty(string property) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));` and call that in property's setter at the end `RaiseProperty(nameof(property));`. This should do the job. – Romasz Feb 18 '17 at 07:44
  • @Maryam Another question `myProperty` is in Page? Not in class? Then it won't work as *DataContext* is different. You can change that, probably for example by using as a *Source*, page's *DataContext*. However I'm not sure if I won't put another property in the class. – Romasz Feb 18 '17 at 07:47
  • as i said in question that property changes my resources in whole app so I just want that converter get called again to get the new color, it doesn't need to be as part of dataContext. I just want that ListView refresh it's UI – Maryam Feb 18 '17 at 07:49
  • If you use Binging, then you have a DataContext - where it looks for the property. If you want to change the property and see the cahnge, then this DataContext should implement *INotifyPropertyChanged*. As for your code, your datacontext is an element's class in your itemssource. You can change that for [example like this](http://stackoverflow.com/a/19646872/2681948) - to datacontext of element in page. Another way may be to declare a resource in app's `` and use that, however that class used for resource should also implement *INotifyPropertyChanged*. – Romasz Feb 18 '17 at 07:56
  • If you want to make it 'dirty way', then make a property from your ItemsSource* and bind it in *ListView*: ``. Then every time you want refresh/change the collection call `Bindings.Update()`. A step better would be to (again) implement *INotifyPropertyChanged* on page and invoke *PropertyChanged* once you need to refresh itemssource. However look that in the above comment's method, refreshed is only what is needed, items are not created again and so on - this is much better. – Romasz Feb 18 '17 at 08:02
  • as I said I have 2 properties .my listview dataContext is its itemSource. I bind it to one of itemSource's properties it works fine. when I change some property in the page not in ItemsSource, I want the listview refresh again. because in the converter I get the color from myresource SolidColorBrush((Color)Application.Current.Resources["Red"]) that is changed – Maryam Feb 18 '17 at 08:38
  • @Maryam I'm not sure if we understand each other, therefore to show what I've on my mind see the edit in the answer - it's a complete sample app. Give it a try and see if that is what you want. – Romasz Feb 18 '17 at 08:52
  • Yes I think we don't understand each other maybe because my question is not complete. MyProperty is one of attributes in ItemsSource class and I used Converter that according to that property I pick a color. so for each row the color is different according to that property of that rowItem. it works fine. but the problem is when I change another property in class not in Items, so I want that converter again get called again – Maryam Feb 18 '17 at 09:16
  • @Maryam The converter will be called once you invoke *RaiseProperty* on suitable item -> it will invoke the getter and then converter. You cannot just like that call converter. I must say that I'm lost in this what you try to achieve, if possible please build a sample app that will reproduce the issue. – Romasz Feb 18 '17 at 09:22