WPF 中图像控件的奇怪行为
我正在尝试在 C# 中开始使用 WPF。 我将一个 Canvas 设置为窗口的内容,然后创建另一个 Canvas 并将其作为第一个 Canvas 的子级(与其他元素一起,例如按钮和标签)。一切都运行良好,直到我创建一个 Image 对象并将其动态添加到内部画布:
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 是内部画布。图像的来源是一个PNG文件,从XML文件中提取(返回的字符串是正确的)。
奇怪的行为就在这里:如果我注释掉该行,则
double d = m_Img.Source.Width;
图像不再显示,尽管画布中的其他控件(例如标签和按钮)正确显示。
我不需要源图像的宽度,因此编译器告诉我从未使用该变量。
我将 Visual Studio 2010 更新到最新的 SP1,但该行为仍然存在。谷歌也没有帮助。我开始认为 Width 属性可能有一个 getter 方法,可以触发某些操作,但无法解决这个难题。
编辑:使用源的另一个属性(例如高度)会发生同样的事情。如果我访问至少一个属性,则图像显示正常。
I'm trying to get started with WPF in c#.
I set a Canvas as the content of a window, then I create another Canvas and put it as a child of the first Canvas (together with other elements, such as buttons and labels). Everything runs fine until I create an Image object and add it dynamically to the inner 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);
Here m_Img is the image I create, cvWindow is the inner Canvas. The source of the image is a PNG file, extracted from an XML file (the string returned is correct).
The odd behaviour is here: if I comment out the line
double d = m_Img.Source.Width;
the Image is not displayed anymore, although other controls in the Canvas (such as labels and buttons) are correctly displayed.
I don't need the width of the source image, so the compiler tells me that variable is never used.
I updated Visual Studio 2010 to the last SP1, but the behaviour remained. Google doesn't help either. I came to think that the Width property may have a getter method that triggers some action, but cannot solve the puzzle.
Edit: Same thing happens using another property of Source (e.g. Height). If I access at least one property, the image displays ok.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我终于发现发生了什么:Image 控件需要将 Source 的属性 DecodePixelWidth 和 DecodePixelHeight 设置为正确的值。
一旦创建了源,就不会设置这些值,并且不会绘制图像。首次访问用作源的 BitmapImage 的任何属性时,图像实际上被解码,并且这些属性被设置为解码图像的最终宽度和高度(以便可以绘制图像)。
我可以通过像这样手动设置这些值(强制转换为 int)来解决这个问题
,但我想我会重新设计我的视图,更好地分离(XAML 中的视图、模型和视图模型通过代码)。
http://msdn.microsoft.com 的第二个注释中也提到了这一点/en-us/library/ms747027.aspx
I finally discovered what happens: the Image control needs that the properties DecodePixelWidth and DecodePixelHeight of the Source are set to the correct values.
Once the Source is created, those values are not set, and the Image is not drawn. Upon first access to any property of the BitmapImage that serves as source the image is actually decoded and those properties are set to the final width and height of the decoded image (so the Image can be drawn).
I can solve this by setting those values by hand (with a cast to int) like this
but I think I will re-design my views with a better separation (views in XAML, model and viewmodel via code).
This bit is also mentioned in the second note in http://msdn.microsoft.com/en-us/library/ms747027.aspx
不要通过代码定义视图 - 使用 XAML,
即使您尝试创建动态视图,使用 XAML 也更加干净
使用优秀的设计应用程序(例如 Blend),您会注意到您没有考虑到的事情。
您没有考虑到的一些事情是 .Width 不一定等于 .ActalWidth。
默认宽度通常是 double.NaN (这意味着自动宽度)。
使用绑定,将 A 的宽度绑定到 B 的宽度,使用边距、填充或值转换器将宽度 A 绑定到 B 的宽度 - const。
使用布局面板(例如 Grid、StackPanel、DockPanel)使多个控件的对齐变得简单(并且无需绑定)。
另外,最好使用标准命名约定(例如没有m_)。
Don't define your views via code - use XAML,
even if you are trying to creating dynamic views, using XAML is much more clean
and using a good designer app (e.g. Blend), you'll notice things that you didn't consider.
Some things that you didn't consider are that .Width is not necessary equal to .ActalWidth.
Default widths are usually double.NaN (which means auto-width).
Use bindings, bind width of A to width of B, use margin, padding or value converters to make width A binded to width of B - const.
Use layout panels (e.g. Grid, StackPanel, DockPanel) to make alignment of multiple controls simple (and binding free).
Also, prefer using standard naming conventions (e.g. no m_).