【问题标题】:WPF UserControl property change not updatingWPF UserControl 属性更改未更新
【发布时间】:2014-02-20 04:42:36
【问题描述】:

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

UserControl 包含一个 DispatchTimer,每 2 秒根据一些 int 值确定按钮图像是什么。

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

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

在主应用程序上获得控件更新的外观我是否缺少一些东西?

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

XAML

<UserControl x:Class="SC.FlashSystem.MainButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" Height="53" Width="164">
<Button x:Name="btnFlashAlert" Background="{x:Null}" BorderBrush="{x:Null}" Cursor="Hand" Click="btnFlashAlert_Click">
    <Button.Template>
        <ControlTemplate>
            <Image Source="Images/FlashButton.png"/>
        </ControlTemplate>
    </Button.Template>
</Button>

代码隐藏更新

        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 和代码。
  • 您的 XAML 错误,而且您正在更改 Button.Content 并再次放置 相同的图像,即使它有效,您也不会在视觉上看到任何变化。请澄清这一点。你有没有把它改成别的东西?
  • 我将发布代码,这只是我发布的一种方法
  • 从 xaml 中移除按钮模板

标签: c# wpf


【解决方案1】:

将您的 XAML 更改为此

 <Image Source="{Binding TheImage}"/>

添加通知属性已更改

 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;

创建位图道具并通知道具更改事件

    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

我知道这似乎有些过分,但从长远来看,您会发现它是一个更简洁的实现。

【讨论】:

  • 完美,这也清理了其他部分的逻辑
  • 我一直是个怀疑论者。但是,在进行 WPF 或其变体时,数据绑定是滚动的唯一方法。
【解决方案2】:

我认为这是图片选择逻辑在不满足任何条件时没有默认图片的问题...

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

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

示例

以下示例有一个带有两个图像的按钮。两个图像的可见性都绑定到 VM 上的布尔值。虚拟机有一个布尔值,镜像工作时使用的布尔值和一个每两秒切换一次镜像状态的计时器。

Xaml:

<Window.Resources>
   <BooleanToVisibilityConverter  x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>

<Button x:Name="bStatus" Width="48" Height="48">
    <StackPanel Orientation="Vertical">
        <Image Source="Images\Copy-icon.png" Visibility="{Binding IsCopyOn, 
                                                            Converter={StaticResource BooleanToVisibilityConverter}}" />
        <Image Source="Images\Recycle-icon.png"
                Visibility="{Binding IsRecycleOn, 
                            Converter={StaticResource BooleanToVisibilityConverter}}" />
    </StackPanel>
</Button>

虚拟机

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();

    }

    /// <summary>Event raised when a property changes.</summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>Raises the PropertyChanged event.</summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

【讨论】:

  • 感谢您让我思考了一些我之前没有注册过的延迟和内存问题。您能否展示一个将多个图像绑定到按钮的示例?没想到您可以拥有多个图像源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 2014-04-23
  • 2021-04-16
  • 2019-11-25
  • 2020-06-11
相关资源
最近更新 更多