locked
Unable to upadate layout when ObservableCollection is changes in xaml

    Question

  • Hi,

    I have created DataTemplate for ListView having two textblock and two Textboxes(for height and width ).The ObservableCollection(Which gets initialized in constructor of ViewModel) say Images is bind to that ListView.

    I have VariablesizedWrapGrid with Image.Now I want to dynamically change Image width and height when the values in above listView(Width and height changes.).Currently the values in ObservableCollection is changing but the layout is not getting updated.I want to change image width and height from VariableSizedWrapGrid when values of width and height textbox from ListView are chnages

    Model:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ComponentModel;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Imaging;
    
    namespace Demo
    {
        public class ImageModel : INotifyPropertyChanged
        {
    
            private int _ordinal;
            private int _width;
            private int _height;
            private string _imagePath = null;
            private int _imageWidth;
            private int _imageHeight;
    
            public int ImageWidth
            {
                get
                {
                    return _imageWidth;
    
                }
                set
                {
                    _imageWidth = value;
                    OnPropertyChanged("ImageWidth");
                }
            }
            public int ImageHeight
            {
                get
                {
                    return _imageHeight;
    
                }
                set
                {
                    _imageHeight = value;
                    OnPropertyChanged("ImageHeight");
                }
            }
    
            public string ImagePath
            {
                get
                {
                    return _imagePath;
    
                }
                set
                {
                    _imagePath = value;
                    OnPropertyChanged("ImagePath");
                }
            }
            public int Ordinal
            {
                get
                {
                    return _ordinal;
                }
                set
                {
                    _ordinal = value;
                    OnPropertyChanged("Ordinal");
                }
            }
    
            public int Width
            {
                get
                {
                    return _width;
                }
                set
                {
                    _width = value;
                    OnPropertyChanged("Width");
                }
            }
    
            public int Height
            {
                get
                {
                    return _height;
                }
                set
                {
                    _height = value;
                    ImageHeight = _height * 500;
                    //VariableGridView obj = new VariableGridView();
                    //obj.Update();
                    OnPropertyChanged("Height");
                }
            }
    
            public ImageSource Image
            {
                get
                {
                    return new BitmapImage(new Uri("ms-appx:/Assets/" + this.ImagePath));
                }
            }
    
            private ImageModel selectedImage;
    
            public ImageModel SelectedImage
            {
                get { return selectedImage; }
                set
                {
                    //this.SetProperty(ref this.selectedImage, value);
                    selectedImage = value;
                    OnPropertyChanged("SelectedImage");
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
    
        }
    }
    

    ViewModel:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    
    namespace Demo
    {
        public class ImageViewModel : INotifyPropertyChanged
        {
            private ObservableCollection<ImageModel> _list;
       
    
    
            public ImageViewModel()
            {
                _list = new ObservableCollection<ImageModel>
                 {
                     new  ImageModel{ImagePath="beer.jpg",Width=1,Height=2,Ordinal=4},                 new  ImageModel{ImagePath="sugars.jpg",Width=2,Height=1,Ordinal=6},
                    new  ImageModel{ImagePath="herbs.jpg",Width=1,Height=2,Ordinal=2},
                    new  ImageModel{ImagePath="yeast.jpg",Width=2,Height=2,Ordinal=3},
                    new  ImageModel{ImagePath="malt.jpg",Width=1,Height=2,Ordinal=1},
                    new  ImageModel{ImagePath="hops.jpg",Width=2,Height=2,Ordinal=5},
    
                 };
                _list = new ObservableCollection<ImageModel>(_list.OrderBy(i => i.Ordinal));
                // _list = _list.OrderBy(i => i.Ordinal).ToList();
            }
    
    
    
            public ObservableCollection<ImageModel> Images
            {
                get { return _list; }
                set
                {
                    _list = value;
                   
                    OnPropertyChanged("Images");
    
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
    

    View:

    <Page
        x:Class="Demo.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Demo"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.DataContext>
            <local:ImageViewModel />
        </Page.DataContext>
    
        <Page.Resources>
    
            <Style x:Key="rectangleStyle" TargetType="Rectangle">
                <Setter Property="Fill" Value="White"/>
                <Setter Property="Stroke" Value="Gray"></Setter>
            </Style>
    
            <Style x:Key="headerTextBlockStyle" TargetType="TextBlock">
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="FontSize" Value="32"/>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
            </Style>
    
            <Style x:Key="textBlockStyle" TargetType="TextBlock">
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="FontSize" Value="25"/>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
            </Style>
    
            <Style x:Key="textBoxStyle" TargetType="TextBox">
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="FontSize" Value="25"/>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="Width" Value="100"></Setter>
                <Setter Property="Height" Value="50"></Setter>
                <Setter Property="MaxLength" Value="1"></Setter>
                <!--<Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="0"/>-->
                <Setter Property="Margin" Value="25,0,25,10"/>
            </Style>
        </Page.Resources>
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ScrollViewer HorizontalScrollBarVisibility="Visible" HorizontalScrollMode="Enabled" 
                          VerticalScrollMode="Disabled" VerticalScrollBarVisibility="Hidden">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="60"></RowDefinition>
                        <RowDefinition Height="100"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="60"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="60"></ColumnDefinition>
                        <ColumnDefinition Width="auto"></ColumnDefinition>
                        <ColumnDefinition Width="100"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
    
                    <StackPanel Grid.Row="1"  Grid.Column="1" Orientation="Horizontal" Height="50" Margin="4,50,0,0">
                        <Grid>
                            <Grid.RowDefinitions>
    
                                <RowDefinition Height="60"></RowDefinition>
    
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="150"></ColumnDefinition>
                                <ColumnDefinition Width="150"></ColumnDefinition>
                                <ColumnDefinition Width="150"></ColumnDefinition>
                                <ColumnDefinition Width="150"></ColumnDefinition>
    
                            </Grid.ColumnDefinitions>
    
                            <Rectangle Grid.Column="0" Style="{StaticResource rectangleStyle}" Margin="0,0,0,10"/>
                            <TextBlock Grid.Column="0" Text="Image" Style="{StaticResource headerTextBlockStyle}"/>
    
                            <Rectangle  Grid.Column="1" Style="{StaticResource rectangleStyle}" Margin="0,0,0,10"/>
                            <TextBlock Grid.Column="1" Text="Ordinal" Style="{StaticResource headerTextBlockStyle}"/>
    
                            <Rectangle  Grid.Column="2" Style="{StaticResource rectangleStyle}" Margin="0,0,0,10"/>
                            <TextBlock Grid.Column="2" Text="Width" Style="{StaticResource headerTextBlockStyle}"/>
    
                            <Rectangle  Grid.Column="3" Style="{StaticResource rectangleStyle}" Margin="0,0,0,10"/>
                            <TextBlock Grid.Column="3" Text="Height" Style="{StaticResource headerTextBlockStyle}"/>
                        </Grid>
    
    
                    </StackPanel>
    
    
                    <ListView Name="ListView1" Grid.Row="2" Grid.Column="1" 
                              ItemsSource="{Binding Images,Mode=TwoWay}" 
                              TabNavigation="Local">
                        <ListView.ItemTemplate>
                            <!--Padding="-10 0 -10 -10"
                             Margin="5 0 0 0"-->
    
                            <DataTemplate>
    
                                <Grid Background="White">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="60"></RowDefinition>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="150"></ColumnDefinition>
                                        <ColumnDefinition Width="150"></ColumnDefinition>
                                        <ColumnDefinition Width="150"></ColumnDefinition>
                                        <ColumnDefinition Width="150"></ColumnDefinition>
                                    </Grid.ColumnDefinitions>
    
                                    <Rectangle Grid.Column="0" Style="{StaticResource rectangleStyle}" Margin="0 -20 0 0"/>
                                    <TextBlock Grid.Column="0" Text="{Binding ImagePath,Mode=TwoWay}" Style="{StaticResource textBlockStyle}" />
    
                                    <Rectangle Grid.Column="1" Style="{StaticResource rectangleStyle}" Margin="0 -20 0 0"/>
                                    <TextBlock Grid.Column="1"  Text="{Binding Ordinal,Mode=TwoWay}" Style="{StaticResource textBlockStyle}"/>
    
                                    <Rectangle  Grid.Column="2" Style="{StaticResource rectangleStyle}" Margin="0 -20 0 0"/>
                                    <TextBox Grid.Column="2" Text="{Binding Width,Mode=TwoWay}" Style="{StaticResource textBoxStyle}"  Height="Auto" />
    
                                    <Rectangle Grid.Column="3" Style="{StaticResource rectangleStyle}" Margin="0 -20 0 0"/>
                                    <TextBox Grid.Column="3" Text="{Binding Height,Mode=TwoWay}" Style="{StaticResource textBoxStyle}" />
                                </Grid>
                            </DataTemplate>
                        </ListView.ItemTemplate>
    
                    </ListView>
    
                    <local:VariableGridView x:Name="Variable" 
                                            ItemsSource="{Binding Images,Mode=TwoWay}" 
                                            SelectedItem="{Binding SelectedImage,Mode=TwoWay}"
                                            Grid.Row="1" Grid.Column="3" Grid.RowSpan="2">
                        <local:VariableGridView.ItemTemplate>
                            <DataTemplate>
                                <Grid VariableSizedWrapGrid.ColumnSpan="{Binding Width,Mode=TwoWay}" >
                                    <Image Source="{Binding Image}"  
                                           Stretch="UniformToFill" 
                                           HorizontalAlignment="Stretch" 
                                           
                                           VerticalAlignment="Stretch"></Image> <!--Width="{Binding ImageWidth,Mode=TwoWay}" Height="{Binding ImageHeight,Mode=TwoWay}"-->
                                </Grid>
                            </DataTemplate>
                        </local:VariableGridView.ItemTemplate>
    
                        
                        <local:VariableGridView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <VariableSizedWrapGrid VerticalAlignment="Center"
                                               ItemHeight="100"
                                               ItemWidth="100"
                                               MaximumRowsOrColumns="4" 
                                                       >
    
    
                                </VariableSizedWrapGrid>
                            </ItemsPanelTemplate>
                        </local:VariableGridView.ItemsPanel>
                    </local:VariableGridView>
    
                                </Grid>
            </ScrollViewer>
        </Grid>
    
    </Page>
    

    VariableGridView:

     public class VariableGridView : GridView
        {
            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    
            {
                var viewModel = item as ImageModel;
    
                if (viewModel != null)
                {
                    element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, viewModel.Width); //viewModel.Width
                    element.SetValue(VariableSizedWrapGrid.RowSpanProperty, viewModel.Height); //viewModel.Height
                }
                base.PrepareContainerForItemOverride(element, item);
            }
    }

    Kindly give me the solution.

    thank you.

    Tuesday, December 23, 2014 5:08 AM

Answers

  • The problem is that the "Variable" VariableGridView needs to be rebound to the underlying ObservableCollection in order to reflow the GridView. 

    You may be able to listen for the ObservableCollection.CollectionChanged event and rebind when that happens.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, December 30, 2014 4:25 PM
    Moderator

All replies

  • Please provide a project containing this code. You can upload to OneDrive and share a link to it here.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, December 23, 2014 12:55 PM
    Moderator
  • Hi Matt,

    Code link is ImagesDemo.

    Wednesday, December 24, 2014 11:47 AM
  • The problem is that the "Variable" VariableGridView needs to be rebound to the underlying ObservableCollection in order to reflow the GridView. 

    You may be able to listen for the ObservableCollection.CollectionChanged event and rebind when that happens.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, December 30, 2014 4:25 PM
    Moderator
  • Hi Matt,

    What I have read about ObservableCollection.CollectionChanged event is that it gets fired only when items get added/removed from ObservableCollection but its not fired when item gets edited...

    I want to bind values when it gets edited.

    Tuesday, January 06, 2015 5:02 AM
  • You should be able to find some function that is fired when the item is edited - I'm thinking either you write your own event or a converter that rebinds the observablecollection.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, January 06, 2015 1:30 PM
    Moderator