0

如果列表中存在多个图像,我需要在 x 时间后更改鼠标悬停时的图像。

为了实现这一点,我开发了一个自定义图像控件,我的控件有两个属性,基本上 MainImageSource 是一个 BitmapImage 和 ImageUrl 这是一个 IList。

现在我在这里做的是 onmouseenter 启动一个计时器并MainImageSource在计时器结束并重置图像 onmouseleave 事件后更改到列表中的下一个图像(如果有的话)。

一切正常,就像我设置图像网址时它按预期设置图像一样。

现在我需要在 ListBox 中使用这个控件,它是数据绑定到 ObservableCollection 类型FileItem(自定义类)的数据。现在在列表框中,我需要设置该数组,所以我所做的是,在FileItem调用Imageurls类型中添加一个属性string[]。在 xaml 中,我使用以下内容进行数据绑定。

<local:MBImage ImageUrl="{Binding ImageUrls}"  Source="{Binding MainImageSource}" />

MBImage但从未设置过ImageUrl 。

所以现在有两件事

  1. 我怎样才能与ImageUrlsof绑定。FileItemImageUrlMBImage
  2. 我怎样才能摆脱Source="{Binding MainImageSource}"。因为它在内部使用MBImage。如果我不使用 MainImageSource 属性,即使我更新了 MBImage 也不会更改图像Source

除了一切之外,还有更好的方法来实现我的主要目标,即在悬停时显示多个图像。如果我找到比这更好的方法并且使用更多 WPF 的优势,我愿意重写所有内容。

已编辑

这是错误

'ImageUrls' property not found on 'object' ''MBImage' (Name='')'

这表明它在 MBImage 中寻找 ImageUrls 而不是 ObservableCollection 类型的列表框 itemsource。

MBImage.cs

class MBImage : Image, INotifyPropertyChanged
{
    private List<BitmapImage> bmpImages = new List<BitmapImage>();
    private Timer imgChangeTimer = new Timer(1000);
    private int curImage = 0;

    BitmapImage _MainImageSource = null;
    public event PropertyChangedEventHandler PropertyChanged;

    public static readonly DependencyProperty ImageUrlProperty = DependencyProperty.Register("ImageUrl", typeof(IList<string>), typeof(MBImage));

    public IList<string> ImageUrl
    {
        get { return (IList<string>)this.GetValue(ImageUrlProperty); }
        set
        {                
            this.SetValue(ImageUrlProperty, value);
            DownloadImages();
        }
    }

    public MBImage()
    {
        imgChangeTimer.Elapsed += new ElapsedEventHandler(imgChangeElapsed);
        DataContext = this;
    }

    public BitmapImage MainImageSource
    {
        get
        {
            return _MainImageSource;
        }
        set
        {
            _MainImageSource = value;
            OnPropertyChanged("MainImageSource");
        }
    }

    private void DownloadImages()
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += (s, e) =>
        {
            List<ImageDownloadArgs> argList = new List<ImageDownloadArgs>();

            int index = (int)e.Argument;
            int count = 1;
            if (index == -1)
            {
                count = ImageUrl.Count();
                index = 1;
            }

            for (int i = index; i < count; i++)
            {
                ImageDownloadArgs args = new ImageDownloadArgs();
                args.Index = i;


                Uri uri = new Uri(ImageUrl[i], UriKind.Absolute);

                using (WebClient webClient = new WebClient())
                {
                    webClient.Proxy = null;  
                    webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
                    try
                    {
                        byte[] imageBytes = null;

                        imageBytes = webClient.DownloadData(uri);

                        if (imageBytes == null)
                        {
                            e.Result = null;
                            return;
                        }
                        MemoryStream imageStream = new MemoryStream(imageBytes);
                        args.Img = new BitmapImage();

                        args.Img.BeginInit();
                        args.Img.StreamSource = imageStream;
                        args.Img.CacheOption = BitmapCacheOption.OnLoad;
                        args.Img.EndInit();

                        args.Img.Freeze();
                        imageStream.Close();

                        argList.Add(args);

                    }
                    catch (WebException)
                    {                
                        //argList.Add(args);
                    }
                }
            }
            e.Result = argList;
        };

        worker.RunWorkerCompleted += (s, e) =>
        {
            List<ImageDownloadArgs> argList = e.Result as List<ImageDownloadArgs>;
            bool shouldDownloadRest = false;
            foreach (ImageDownloadArgs args in argList)
            {
                if (args != null)
                {
                    if (args.Index == 0)
                    {
                        MainImageSource = args.Img;
                        bmpImages.Add(args.Img);
                        shouldDownloadRest = true;
                    }
                    else
                    {
                        bmpImages.Add(args.Img);
                    }
                }
            }

            worker.Dispose();
            if (shouldDownloadRest)
                worker.RunWorkerAsync(-1);

        };

        worker.RunWorkerAsync(0);

    }

    private void imgChangeElapsed(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("Time out");
        MainImageSource = bmpImages[++curImage % bmpImages.Count()];

    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
    {
        imgChangeTimer.Start();
    }

    protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
    {
        imgChangeTimer.Stop();
        MainImageSource = bmpImages[0];
        curImage = 0;

    }
}
4

1 回答 1

1

问题是你Setting the DataContext of MBImage to itself在它的构造函数DataContext = this;中,你不应该这样做。这就是当您这样做时它会自行搜索属性的原因ImageUrl="{Binding ImageUrls}"

删除DataContext = this;此行,因为它不是必需的。

我还看到你在属性设置器中做一些工作,这不会从 Xaml 绑定中调用,因为 wpf 内部调用 GetValue 和 SetValue 函数。如果你想对属性值集做一些事情,请在定义依赖属性元数据并在 valuechanged 处理程序中执行该工作

public static readonly DependencyProperty ImageUrlProperty = DependencyProperty.Register("ImageUrl", typeof(IList<string>), typeof(MBImage), new FrameworkPropertyMetadata(null, ImageUrlsChanged));
于 2013-09-26T04:02:02.780 回答