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

时间:2017-10-23 07:17:29

标签: c# wpf mvvm combobox datagrid

我试图学习并使用MVVM原理制作应用程序。我正在做的是这个,

enter image description here

当试图实现2个IValueConverters时,只触发其中一个,即只有一个被加载并运行,OnStockIconConverter,在Datagrid初始化时加载。

当我更改所选值时,另一个依赖于ComboBox切换的CurrencyConverter对DataGrid没有反应。

我一直试图解决这个问题几个小时,而且MVVM初学者的大部分内容都相当模糊。

这里的所有其他问题都解释了我想做的事情的反面。

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>

1 个答案:

答案 0 :(得分:1)

您应该将viewmodel和view分开,以便可以使用真正的MVVM。现在您的视图同时是一个视图模型 要达到目标,请为您的输入模型添加一个方法,例如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()); // <==
    }