.net WPF ImageSource 绑定与自定义转换器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3204883/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:30:51  来源:igfitidea点击:

WPF ImageSource binding with Custom converter

.netwpfimageconverterresourcedictionary

提问by Raffaeu

I have a simple template for a combobox structured in this way:

我有一个以这种方式构造的组合框的简单模板:

<ComboBox DockPanel.Dock="Left" MinWidth="100" MaxHeight="24"
          ItemsSource="{Binding Actions}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" Width="100" />
                <Image Source="{Binding Converter={StaticResource TypeConverter}}" />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

So, if I use this code, everything works:

因此,如果我使用此代码,一切正常:

<TextBlock Text="{Binding Name}" Width="100" />
<!--<Image Source="{Binding Converter={StaticResource TypeConverter}}" /> -->
<Image Source="{StaticResource SecurityImage}" />

But if I use the converter it doesn't work anymore. This is the converter, but I don't know how I can refer to the static resource from there ...

但是如果我使用转换器,它就不再工作了。这是转换器,但我不知道如何从那里引用静态资源...

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    var type = (Action)value;
    var img = new BitmapImage();
    switch (type.ActionType)
    {
        case ActionType.Security:
            img.UriSource = new Uri("StructureImage", UriKind.Relative);
            break;
        case ActionType.Structural:
            img.UriSource = new Uri("SecurityImage", UriKind.Relative);
            break;
    }

    return img;
}

回答by akjoshi

Try to use the Switch Converter written by Josh, should work for you:

尝试使用 Josh 编写的 Switch Converter,应该对你有用:

SwitchConverter –

开关转换器 –

A "switch statement" for XAML - http://josheinstein.com/blog/index.php/2010/06/switchconverter-a-switch-statement-for-xaml/

XAML 的“switch 语句” - http://josheinstein.com/blog/index.php/2010/06/switchconverter-a-switch-statement-for-xaml/

No need to write your converter, your code will look like this -

无需编写转换器,您的代码将如下所示 -

<Grid.Resources>  
    <e:SwitchConverter x:Key="ActionIcons">  
        <e:SwitchCase When="Security" Then="SecurithImage.png" />  
        <e:SwitchCase When="Structural" Then="StructureImage.png" />             
    </e:SwitchConverter>  
</Grid.Resources>  

<Image Source="{Binding Converter={StaticResource ActionIcons}}" />  

Update1:

更新1:

Here is code of SwitchConverter as Josh'ssite seems to be down -

这是 SwitchConverter 的代码,因为Josh 的网站似乎已关闭 -

/// <summary>
/// A converter that accepts <see cref="SwitchConverterCase"/>s and converts them to the 
/// Then property of the case.
/// </summary>
[ContentProperty("Cases")]
public class SwitchConverter : IValueConverter
{
    // Converter instances.
    List<SwitchConverterCase> _cases;

    #region Public Properties.
    /// <summary>
    /// Gets or sets an array of <see cref="SwitchConverterCase"/>s that this converter can use to produde values from.
    /// </summary>
    public List<SwitchConverterCase> Cases { get { return _cases; } set { _cases = value; } }
    #endregion
    #region Construction.
    /// <summary>
    /// Initializes a new instance of the <see cref="SwitchConverter"/> class.
    /// </summary>
    public SwitchConverter()
    {
        // Create the cases array.
        _cases = new List<SwitchConverterCase>();
    }
    #endregion

    /// <summary>
    /// Converts a value.
    /// </summary>
    /// <param name="value">The value produced by the binding source.</param>
    /// <param name="targetType">The type of the binding target property.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // This will be the results of the operation.
        object results = null;

        // I'm only willing to convert SwitchConverterCases in this converter and no nulls!
        if (value == null) throw new ArgumentNullException("value");

        // I need to find out if the case that matches this value actually exists in this converters cases collection.
        if (_cases != null && _cases.Count > 0)
            for (int i = 0; i < _cases.Count; i++)
            {
                // Get a reference to this case.
                SwitchConverterCase targetCase = _cases[i];

                // Check to see if the value is the cases When parameter.
                if (value == targetCase || value.ToString().ToUpper() == targetCase.When.ToString().ToUpper())
                {
                    // We've got what we want, the results can now be set to the Then property
                    // of the case we're on.
                    results = targetCase.Then;

                    // All done, get out of the loop.
                    break;
                }
            }

