Verint Verint
Verint Verint

Reputation: 567

ObservableCollection not update my UI

This is my Model:

public class WiresharkFile : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    virtual public void NotifyPropertyChange(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

   private string _file; // file path
   private string _packets; // how many packet in file
   private string _sentPackets; // how many packet sent
   private string _progress; // percentage (_sentPackets/_packets) * 100

   public int Progress
   {
       get { return _progress; }
       set
       {
           _progress = value;
           NotifyPropertyChange("Progress");
       }
   }

   public void Transmit(WireshrkFile)
   {
         // here i am send the packets
   }

    public event PropertyChangedEventHandler PropertyChanged;

    virtual public void NotifyPropertyChange(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

My model collection:

public ObservableCollection<WireshrkFile> files{ get; set; }

My ListView:

    <ListView Name="lvFiles" Margin="16,455,0,65" Background="Transparent" BorderThickness="0,1,0,1" 
              ItemsSource="{Binding pcapFiles}" MouseDoubleClick="lvPcapFiles_MouseDoubleClick" 
              MouseDown="lvPcapFiles_MouseDown" MouseLeftButtonDown="lvPcapFiles_MouseLeftButtonDown" >
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListViewItem}">
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="SnapsToDevicePixels" Value="True"/>
                <Setter Property="Padding" Value="4,1"/>
                <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                <Style.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsMouseOver" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Foreground" Value="Black"></Setter>
                        <Setter Property="Background" Value="#FFD8D5D5"/>
                        <Setter Property="BorderBrush" Value="White"/>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive" Value="False"/>
                            <Condition Property="IsSelected" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" Value="#FF15669E"/>
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="BorderBrush" Value="Transparent"/>
                        <Setter Property="BorderThickness" Value="0"/>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive" Value="True"/>
                            <Condition Property="IsSelected" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" Value="#FF15669E"/>
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="BorderBrush" Value="Transparent"/>
                        <Setter Property="BorderThickness" Value="1"/>
                    </MultiTrigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.Resources>
            <DataTemplate x:Key="MyDataTemplate">
                <Grid Margin="-6">
                    <ProgressBar Name="progressBarColumn" Maximum="100" Value="{Binding Progress}" 
                                 Width="{Binding Path=Width, ElementName=ProgressCell}" 
                                 Height="20" Margin="0" Background="Gray" Style="{StaticResource CustomProgressBar}" />
                    <TextBlock Text="{Binding Path=Value, ElementName=progressBarColumn, StringFormat={}{0}%}" VerticalAlignment="Center"
                               HorizontalAlignment="Center" FontSize="11" Foreground="White" />
                </Grid>
            </DataTemplate>
            <ControlTemplate x:Key="ProgressBarTemplate">
                <Label  HorizontalAlignment="Center" VerticalAlignment="Center" />
            </ControlTemplate>
        </ListView.Resources>
        <ListView.View>
            <GridView ColumnHeaderContainerStyle="{StaticResource ListViewHeaderStyle}">
                <!-- file name column -->
                <GridViewColumn Width="420" Header="File name" DisplayMemberBinding="{Binding FileName}" />

                <!-- duration column -->
                <GridViewColumn Width="60" Header="Duration" DisplayMemberBinding="{Binding Duration}" />

                <!-- packets column -->
                <GridViewColumn Width="80" Header="Packets" DisplayMemberBinding="{Binding Packets}" />

                <!-- packet sent -->
                <GridViewColumn Width="80" Header="Packet sent" DisplayMemberBinding="{Binding PacketsSent}" />

                <!-- progress column -->
                <GridViewColumn x:Name="ProgressCell"  Width="50" Header="Progress" CellTemplate="{StaticResource MyDataTemplate}" />
            </GridView>
        </ListView.View>
        <ListView.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Open Capture" FontSize="12" FontFamily="Microsoft Sans Serif"
                              Click="MenuItem_Click" VerticalAlignment="Center" Height="20">
                    <MenuItem.Icon>
                        <Image Height="18" Width="18" VerticalAlignment="Center"
                               Source="C:\Users\rsteinbe\Dropbox\PacketPlayer\PacketPlayer\resources\wireshark.ico" />
                    </MenuItem.Icon>
                </MenuItem>
            </ContextMenu>
        </ListView.ContextMenu>
    </ListView>

I can see that my collection properties changing but mu UI not.

Upvotes: 2

Views: 284

Answers (1)

Olaru Mircea
Olaru Mircea

Reputation: 2620

Note: Pay attention here: ItemsSource="{Binding WiresharkFile}"

Change this to ItemsSource="{Binding files}"

I've prepared a small sample:

Window x:Class="ProgressBarChangedStack.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <StackPanel>
        <ListView ItemsSource="{Binding files}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="Progress: "/>
                        <ProgressBar Value="{Binding Progress}" Margin="5" MinWidth="100"/>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Content="Click to complete progress" Width="150" Margin="10" Click="btnProgressComplete_Click"/>
    </StackPanel>
</Grid>

Simple View, you have a ProgressBar there with its Value bound to a property from the Model.

This is the Model:

public class Model : INotifyPropertyChanged
{
    private int _Progress;

    public int Progress
    {
        get { return _Progress; }
        set
        {
            _Progress = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Progress"));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

I think there is nothing to explain here, you have the same approach.

And here is my testing code:

 public partial class MainWindow : Window
{
    public ObservableCollection<Model> files { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        files = new ObservableCollection<Model>();
        files.Add(new Model() { Progress = 20 });
        files.Add(new Model() { Progress = 30 });
        files.Add(new Model() { Progress = 40 });
        this.DataContext = this;
    }

    private void btnProgressComplete_Click(object sender, RoutedEventArgs e)
    {
        foreach (var file in files)
        {
            file.Progress = 100;
        }
    }
}

So, when i click the Button, all the ProgressBars will be complete.

I see you don't have INPC implemented for these properties:

  private string _file; // file path
  private string _packets; // how many packet in file
  private string _sentPackets; // how many packet sent
  private string _progress; // percentage (_sentPackets/_packets) * 100

With their actual form, the View will not be inform when changes occur.

Upvotes: 1

Related Questions