简体   繁体   中英

IValueConverter not updating Datagrid When Combobox Selection is Changed

Im trying to learn and make the application using the MVVM principle. What Im working on is this,

在此处输入图片说明

When trying to implement 2 IValueConverters, only one of them is triggered ie only one is loaded and works, the OnStockIconConverter, which is loaded when the Datagrid is initialised.

The other one, CurrencyConverter, which depends on a ComboBox toggle doesnt react on the DataGrid when I change the selected value.

I have been trying to solve this for hours, and most of the content out there is rather obscure for an MVVM beginner.

All other questions on here explain the opposite of what I want to do.

C#

namespace Coding_Dojo_3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 
    /// 


    public partial class MainWindow : Window
    {

        public ObservableCollection<StockEntryModel> StockEntriesCollection { get; }

        public MainWindow()
        {

            InitializeComponent();
            var sampleManager = new SampleManager();
            StockEntriesCollection = new ObservableCollection<StockEntryModel>();
            foreach (var stockEntry in sampleManager.CurrentStock.OnStock)
            {
                StockEntriesCollection.Add((new StockEntryModel{SoftwarePackage = stockEntry.SoftwarePackage, Amount = stockEntry.Amount}));
            }
            DataContext = this;
        }

        private void ComboBoxCurrency_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
            SelectedCurrency.Name = text;
            Console.WriteLine("Currency changed to {0}", text);
        }
    }


    public class StockEntryModel : INotifyPropertyChanged
    {
        private object _softwarePackage;
        private int _amount;

        public event PropertyChangedEventHandler PropertyChanged;

        public object SoftwarePackage
        {
            get => _softwarePackage;
            set
            {
                _softwarePackage = value;
                OnPropertyChanged(nameof(SoftwarePackage));
            } 
        }

        public int Amount
        {
            get { return _amount; }
            set
            {
                _amount = value;

                OnPropertyChanged(nameof(Amount));
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }


    public class StockEntryViewModel
    {
        public StockEntryModel NewStockEntryModel { get; set; }

        public StockEntryViewModel()
        {
            NewStockEntryModel = new StockEntryModel();
        }
    }


    public static class SelectedCurrency
    {
        public static String Name;
    }

    public class CurrencyConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var currency = SelectedCurrency.Name;
            switch (currency)
            {

                case "EUR":
                    return CodingDojo4DataLib.Converter.CurrencyConverter.ConvertFromEuroTo(Currencies.EUR,
                            (double)value);
                case "USD":
                    return CodingDojo4DataLib.Converter.CurrencyConverter.ConvertFromEuroTo(Currencies.EUR,
                        (double)value);
                case "GBP":
                    return CodingDojo4DataLib.Converter.CurrencyConverter.ConvertFromEuroTo(Currencies.EUR,
                        (double)value);
                default:
                    return CodingDojo4DataLib.Converter.CurrencyConverter.ConvertFromEuroTo(Currencies.EUR,
                        (double)value);
            }

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class OnStockIconConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is int)
            {
                if ((int)value < 10)
                    return "red";
                if ((int)value > 10 && (int)value < 20)
                    return "orange";
                if ((int)value > 20)
                    return "green";
            }
            return "red";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

XAML

<Window x:Class="Coding_Dojo_3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Coding_Dojo_3"
        mc:Ignorable="d"
        Title="Coding Dojo 3" Height="400" Width="1024">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.125*" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="0.125*" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Label VerticalAlignment="Top">Currency :</Label>
            <ComboBox AllowDrop="True" Name="ComboBoxCurrency" VerticalAlignment="Top" SelectionChanged="ComboBoxCurrency_SelectionChanged">
                <ComboBoxItem IsSelected="True">EUR</ComboBoxItem>
                <ComboBoxItem>USD</ComboBoxItem>
            </ComboBox>
        </StackPanel>
        <DataGrid Grid.Row="1" 
                  Name="DataGridStock" 
                  AutoGenerateColumns="False"
                  ColumnWidth="*" 
                  x:FieldModifier="public"
                  IsReadOnly="False"
                  CanUserAddRows="True"
                  CanUserDeleteRows="True"
                  ItemsSource="{Binding StockEntriesCollection}">
            <DataGrid.Resources>
                <local:CurrencyConverter x:Key="CurrencyConverter"/>
                <local:OnStockIconConverter x:Key="OnStockIconConverter"/>
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding SoftwarePackage.Name}"></DataGridTextColumn>
                <DataGridTextColumn Header="Group" Binding="{Binding SoftwarePackage.Category.Name}"></DataGridTextColumn>
                <DataGridTextColumn Header="Sales Price" Binding="{Binding SoftwarePackage.SalesPrice, NotifyOnTargetUpdated=True, Converter={StaticResource CurrencyConverter}}"></DataGridTextColumn>
                <DataGridTextColumn Header="Purchase Price" Binding="{Binding SoftwarePackage.PurchasePrice, NotifyOnTargetUpdated=True, Converter={StaticResource CurrencyConverter}}"></DataGridTextColumn>
                <DataGridTextColumn Header="Amount" Binding="{Binding Amount}"></DataGridTextColumn>
                <DataGridTextColumn Header="On Stock" Binding="{Binding Amount,  Converter={StaticResource OnStockIconConverter}}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
        <StackPanel Grid.Row="2" Orientation="Horizontal">
            <Button Margin="3">Add</Button>
            <Button Margin="3">Edit</Button>
            <Button Margin="3">Delete</Button>
        </StackPanel>
    </Grid>
</Window>

You should separate your viewmodel and view for you can work with real MVVM. Now your view is at the same time a viewmodel.
To reach the goal add to your entry model a method eg NotifyAllChanged to recalculate all properties and call it in your combobox event handler.

public class StockEntryModel : INotifyPropertyChanged
{
    ...

    public void NotifyAllChanged()
    {
        OnPropertyChanged(string.Empty);
    }
}

       private void ComboBoxCurrency_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
        SelectedCurrency.Name = text;
        Console.WriteLine("Currency changed to {0}", text);

        StockEntriesCollection?.ForEach(entry=>entry.NotifyAllChanged()); // <==
    }

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