        // return the results.
        return results;
    }

    /// <summary>
    /// Converts a value.
    /// </summary>
    /// <param name="value">The value that is produced by the binding target.</param>
    /// <param name="targetType">The type to convert to.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

/// <summary>
/// Represents a case for a switch converter.
/// </summary>
[ContentProperty("Then")]
public class SwitchConverterCase
{
    // case instances.
    string _when;
    object _then;

    #region Public Properties.
    /// <summary>
    /// Gets or sets the condition of the case.
    /// </summary>
    public string When { get { return _when; } set { _when = value; } }
    /// <summary>
    /// Gets or sets the results of this case when run through a <see cref="SwitchConverter"/>
    /// </summary>
    public object Then { get { return _then; } set { _then = value; } }
    #endregion
    #region Construction.
    /// <summary>
    /// Switches the converter.
    /// </summary>
    public SwitchConverterCase()
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="SwitchConverterCase"/> class.
    /// </summary>
    /// <param name="when">The condition of the case.</param>
    /// <param name="then">The results of this case when run through a <see cref="SwitchConverter"/>.</param>
    public SwitchConverterCase(string when, object then)
    {
        // Hook up the instances.
        this._then = then;
        this._when = when;
    }
    #endregion

    /// <summary>
    /// Returns a <see cref="System.String"/> that represents this instance.
    /// </summary>
    /// <returns>
    /// A <see cref="System.String"/> that represents this instance.
    /// </returns>
    public override string ToString()
    {
        return string.Format("When={0}; Then={1}", When.ToString(), Then.ToString());
    }
}

Update2:

更新2:

Another SwitchConverterimplementation from Microsoft Reference Source.

另一个来自 Microsoft 参考源的SwitchConverter实现。

回答by Jakob Christensen

When using Image.UriSourceyou need to specify the relative file path to your images if the images have been added to your project and their "Build Action" has been set to "Resource". E.g. if you have put your images in a project folder in Visual Studio called "images", you can refer to the images in the following way:

使用时Image.UriSource,如果图像已添加到您的项目并且其“构建操作”已设置为“资源”,则需要指定图像的相对文件路径。例如,如果您将图像放在 Visual Studio 中名为“图像”的项目文件夹中,则可以通过以下方式引用图像:

img.UriSource = new Uri("/Images/StructureImage.png", UriKind.Relative);

If the images are not build as a resource, you have to use the full file path i.e.

如果图像不是作为资源构建的,则必须使用完整的文件路径,即

img.UriSource = new Uri("http://server/Images/StructureImage.png", UriKind.Absolute);


EDIT:

编辑:

If you put your images in your Application resourcedictionary, you can always access it in the following way:

如果你把你的图像放在你的应用程序资源字典中,你总是可以通过以下方式访问它:

Application.Current.Resources["StructureImage"];

If you put the resources somewhere else you may use a IMultiValueConverterinstead of IValueConverterfor your converter. Then your typeconverter would look something like the following:

如果您将资源放在其他地方,您可以使用 aIMultiValueConverter而不是IValueConverter您的转换器。那么您的类型转换器将如下所示:

class TestValueConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // Validation of parameters goes here...

        var type = (Action) values[0];
        var image1 = values[1];
        var image2 = values[2];

        if (type.ActionType == ActionType.Security)
        {
            return image1;
        }
        else
        {
            return image2;
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

and your XAML would look similar to this:

并且您的 XAML 将类似于以下内容:

    <Image>
        <Image.Source>
            <MultiBinding Converter="{StaticResource testValueConverter}">
                <Binding Path="Action" />
                <Binding Source="{StaticResource SecurityImage}" />
                <Binding Source="{StaticResource StructureImage}" />
            </MultiBinding>
        </Image.Source>
    </Image>

Finally, this would be how you'd define your resources:

最后,这将是您定义资源的方式:

<imaging:BitmapImage x:Key="StructureImage" UriSource="StructureImage.png" />
<imaging:BitmapImage x:Key="SecurityImage" UriSource="SecurityImage.png" />
<local:TestValueConverter x:Key="testValueConverter" />

The above code is untested!

以上代码未经测试!