【问题标题】:How to make input controls communicate with each other in MVVM (WPF)?如何使输入控件在 MVVM (WPF) 中相互通信?
【发布时间】:2012-10-26 09:37:38
【问题描述】:

我正在开发一个温度转换器作为测试项目。它具有三个应该相互通信的向上/向下控件。 (右侧的标签仅用于调试。)当我通过旋转(例如摄氏度)更改温度时,其相应的标签会正确更新,但我也希望开尔文和华氏值同时更改。但他们没有。为什么不呢?

目的是模型(TempModel)应该只保留一个值(Kelvin)。其他需要时计算。我尝试了不同的方法来获取摄氏和华氏值。在这种情况下,我在模型中有从私有 _Kelvin 变量计算其值的属性。它在启动时有效,但在我在运行时更改值时无效。

我也尝试对视图模型中的属性做类似的事情。

我相信解决方案相当简单,并且与绑定有关,但我仍然找不到。

这是它的样子: User interface image

这里是查看 XAML 代码:

<Window x:Class="Temperature.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
    Title="Temperature converter" Height="183" Width="468">
<Grid VerticalAlignment="Stretch">
    <Label Content="Kelvin" Height="28" HorizontalAlignment="Left" Margin="10,10,0,0" Name="label1" VerticalAlignment="Top" />
    <extToolkit:DoubleUpDown Name="_KelvinUD" Increment="0.1" FormatString="F2" Value="{Binding Kelvin}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,14,0,0" />
    <Label Height="28" HorizontalAlignment="Left" Margin="279,10,0,0" Name="label4" VerticalAlignment="Top" Content="{Binding Kelvin}" />

    <Label Content="Celsius" Height="28" HorizontalAlignment="Left" Margin="12,44,0,0" Name="label2" VerticalAlignment="Top" />
    <extToolkit:DoubleUpDown Name="_CelsiusUD" Increment="0.1" FormatString="F2" Value="{Binding Celsius}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,48,0,0" />
    <Label Height="28" HorizontalAlignment="Left" Margin="279,44,0,0" Name="label5" VerticalAlignment="Top" Content="{Binding Celsius}" />

    <Label Content="Fahrenheit" Height="28" HorizontalAlignment="Left" Margin="12,78,0,0" Name="label3" VerticalAlignment="Top" />
    <extToolkit:DoubleUpDown Name="_FarenheitUD" Increment="0.1" FormatString="F2" Value="{Binding Fahrenheit}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,82,0,0" />
    <Label Height="28" HorizontalAlignment="Left" Margin="279,78,0,0" Name="label6" VerticalAlignment="Top" Content="{Binding Fahrenheit}" />
</Grid>

背后的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Temperature
{
    public partial class MainWindow : Window
    {
        private TempViewModel _viewModel = new TempViewModel();
        TempViewModel ViewModel
        {
            get { return _viewModel; }
        }

        public MainWindow()
        {
            InitializeComponent();
            base.DataContext = ViewModel;
        }
    }
}

型号:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Temperature
{
    public class TempModel
    {
        private double _kelvin;
        public double Kelvin
        {
            get
            {
                return _kelvin;
            }
            set
            {
                _kelvin = value;
                OnPropertyChanged("Kelvin");
            }
        }

        public double Celsius
        {
            get
            {
                return _kelvin - 273.15;
            }
            set
            {
                _kelvin = value + 273.15;
                OnPropertyChanged("Celsius");
            }
        }

        public double Fahrenheit
        {
            get
            {
                return 9.0 / 5.0 * (_kelvin - 273.15) + 32;
            }
            set
            { 
                _kelvin = 5.0 / 9.0 * (value - 32) + 273.15;
                OnPropertyChanged("Fahrenheit");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

视图模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Temperature
{
    class TempViewModel
    {
        TempModel _tempModel;

        public TempViewModel()
        {
            _tempModel = new TempModel 
            {
                Kelvin = 300.15 // Initial value
            };
        }

        public TempModel TempModel
        {
            get
            {
                return _tempModel;
            }
            set
            {
                _tempModel = value;
            }
        }

        public double Kelvin
        {
            get
            {
                return _tempModel.Kelvin;
            }
            set
            {
                _tempModel.Kelvin = value;
            }
        }
        public double Celsius
        {
            get
            {
                return _tempModel.Celsius;
            }
            set
            {
                _tempModel.Celsius = value;
            }
        }
        public double Fahrenheit
        {
            get
            {
                return _tempModel.Fahrenheit;
            }
            set
            {
                _tempModel.Fahrenheit = value;
            }
        }

    }
}

【问题讨论】:

    标签: c# wpf mvvm wpftoolkit


    【解决方案1】:

    FahrenheitCelsius 的设置器中,设置Kelvin 属性而不是_kelvin 字段。此外,从Kelvin 的设置器而不是其他度量的设置器中引发所有三个属性更改。这样,当任何温度发生变化时,Kelvin 都会更新并通知视图所有三个值都已更改。

    另外,我假设您正在实现 INotifyPropertyChanged,即使它没有在您的模型或视图模型的代码中指定。

    【讨论】:

    • public class TempModel : INotifyPropertyChanged 和下面@blindmeis 的答案的组合使它起作用。谢谢!
    【解决方案2】:

    如果一个属性的更改也改变了其他两个属性,您还必须提高 OnPropertyChanged 以便其他属性通知您的视图。

    这应该可行(快速而肮脏的方法)。我只是公开并绑定到模型属性。

    public class TempModel
    {
        private double _kelvin;
        public double Kelvin
        {
            get
            {
                return _kelvin;
            }
            set
            {
                _kelvin = value;
                OnPropertyChanged("Kelvin");
                OnPropertyChanged("Celsius");
                OnPropertyChanged("Fahrenheit");
            }
        }
    
        public double Celsius
        {
            get
            {
                return _kelvin - 273.15;
            }
            set
            {
                _kelvin = value + 273.15;
                OnPropertyChanged("Celsius");
                OnPropertyChanged("Kelvin");
                OnPropertyChanged("Fahrenheit");
            }
        }
    
        public double Fahrenheit
        {
            get
            {
                return 9.0 / 5.0 * (_kelvin - 273.15) + 32;
            }
            set
            { 
                _kelvin = 5.0 / 9.0 * (value - 32) + 273.15;
                OnPropertyChanged("Fahrenheit");
                OnPropertyChanged("Celsius");
                OnPropertyChanged("Kelvin");
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
    }
    
    public class TempViewModel
    {
        TempModel _tempModel;
    
        public TempViewModel()
        {
            _tempModel = new TempModel 
            {
                Kelvin = 300.15 // Initial value
            };
        }
    
        public TempModel TempModel
        {
            get
            {
                return _tempModel;
            }
            set
            {
                _tempModel = value;
            }
        }
    }
    
    
    <Grid VerticalAlignment="Stretch">
    
    <extToolkit:DoubleUpDown Increment="0.1" FormatString="F2" Value="{Binding TempModel.Kelvin}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,14,0,0" />
    
    <extToolkit:DoubleUpDown  Increment="0.1" FormatString="F2" Value="{Binding TempModel.Celsius}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,48,0,0" />
    
    <extToolkit:DoubleUpDown  Increment="0.1" FormatString="F2" Value="{Binding TempModel.Fahrenheit}" HorizontalAlignment="Left" Width="100" VerticalAlignment="Top" Margin="113,82,0,0" />
    </Grid> 
    

    【讨论】:

    • 谢谢!这与@mlorbetske 提到的接口(公共类 TempModel:INotifyPropertyChanged)的实现一起工作得很好。
    猜你喜欢
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    相关资源
    最近更新 更多