我們的需求是什麼? 答:需要在圖片上增加一些自定義標記,例如:2個圖片對比時,對相同區域進行高亮。 先上效果圖: 設計思路 1.概述 1.通過TargeUpdated事件,重新繪製圖片進行替換。 2.詳細實現 1.我們先綁定ImageTargetUpdated事件。 根據微軟官方文檔,如上圖,我們需 ...
我們的需求是什麼?
答:需要在圖片上增加一些自定義標記,例如:2個圖片對比時,對相同區域進行高亮。
先上效果圖:
設計思路
1.概述
1.通過TargeUpdated事件,重新繪製圖片進行替換。
2.詳細實現
1.我們先綁定ImageTargetUpdated事件。
<Image x:Name="DestImageControl" Source="{Binding Path=Source.Url, NotifyOnTargetUpdated=True}" TargetUpdated="ImageTargetUpdated">
根據微軟官方文檔,如上圖,我們需要設置NotifyOnRargetUpdated的值,官方文檔如下:
2.在響應方法中,對圖像進行繪製。
private void ImageTargetUpdated(object sender, DataTransferEventArgs e) { //todo:繪製圖像:drawingImage = DrawImage...... //設置新圖像:DestImageControl.SetCurrentValue(Image.SourceProperty, drawingImage); }
3.按照上面的思路,很完美,於是我們遇到了問題
什麼?有什麼問題?在直接讀取Image控制項的Source時,我們發現它是沒有值的,所以我們繪製的圖片底圖是沒有的。
下麵我們來分析一下:
由於Image控制項的Source我們是綁定的Url(類似:http://xxx.xxx.com/xxx.jpg),所以wpf會進行一步下載,通過調試,我們會發現它此時的類是LateBoundBitmapDecoder。
關於類LateBoundBitmapDecoder的官方文檔如下:
我們發現,這個類載入圖片是非同步的。所以我們在TargeUpdated事件中直接拿到的Source,此時僅僅是一個空對象,他的數據還在網路中傳輸。知道原理就好辦了。
我們對Source綁定下載完成事件!
if (((BitmapFrame)imageControl.Source).IsDownloading) { //如果是非同步下載,則綁定下載完成後事件 ((BitmapFrame)imageControl.Source).Decoder.DownloadCompleted += (sender2, e2) => { BitmapSource sourceImg = (BitmapSource)((LateBoundBitmapDecoder)sender2).Frames[0]; DrawImage(sourceImg); }; } else { //如果已存在圖片,則直接使用 BitmapSource sourceImg = (BitmapSource)imageControl.Source; DrawImage(sourceImg); }
再試運行一下,就和最前面的效果圖一致了。
總結
1.對於雙向綁定的Image控制項,我們在原圖上增加內容時,可以響應TargeUpdated事件進行自定義繪製。
2.在TargeUpdated事件響應中,有可能拿不到Source,此時,我們需要綁定下載完成事件,在事件中進行底圖的獲取。
3.我們需要使用SetCurrentValue方法對Source進行賦值,如此不會影響雙向綁定。
PS:
1.此文僅介紹遇到問題的解決思路及解決過程,並不分享源碼。