简体   繁体   English

当组合框选择更改时,IValueConverter 不更新 Datagrid

[英]IValueConverter not updating Datagrid When Combobox Selection is Changed

Im trying to learn and make the application using the MVVM principle.我正在尝试使用 MVVM 原理学习和制作应用程序。 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.当尝试实现 2 个 IValueConverters 时,只有其中一个被触发,即只有一个被加载和工作,即 OnStockIconConverter,它在 Datagrid 初始化时加载。

The other one, CurrencyConverter, which depends on a ComboBox toggle doesnt react on the DataGrid when I change the selected value.另一个是 CurrencyConverter,它依赖于 ComboBox 切换,当我更改所选值时,它不会对 DataGrid 做出反应。

I have been trying to solve this for hours, and most of the content out there is rather obscure for an MVVM beginner.我已经尝试解决这个问题好几个小时了,对于 MVVM 初学者来说,那里的大部分内容都相当晦涩。

All other questions on here explain the opposite of what I want to do.这里的所有其他问题都与我想做的相反。

C# 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 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.您应该将视图模型和视图分开,以便您可以使用真正的 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.为了达到目标,向您的入口模型添加一个方法,例如 NotifyAllChanged 以重新计算所有属性并在您的组合框事件处理程序中调用它。

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()); // <==
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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