WPF UserControl属性更改未更新

我有一个UserControl,我添加到我的主应用程序。 该UserControl包含UIElement的按钮

UserControl包含DispatchTimer,并且每2秒基于一些int值确定按钮图像的内容。

UserControl中调用的方法之一应该设置它的图像,但控件永远不会显示它被更改为的图像。

public void SetNormal() { btnFlashAlert.Content = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute)); } 

是否有一些东西我不知道在主应用程序上看到控件更新?

当我查看.Content包含的内容时,它是正确的。 用户界面不反映变化。

XAML

    

Codebehind 更新

  public partial class MainButton : UserControl { private SupportConsoleWeb.MessageData messageCounts { get; set; } private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer(); private BitmapImage NormalImage { get; set; } private BitmapImage CriticalImage { get; set; } private BitmapImage AlertImage { get; set; } private BitmapImage InfoImage { get; set; } public MainButton() { InitializeComponent(); messageCounts = new SupportConsoleWeb.MessageData(); messageCounts.CriticalCount = 0; messageCounts.AlertCount = 0; messageCounts.InfoCount = 0; NormalImage = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute)); CriticalImage = new BitmapImage(new Uri("Images/FlashButtonRed.png", UriKind.RelativeOrAbsolute)); AlertImage = new BitmapImage(new Uri("Images/FlashButtonOrange.png", UriKind.RelativeOrAbsolute)); InfoImage = new BitmapImage(new Uri("Images/FlashButtonGreen.png", UriKind.RelativeOrAbsolute)); flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2); flashButtonChangeTimer.Tick += flashButtonChangeTimer_Tick; flashButtonChangeTimer.Start(); } void flashButtonChangeTimer_Tick(object sender, EventArgs e) { btnFlashAlert.Dispatcher.BeginInvoke(new Action(() => { if (btnFlashAlert.Content == null) { SetNormal(); } else if (messageCounts.CriticalCount > 0 && btnFlashAlert.Content.Equals(CriticalImage)) { SetNormal(); } else if (messageCounts.AlertCount > 0 && btnFlashAlert.Content.Equals(AlertImage)) { SetNormal(); } else if (messageCounts.InfoCount > 0 && btnFlashAlert.Content.Equals(InfoImage)) { SetNormal(); } else if (messageCounts.CriticalCount > 0) { SetCritical(); } else if (messageCounts.AlertCount > 0) { SetAlert(); } else if (messageCounts.InfoCount > 0) { SetInfo(); } })); } public void UpdateMessageCounts(SupportConsoleWeb.MessageData messageCounts) { this.messageCounts = messageCounts; } private void btnFlashAlert_Click(object sender, RoutedEventArgs e) { MainWindow window = new MainWindow(); window.WindowStartupLocation = WindowStartupLocation.CenterScreen; window.ShowDialog(); } public void SetMessageCount(int criticalCount, int alertCount, int infoCount) { messageCounts.CriticalCount = criticalCount; messageCounts.AlertCount = alertCount; messageCounts.InfoCount = infoCount; } private void SetNormal() { btnFlashAlert.Content = NormalImage; } private void SetCritical() { btnFlashAlert.Content = CriticalImage; } private void SetAlert() { btnFlashAlert.Content = AlertImage; } private void SetInfo() { btnFlashAlert.Content = InfoImage; } } 

将XAML更改为此

   

添加通知属性已更改

  public partial class MainButton : UserControl, INotifyPropertyChanged 

创建OnPropertyChanged事件

  void OnPropertyChanged(String prop) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } public event PropertyChangedEventHandler PropertyChanged; 

创建一个Bitmap prop并通知prop更改的事件

  private BitmapImage _TheImage; public BitmapImage TheImage { get { return _TheImage; } set { _TheImage = value; OnPropertyChanged("TheImage"); } } 

在您的初始化程序中

  public MainButton() { this.DataContext = this; InitializeComponent(); TheImage = new BitmapImage(); 

现在在你的设置方法中调用

 TheImage = //Your Bitmap Goes here 

我知道这似乎过多,但从长远来看,你会发现这是一个更清洁的实施。

我相信当没有条件满足时,图片选择逻辑没有默认图像的问题……

话虽如此, 恕我直言 ,通过预先加载所有图像并将其可见性初始设置为隐藏,可以更好地表达图像逻辑。 然后将每个图像的可见性绑定到VM上的特定标志布尔值。 其中定时器事件可以简单地打开或关闭布尔值,最终将根据需要显示或隐藏图像。

这消除了由于加载和显示图像而导致的任何延迟,因为它们将被预加载; 它还将解决由于加载/卸载图像而导致的任何可能的未来内存问题。

以下示例包含一个包含两个图像的按钮。 图像的可见性都与VM上的布尔值绑定。 VM具有一个布局,其中图像工作,并且计时器每两秒改变其状态来切换图像。

XAML:

     

VM

 public class MainVM : INotifyPropertyChanged { private bool _bSwitch; private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer(); public bool IsRecycleOn { get { return _bSwitch; } } public bool IsCopyOn { get { return !_bSwitch; } } public MainVM() { flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2); flashButtonChangeTimer.Tick += (sender, args) => { _bSwitch = ! _bSwitch; OnPropertyChanged("IsCopyOn"); OnPropertyChanged("IsRecycleOn"); }; flashButtonChangeTimer.Start(); } /// Event raised when a property changes. public event PropertyChangedEventHandler PropertyChanged; /// Raises the PropertyChanged event. /// The name of the property that has changed. protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }