【发布时间】:2018-11-29 21:13:07
【问题描述】:
BoolToImage 转换器在运行时完美运行,根据与单击按钮时切换的布尔属性的绑定更改 Image 对象的 ImageSource。在设计时,VS 设计器不会显示转换器返回的图像。为什么? TrueImageProperty 和 FalseImageProperty 是静态的,它们具有默认值。为什么 VS 设计器中至少没有返回默认的 ImageSource 并显示???
转换器:
namespace BoolToImageConverterTestApp
{
[ValueConversion (typeof (bool), typeof (ImageSource))]
public class BoolToImageConverter : DependencyObject, IValueConverter
{
public static readonly DependencyProperty TrueImageProperty = DependencyProperty.Register ("TrueImage", typeof (ImageSource), typeof (BoolToImageConverter), new UIPropertyMetadata ((ImageSource)new BitmapImage (new Uri ("pack://application:,,,/BoolToImageConverterTestApp;component/green_led.png", UriKind.RelativeOrAbsolute))));
public static readonly DependencyProperty FalseImageProperty = DependencyProperty.Register ("FalseImage", typeof (ImageSource), typeof (BoolToImageConverter), new UIPropertyMetadata ((ImageSource)new BitmapImage (new Uri ("pack://application:,,,/BoolToImageConverterTestApp;component/gray_led.png", UriKind.RelativeOrAbsolute))));
public ImageSource TrueImage
{
get { return (ImageSource)GetValue (TrueImageProperty); }
set { SetValue (TrueImageProperty, value); }
}
public ImageSource FalseImage
{
get { return (ImageSource)GetValue (FalseImageProperty); }
set { SetValue (FalseImageProperty, value); }
}
private const string Invert = "Invert";
public object Convert (object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ( targetType != typeof (ImageSource) )
throw new InvalidOperationException ("The target must be a ImageSource");
if ( (value == null) || (value == DependencyProperty.UnsetValue) )
{
if ( FalseImage != null )
return FalseImage;
else
return DependencyProperty.UnsetValue;
}
bool? bValue = (bool?)value;
if ( (parameter != null) && ((parameter as string) == Invert) )
bValue = !bValue;
if ( bValue.Value )
{
if ( TrueImage != null )
return this.TrueImage;
}
else
{
if ( FalseImage != null )
return this.FalseImage;
}
return DependencyProperty.UnsetValue;
}
public object ConvertBack (object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ("BoolToImageConverter ConvertBack not implemented - use OneWay binding");
}
}
}
测试应用 XAML:
<Window x:Class="BoolToImageConverterTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BoolToImageConverterTestApp"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:BoolToImageConverter x:Key="RollFeedImageConverter" TrueImage="roll_feed_closed.png" FalseImage="roll_feed_opened.png"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image x:Name="TestImage" Grid.Row="0" Source="{Binding Path=SomeBoolValue, Converter={StaticResource RollFeedImageConverter}, Mode=OneWay}" Stretch="None"/>
<Button x:Name="TestButton" Grid.Row="1" Content="Toggle Image" Margin="20" Click="TestButton_Click"/>
</Grid>
测试应用程序代码隐藏:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;
using System.ComponentModel;
namespace BoolToImageConverterTestApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow ()
{
DataContext = this;
InitializeComponent ();
}
public bool SomeBoolValue
{
get { return _someBoolValue; }
set
{
if ( _someBoolValue != value )
{
_someBoolValue = value;
RaisePropertyChanged ("SomeBoolValue");
}
}
}
private bool _someBoolValue = false;
private void TestButton_Click (object sender, RoutedEventArgs e)
{
SomeBoolValue ^= true;
}
#region INotifyPropertyChanged implementation
/// <summary>
/// Raises the PropertyChange event for the property specified
/// </summary>
/// <param name="propertyName">Property name to update. Is case-sensitive.</param>
public virtual void RaisePropertyChanged (string propertyName)
{
OnPropertyChanged (propertyName);
}
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged (string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if ( handler != null )
{
var e = new PropertyChangedEventArgs (propertyName);
handler (this, e);
}
}
#endregion // INotifyPropertyChanged implementation
}
}
【问题讨论】:
-
您正在使用 roll_feed_closed.png 和 roll_feed_opened.png 覆盖 xaml 中的图像值。您需要在那里使用 pack 语法。只是一些友好的建议,但我会学习 MVVM 和正确的 WPF 数据绑定。您正在按照代码的结构方式陷入困境。更好的方法是使用触发器。
-
“包语法”部分不正确。 XAML 解析器将自动添加缺少的 Uri 组件。并且“转换器在运行时完美运行”。
-
我根本不会使用绑定转换器来执行此操作。您可能会更好地在 SomeBoolValue 上使用带有 DataTrigger 的 Image Style,并为 Source 属性使用 Setter。
-
同意你应该使用触发器,这里根本不需要转换器。
-
感谢 cmets。这只是问题的一个简单示例,或者更确切地说是我试图更好地理解的问题。我同意,如果这就是我想要完成的全部,那么带有一些触发器的风格会更直接。我实际上是在一个自定义控件上使用这个转换器,该控件已经具有与之关联的样式,以及它自己的 ImageSource 类型的 Image 属性。我使用转换器的正是这个属性。