如何检测整个绑定的 ViewModel 是否已更改?
How to detect that entire binded ViewModel has changed?
我有一个简单的视图模型 class,它包含三个属性。
public class ColorViewModel : INotifyPropertyChanged
{
private int red;
public int Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private int green;
public int Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private int blue;
public int Blue
{
get { return blue; }
set
{
if (blue!= value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
现在我想将整个模型传递给给定的转换器,以便为 RGB 值创建颜色。
<Rectangle Grid.Row="4" Grid.Column="1" HorizontalAlignment="Center" Height="120" Width="120"
Fill="{Binding Model, Converter={StaticResource intToBrushValueConverter}}"/>
其中 Model
是我的 ColorViewModel
.
的一个实例
问题是 intToBrushValueConverter
转换器只在程序启动时触发一次。换句话说,当 Model
改变时,转换器不会被触发。
然后当 ColorViewModel
中的一个 属性 被更改时,PropertyChanged
工作,但 initToBrushValueConverter
转换器没有命中。
有一种方法可以解决这个问题吗?
我正在寻找一种不使用 MultiBinding
或 CommandParameter
的解决方案。
提前致谢。
问题在于 Rectangle 仅侦听 Model
的 PropertyChanged
事件,而不侦听三种颜色属性。
尝试使用 RaisePropertyChanged("Model");
或 RaisePropertyChanged(null);
为 Model
本身引发事件。
挂钩 属性 将事件更改为父视图模型,并在火 属性 每当 属性 更改颜色 属性 时更改事件。
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
更新:
下面是完整的工作解决方案。
MainWindows.xaml.cs
using System;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Random random = new Random();
private ParentViewModel model;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.model = new ParentViewModel();
this.model.Color = new ColorViewModel();
}
public ParentViewModel Model
{
get { return model; }
set
{
model = value;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.model.Color.Blue = (byte)random.Next(0, 255);
this.model.Color.Green = (byte)random.Next(0, 255);
this.model.Color.Red = (byte)random.Next(0, 255);
}
}
}
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:IntToBrushConverter x:Key="intToBrushConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Rectangle HorizontalAlignment="Center" Height="120" Width="120" Fill="{Binding Model.Color, Converter={StaticResource intToBrushConverter}, FallbackValue=Black}"/>
<Button Grid.Row="1" Content="Click me!" Click="Button_Click" />
</Grid>
</Window>
IntToBrushConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace WpfApp1
{
public class IntToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is ColorViewModel)
{
var color = value as ColorViewModel;
return new SolidColorBrush(Color.FromRgb(color.Red, color.Green, color.Blue));
}
throw new NotSupportedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
ParentViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
ColorViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ColorViewModel : INotifyPropertyChanged
{
private byte red;
public byte Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private byte green;
public byte Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private byte blue;
public byte Blue
{
get { return blue; }
set
{
if (blue != value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
App.xaml 和 App.xaml.cs 是模板生成的标准。
输出
希望对您有所帮助!
我有一个简单的视图模型 class,它包含三个属性。
public class ColorViewModel : INotifyPropertyChanged
{
private int red;
public int Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private int green;
public int Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private int blue;
public int Blue
{
get { return blue; }
set
{
if (blue!= value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
现在我想将整个模型传递给给定的转换器,以便为 RGB 值创建颜色。
<Rectangle Grid.Row="4" Grid.Column="1" HorizontalAlignment="Center" Height="120" Width="120"
Fill="{Binding Model, Converter={StaticResource intToBrushValueConverter}}"/>
其中 Model
是我的 ColorViewModel
.
问题是 intToBrushValueConverter
转换器只在程序启动时触发一次。换句话说,当 Model
改变时,转换器不会被触发。
然后当 ColorViewModel
中的一个 属性 被更改时,PropertyChanged
工作,但 initToBrushValueConverter
转换器没有命中。
有一种方法可以解决这个问题吗?
我正在寻找一种不使用 MultiBinding
或 CommandParameter
的解决方案。
提前致谢。
问题在于 Rectangle 仅侦听 Model
的 PropertyChanged
事件,而不侦听三种颜色属性。
尝试使用 RaisePropertyChanged("Model");
或 RaisePropertyChanged(null);
为 Model
本身引发事件。
挂钩 属性 将事件更改为父视图模型,并在火 属性 每当 属性 更改颜色 属性 时更改事件。
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
更新:
下面是完整的工作解决方案。
MainWindows.xaml.cs
using System;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Random random = new Random();
private ParentViewModel model;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.model = new ParentViewModel();
this.model.Color = new ColorViewModel();
}
public ParentViewModel Model
{
get { return model; }
set
{
model = value;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.model.Color.Blue = (byte)random.Next(0, 255);
this.model.Color.Green = (byte)random.Next(0, 255);
this.model.Color.Red = (byte)random.Next(0, 255);
}
}
}
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:IntToBrushConverter x:Key="intToBrushConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Rectangle HorizontalAlignment="Center" Height="120" Width="120" Fill="{Binding Model.Color, Converter={StaticResource intToBrushConverter}, FallbackValue=Black}"/>
<Button Grid.Row="1" Content="Click me!" Click="Button_Click" />
</Grid>
</Window>
IntToBrushConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace WpfApp1
{
public class IntToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is ColorViewModel)
{
var color = value as ColorViewModel;
return new SolidColorBrush(Color.FromRgb(color.Red, color.Green, color.Blue));
}
throw new NotSupportedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
ParentViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ParentViewModel : INotifyPropertyChanged
{
private ColorViewModel color;
public ColorViewModel Color
{
get { return color; }
set
{
if (color != value)
{
if (color != null)
color.PropertyChanged -= this.ChildPropertyChanged;
color = value;
if (color != null)
color.PropertyChanged += this.ChildPropertyChanged;
RaisePropertyChanged("Color");
}
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (Color == sender)
{
RaisePropertyChanged("Color");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
ColorViewModel.cs
using System.ComponentModel;
namespace WpfApp1
{
public class ColorViewModel : INotifyPropertyChanged
{
private byte red;
public byte Red
{
get { return red; }
set
{
if (red != value)
{
red = value;
RaisePropertyChanged("Red");
}
}
}
private byte green;
public byte Green
{
get { return green; }
set
{
if (green != value)
{
green = value;
RaisePropertyChanged("Green");
}
}
}
private byte blue;
public byte Blue
{
get { return blue; }
set
{
if (blue != value)
{
blue = value;
RaisePropertyChanged("Blue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
App.xaml 和 App.xaml.cs 是模板生成的标准。
输出
希望对您有所帮助!