简体   繁体   中英

How can I change Image in Listview during runtime in WPF?

I would like to change the picture in the cell when the user clicks on the picture. The initial picture is the "right arrow" and when the user clicks the "right arrow" it should be "red x" but the icon does not change. The value of property (Binding value[3]) changes every time to 0 and 1 so it works fine.

Here is my code:

<GridViewColumn  Header="Functions">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal">
                                                <Image x:Name="MoveImg"  Cursor="Hand" ToolTip="Move Losses" MaxWidth="20" MaxHeight="20" Margin="3,3,3,3" MouseLeftButtonUp="MoveImg_MouseLeftButtonUp" >
                                                    <Image.Style>
                                                        <Style TargetType="{x:Type Image}">
                                                            <Style.Triggers>
                                                                <DataTrigger Binding="{Binding Value[3]}" Value="1">
                                                                    <Setter Property="Source" Value="pack://application:,,,/Resources/x.ico"/>
                                                                </DataTrigger>
                                                                <DataTrigger Binding="{Binding Value[3]}" Value="0">
                                                                    <Setter Property="Source" Value="pack://application:,,,/Resources/right_arrow.png"/>
                                                                </DataTrigger>
                                                            </Style.Triggers>
                                                        </Style>
                                                    </Image.Style>
                                                </Image>
                                            </StackPanel>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>

And the code in DtListView.xaml.cs

Dictionary<string, double[]> prDict = new Dictionary<string, double[]>();
Dictionary<string, string[]> lossTransferDict = new Dictionary<string, string[]>();
public Dictionary<string, double[]> PrDict { get => prDict; set => prDict = value; }

 public DtListView()
        {
            InitializeComponent();
        }


 private void MoveImg_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {



            if (TopLossesLv.SelectedItems != null)
            {
                foreach (KeyValuePair<string, double[]> item in TopLossesLv.SelectedItems)
                {
                    if (!lossTransferDict.ContainsKey(item.Key))
                    {
                        lossTransferDict.Add(item.Key, new string[4] { line, item.Value[0].ToString(), item.Value[1].ToString(), item.Value[2].ToString()});
                        prDict[item.Key][3] = 1; // Modify Value for Picture change

                    }
                    else
                    {
                        lossTransferDict.Remove(item.Key);
                        prDict[item.Key][3] = 0; // Modify Value for Picture change

                    }


                }
            }

        }

This is not C. This is C#. C# is object oriented. Binding to an array of related values is not a good idea for many reasons. Instead bind to an object, that encapsulates the related values of the array.

Instead of binding to a dictionary of arrays, you should bind to a collection of objects. To do this, you would need to convert the array into a class, which implements INotifyPropertyChanged .
Each field of the array becomes a class property. You should apply this refactoring to all your Binding.Source , where the source is an arrays of values. At the end you should be able to bind to lists only.

Avoid binding controls to dictionaries or arrays.

This is a simple example how to use objects (data models) to populate a ListView and change the GridView cell content (the Image ) based on the value of a property SimpleDataObject.IsActive of the data model SimpleDataObject :

SimpleDataObject.cs

class SimpleDataObject : INotifyPropertyChaged
{ 
  // Constructor
  public SimpleDataObject(string data) => this.DataValue = data;

  private bool isActive;
  public bool IsActive
  {
    get => this.isActive;
    set
    {
      this.isActive = value;
      OnPropertyChanged();
    }
  }   

  private string dataValue;
  public string DataValue
  {
    get => this.dataValue;
    set
    {
      this.dataValue = value;
      OnPropertyChanged();
    }
  }   

  #region INotifyPropertyChanged implementation

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }

  #endregion
}

ViewModel.cs

// Binding source
class ViewModel : INotifyPropertyChaged
{ 
  public ViewModel()
  {
    this.SimpleDataObjects = new ObservableCollection<SimpleDataObject>() 
    {
      new SimpleDataObject("Data value 1"),
      new SimpleDataObject("Data value 2"),
      new SimpleDataObject("Data value 3")
    }
  }

  public ObservableCollection<SimpleDataObject> SimpleDataObjects { get; set; }
}

MainWindow.xaml.cs

partial class MainWindow : Window
{
  private void OnImageMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  {
    var image = sender as Image;
    var dataItem = image.DataContext as SimpleDataObject;
    dataItem.IsActive = true; // Toggle image
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <ListView ItemsSource="{Binding SimpleDataObjects}">
    <ListView.View>
      <GridView>
        <GridView.Columns>
          <GridViewColumn  Header="Functions">
            <GridViewColumn.CellTemplate>
              <DataTemplate DataType="{x:Type SimpleDataObject}">
                <StackPanel Orientation="Horizontal">
                  <TextBlock Text="{Binding DataValue}"/>

                  <Image MouseLeftButtonUp="OnImageMouseLeftButtonUp">
                    <Image.Style>
                      <Style TargetType="Image">

                        <!-- Default value. Applies when the observed property IsActive returns false -->
                        <Setter Property="Source" Value="pack://application:,,,/Resources/right_arrow.png" />

                        <Style.Triggers>
                          <DataTrigger Binding="{Binding IsActive}" Value="True">
                            <Setter Property="Source" Value="pack://application:,,,/Resources/x.ico" />
                          </DataTrigger>
                        </Style.Triggers>
                      </Style>
                    </Image.Style>
                  </Image>
                </StackPanel>
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
        </GridView.Columns>
      </GridView>
    </ListView.View>
  </ListView>
</Window>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM