XAML中的自定义WPF图像绑定

ac1kyiln  于 2023-08-07  发布在  其他
关注(0)|答案(1)|浏览(115)

我继承了一个WPF项目,它动态生成XAML,并将Image对象绑定到同样在代码中动态生成的位图。下面的示例代码展示了它的工作原理:

public class XamlImageStore
{
    /// <summary>
    /// Initializes a new <see cref="XamlImageStore"/> object.
    /// </summary>
    static XamlImageStore()
    {
        images = new Dictionary<string, BitmapSource>();
    }

    /// <summary>
    /// Images used in XAML.
    /// </summary>
    private static Dictionary<string, BitmapSource> images;

    internal static void AddImage(string imageID, BitmapSource image)
    {
        images[imageID] = image;
    }

    public static string GetImageId(DependencyObject obj)
    {
        return (string)obj.GetValue(ImageIdProperty);
    }

    public static void SetImageId(DependencyObject obj, string value)
    {
        obj.SetValue(ImageIdProperty, value);
    }

    public static readonly DependencyProperty ImageIdProperty =
        DependencyProperty.RegisterAttached("ImageId", typeof(string), typeof(XamlImageStore), new UIPropertyMetadata("0", ImageIdChanged));

    private static void ImageIdChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        Image target = obj as Image;
        if (target != null)
        {
            string imageID = e.NewValue.ToString();
            if (images.ContainsKey(imageID))
            {
                // Set the image source.
                target.Source = images[imageID];
            }
        }
    }
}

字符串
主应用程序窗口(应用程序命名空间和输出exe为DynamicXamlImage):

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    string customImageID = "ABCD";
    XamlImageStore.AddImage(customImageID, GetBitmap());

    MemoryStream ms = new MemoryStream();
    XmlTextWriter xamlWriter =  new XmlTextWriter(ms, Encoding.UTF8);

    xamlWriter.WriteStartElement("Canvas");
    xamlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/xps/2005/06");
    xamlWriter.WriteAttributeString("xmlns:local", "clr-namespace:DynamicXamlImage;assembly=DynamicXamlImage");

    xamlWriter.WriteStartElement("Image");
    xamlWriter.WriteAttributeString("local:XamlImageStore.ImageId", customImageID);
    xamlWriter.WriteEndElement();

    xamlWriter.WriteEndElement();

    xamlWriter.Flush();
    ms.Position = 0;

    Canvas canvas = (Canvas)XamlReader.Load(ms);
    appGrid.Children.Add(canvas);
}

private WriteableBitmap GetBitmap() 
{
    WriteableBitmap wb = new WriteableBitmap(20, 20, 96, 96, PixelFormats.Gray8, null);
    byte[] pixels = new byte[] { 
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
        0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
    };
    wb.WritePixels(new Int32Rect(0, 0, 20, 20), pixels, 20, 0);

    return wb;
}


这是输出:

的数据
有人能解释一下这个绑定是如何工作的吗?因为我在这个方法上找不到任何东西。
我问的原因是我必须扩展XAML生成代码以支持动态生成的不透明度遮罩,并且我不知道如何使ImageBrush以相同的方式加载遮罩。

uplii1fm

uplii1fm1#

有人能解释一下这个绑定是怎么工作的吗?
不涉及数据绑定。
XamlImageStore由两个部分组成:

  • 一个将ID字符串Map到BitmapSource示例的字典
  • 一个名为ImageIdattached property,它具有一个PropertyChanged回调,该回调将来自Dictionary的BitmapSource分配给已设置附加属性的Image元素的Source属性。

在程式码范例中,会将从GetBitmap()方法传回的BitmapSource加入至Dictionary,并使用索引键"ABCD"。然后,在值为"ABCD"的Image元素上设置attached属性,这将导致Image的Source设置为以前创建的BitmapSource。
注意,XamlImageStore类的静态构造函数是多余的。你也可以写

private static readonly Dictionary<string, BitmapSource> images
    = new Dictionary<string, BitmapSource>();

字符串
PropertyChangedCallback也可以写得更有效率一些:

private static void ImageIdChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    if (obj is Image target)
    {
        string imageID = e.NewValue.ToString();

        if (images.TryGetValue(imageID, out BitmapSource bitmap))
        {
            target.Source = bitmap;
        }
    }
}


还要注意,拥有这个helper类的整个想法可能是多余的。您也可以使用XAML资源,例如就像这样:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    string customImageID = "ABCD";

    // *** see here ***
    Resources[customImageID] = GetBitmap();

    MemoryStream ms = new MemoryStream();
    XmlTextWriter xamlWriter = new XmlTextWriter(ms, Encoding.UTF8);

    xamlWriter.WriteStartElement("Canvas");
    xamlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/xps/2005/06");
    xamlWriter.WriteAttributeString("xmlns:local", "clr-namespace:DynamicXamlImage;assembly=DynamicXamlImage");

    xamlWriter.WriteStartElement("Image");

    // *** and here ***
    xamlWriter.WriteAttributeString("Source", $"{{DynamicResource {customImageID}}}");
    xamlWriter.WriteEndElement();

    xamlWriter.WriteEndElement();

    xamlWriter.Flush();
    ms.Position = 0;

    Canvas canvas = (Canvas)XamlReader.Load(ms);
    appGrid.Children.Add(canvas);
}

相关问题