WPF中图像控件的奇怪行为

时间:2011-04-27 20:16:05

标签: c# image wpf-controls

我正在尝试在c#中开始使用WPF。 我将Canvas设置为窗口的内容,然后创建另一个Canvas并将其作为第一个Canvas的子项(与其他元素一起使用,例如按钮和标签)。一切都运行正常,直到我创建一个Image对象并将其动态添加到内部Canvas:

Image m_Img = new Image
{
    Name = "img1",
    Width = cvWindow.Width,
    Height = dUsefulHeight,
    Stretch = Stretch.Uniform
};

m_Img.Source = new BitmapImage(
    new Uri(xMap.SelectSingleNode("@image").FirstChild.Value,
        UriKind.RelativeOrAbsolute));

Canvas.SetLeft(m_Img, 0);
Canvas.SetTop(m_Img, 0);

double d = m_Img.Source.Width;

cvWindow.Children.Add(m_Img);

这里m_Img是我创建的图像,cvWindow是内部Canvas。图像源是一个PNG文件,从XML文件中提取(返回的字符串是正确的)。

奇怪的行为就在这里:如果我注释掉这行

double d = m_Img.Source.Width;

虽然正确显示了画布中的其他控件(例如标签和按钮),但不再显示图像。

我不需要源图像的宽度,因此编译器告诉我从不使用变量。

我将Visual Studio 2010更新到最后一个SP1,但行为仍然存在。谷歌也没有帮助。我开始认为Width属性可能有一个触发某些动作的getter方法,但无法解决这个难题。


编辑:使用Source的另一个属性(例如Height)也会发生同样的事情。如果我访问至少一个属性,则图像显示正常。

2 个答案:

答案 0 :(得分:1)

我终于发现了会发生什么:Image控件需要将Source的DecodePixelWidth和DecodePixelHeight属性设置为正确的值。

创建源后,不会设置这些值,也不会绘制图像。首次访问作为源的BitmapImage的任何属性时,图像实际上被解码,并且这些属性被设置为解码图像的最终宽度和高度(因此可以绘制图像)。

我可以通过手动设置这些值(使用强制转换为int)来解决这个问题,就像这样

BitmapImage bs1 = new BitmapImage();
bs1.BeginInit();
bs1.UriSource = new Uri(
    xMap.SelectSingleNode("@image").FirstChild.Value,
    UriKind.RelativeOrAbsolute);
bs1.EndInit();
bs1.DecodePixelHeight = (int)bs1.Height;
bs1.DecodePixelWidth = (int)bs1.Width;

m_Img.Source = bs1;

但我想我会通过更好的分离来重新设计我的观点(通过代码在XAML,模型和视图模型中查看)。

http://msdn.microsoft.com/en-us/library/ms747027.aspx

的第二个注释中也提到了这一位
  

当您指定具有宽度或高度的图像大小时,您还应将DecodePixelWidth或DecodePixelHeight设置为相同的相应大小。

答案 1 :(得分:0)

不要通过代码定义您的视图 - 使用XAML,
即使您正在尝试创建动态视图,使用XAML也要干净得多 并且使用一个好的设计师应用程序(例如Blend),你会注意到你没有考虑的事情。

你没有考虑的一些事情是.Width不一定等于.ActalWidth 默认宽度通常为double.NaN(表示自动宽度)。

使用绑定,将A的宽度绑定到B的宽度,使用边距,填充或值转换器使宽度A绑定到宽度为B - const。

使用布局面板(例如Grid,StackPanel,DockPanel)使多个控件的对齐变得简单(并且无绑定)。

此外,更喜欢使用standard naming conventions(例如,没有m _)。