Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Illustrated WPF phần 7 pdf
Nội dung xem thử
Mô tả chi tiết
CHAPTER 11 ■ RESOURCES
280
To set a DynamicResource in the code-behind, use the SetResourceReference method, as shown
in the following code. Like FindResource, SetResourceReference searches up the element tree to find the
resource with the given key. The SetResourceReference method takes two parameters:
• The first parameter is the name of the dependency property to which the resource
is to be assigned. You must use the name of the dependency property, and not the
name of the CLR wrapper property. So in this case, you must use
BackgroundProperty and not Background.
• The second parameter is the resource key.
btn2.SetResourceReference(BackgroundProperty, "gradBrush" );
↑ ↑
Dependency Resource Key
Property Name
To review, suppose you have the markup shown on the left of Figure 11-8. Then the following
code shows the three different forms for retrieving resources in C# code: first, the direct assignment,
second the FindResource method, and third, the SetResourceReference method for assigning a
DynamicResource. The first button uses the default Button properties, and the last three buttons set their
Background properties using the resource.
public Window1()
{ InitializeComponent();
sp.Resources.Add( "background", Brushes.Aqua );
btn2.Background = (Brush) sp.Resources["background"];
btn3.Background = (Brush) btn3.FindResource( "background" );
btn4.SetResourceReference( BackgroundProperty, "background" );
}
Figure 11-8 shows a screenshot of the results on the right.
Figure 11-8. The output and the XAML of the sample program
One last difference between StaticResources and DynamicResources is that StaticResources
don’t allow forward references in the XAML. This means that in the text of the XAML, a resource must be
defined before you can assign it to a property. DynamicResources don’t have this restriction.
CHAPTER 11 ■ RESOURCES
281
Assembly Resources
As I stated at the beginning of the chapter, assembly resources are digital objects, such as images, that
aren’t generated by the source code. You got a preview of using images as assembly resources in Chapter
6, when I covered the Image control. In this chapter, I’ll go into the subject in a bit more detail.
Assembly resources can be embedded in the executable, or you can supply them to the
executable as separate files, also called loose files. Figure 11-9 shows the two forms. In the drawing on the
left, the two JPG files are embedded in the executable. In the drawing on the right, the two JPG resources
are separate from the executable; one is in the same directory, and the other is in a subdirectory called
Images.
Figure 11-9. Assembly resources can be embedded in the executable or supplied as loose files at runtime.
To embed a resource in the executable, first add the resource to the Visual Studio project. The
easiest way to do this is by right-clicking the project name in the Solution Explorer, selecting the Add h
Existing Item... menu selection, and navigating to the item. Visual Studio then adds to the project the
item you selected.
Next you need to tell Visual Studio to embed the resource in the executable in the form that
WPF uses. You do this by setting the Build Action property in the Properties window. To show the
Properties window, right-click the resource name (which is now visible in the Solution Explorer), and
select the Properties menu item. In the Properties window, select Resource—not Embedded Resource—
for the Build Action.
■ Note Although it sounds like exactly what you want, make sure you don’t choose Embedded Resource. This
option stores the resource in a different part of the assembly that is used by the Windows Forms framework, but it
is much more difficult to access from WPF.
CHAPTER 11 ■ RESOURCES
282
For resources that you don’t want embedded in the executable, you don’t have to do anything
in Visual Studio as long as you deploy the resource files along with the executable and make sure they’re
located where your code thinks they are, which I’ll explain in the next several sections.
Visual Studio, however, can manage that process for you and save you trouble. To take
advantage of this, you need to add the resource to the project, as you did to embed the resource and
then set the Build Action property to Content. The Content setting tells Visual Studio not to embed the
resource. Finally, you need to set the Copy to Output Directory property to either “Copy always” or
“Copy if newer.”
Accessing Assembly Resources from the Code
Using assembly resources from XAML is easy—you just specify the name of the resource file as a string
and assign it to the property where you want to use it.
For example, the following line of markup hooks up the Balloons.jpg to the Source property of
the Image element:
<Image Source="Balloons.jpg"/>
Specifying locations in the code-behind is a bit uglier but not difficult. You do it using an object
of the Uri class. A Uri object represents a universal resource identifier, which specifies the location of a
resource. You can create either absolute Uris, which give the fully qualified location of a resource, or
relative Uris, which give the relative location.
For a relative Uri, the path is relative to one of two places. At compile time, the compiler looks
for the file using the path relative to the location of the project file, which has the .csproj extension. If it
finds it, the compiler embeds the resource into the executable and includes an encoding of the
resource’s path.
To retrieve the resource at runtime, the program does the following:
• It checks its executable file to see whether there is a resource with that encoded
path—if so, it uses that resource.
• If it doesn’t find the resource in the executable file, it checks the path relative to
the location of the executable file.
CHAPTER 11 ■ RESOURCES
283
The following lines of code show the two most common overloaded forms of the Uri
constructors. The constructor with a single string parameter assumes the string is an absolute path to
the resource. In the second form, the second parameter specifies whether the path is absolute or
relative. For an absolute path, you would use the UriKind.Absolute enum member.
Uri uri2 = new Uri( "C:/Pictures/HotAirBalloons.jpg" );
Uri uri1 = new Uri( "/DogInSnow.jpg", UriKind.Relative );
For example, the following code shows the use of Uris in the code-behind of a simple window
that contains two Images in a StackPanel named sp, which is declared in the markup:
Uri uri1 = new Uri( "/Balloons.jpg", UriKind.Relative );
Uri uri2 = new Uri( "C:/Pictures/DogInSnow.jpg" );
BitmapImage bi1 = new BitmapImage( uri1 );
Image balloons = new Image();
balloons.Source = bi1;
BitmapImage bi2 = new BitmapImage( uri2 );
Image dogInSnow = new Image();
dogInSnow.Source = bi2;
sp.Children.Add( balloons );
sp.Children.Add( dogInSnow );
CHAPTER 11 ■ RESOURCES
284
Pack URIs
The URI forms you saw in the previous section are shorthand of a form called a pack URI, which you
might sometimes see in programs that access resources from other assemblies and locations. Most of
the time, however, you won’t need more than you learned in the previous section.
From a practical standpoint, although the syntax of pack URIs is ugly, most of the time it’s
pretty boilerplate. Take, for example, the following two pack URI specifications. If you remove the first
22 characters of each, you’ll see the form we’ve been using throughout the book.
"pack://application:,,,/DogInSnow.jpg"
"pack://application:,,,/Images/CatsOnTheBed.jpg"
↑ ↑
Scheme and Authority Path
For example, the following code uses a pack URI to specify the source used for an Image. Just as
with the shorthand form, from the specification you can’t tell whether the JPG it references is embedded
in the executable or is a loose file.
public Window1()
{
InitializeComponent();
Uri uri = new Uri("pack://application:,,,/DogInSnow.jpg");
BitmapImage bi = new BitmapImage( uri );
Image dogInSnow = new Image();
dogInSnow.Source = bi;
sp.Children.Add( dogInSnow ); // Add to StackPanel, named "sp".
}