달력

5

« 2025/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2016. 12. 29. 21:21

C# Keywords - Types 프로그래밍/C#2016. 12. 29. 21:21


Types


https://msdn.microsoft.com/en-us/library/3ewxz6et.aspx






Value Types


https://msdn.microsoft.com/en-us/library/s1ax56ch.aspx




bool


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The bool keyword is an alias of System.Boolean. It is used to declare variables to store the Boolean values, true and false.

System_CAPS_ICON_note.jpg Note

If you require a Boolean variable that can also have a value of null, use bool?. For more information, see Nullable Types.

You can assign a Boolean value to a bool variable. You can also assign an expression that evaluates to bool to a bool variable.

    public class BoolTest
    {
        static void Main()
        {
            bool b = true;

            // WriteLine automatically converts the value of b to text.
            Console.WriteLine(b);

            int days = DateTime.Now.DayOfYear;


            // Assign the result of a boolean expression to b.
            b = (days % 2 == 0);

            // Branch depending on whether b is true or false.
            if (b)
            {
                Console.WriteLine("days is an even number");
            }
            else
            {
                Console.WriteLine("days is an odd number");
            }   
        }
    }
    /* Output:
      True
      days is an <even/odd> number
    */

The default value of a bool variable is false. The default value of a bool? variable is null.

In C++, a value of type bool can be converted to a value of type int; in other words, false is equivalent to zero and true is equivalent to nonzero values. In C#, there is no conversion between the bool type and other types. For example, the following if statement is invalid in C#:

            int x = 123;

            // if (x)   // Error: "Cannot implicitly convert type 'int' to 'bool'"
            {
                Console.Write("The value of x is nonzero.");
            }

To test a variable of the type int, you have to explicitly compare it to a value, such as zero, as follows:

            if (x != 0)   // The C# way
            {
                Console.Write("The value of x is nonzero.");
            }

In this example, you enter a character from the keyboard and the program checks if the input character is a letter. If it is a letter, it checks if it is lowercase or uppercase. These checks are performed with the IsLetter, and IsLower, both of which return the bool type:

    public class BoolKeyTest
    {
        static void Main()
        {
            Console.Write("Enter a character: ");
            char c = (char)Console.Read();
            if (Char.IsLetter(c))
            {
                if (Char.IsLower(c))
                {
                    Console.WriteLine("The character is lowercase.");
                }
                else
                {
                    Console.WriteLine("The character is uppercase.");
                }
            }
            else
            {
                Console.WriteLine("Not an alphabetic character.");
            }
        }
    }
    /* Sample Output:
        Enter a character: X
        The character is uppercase.
     
        Enter a character: x
        The character is lowercase.

        Enter a character: 2
        The character is not an alphabetic character.
     */





byte


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The byte keyword denotes an integral type that stores values as indicated in the following table.

TypeRangeSize.NET Framework type
byte0 to 255Unsigned 8-bit integerSystem.Byte

You can declare and initialize a byte variable like this example:

byte myByte = 255;  

In the preceding declaration, the integer literal 255 is implicitly converted from int to byte. If the integer literal exceeds the range of byte, a compilation error will occur.

There is a predefined implicit conversion from byte to shortushortintuintlongulongfloatdouble, or decimal.

You cannot implicitly convert non-literal numeric types of larger storage size to byte. For more information on the storage sizes of integral types, see Integral Types Table. Consider, for example, the following two byte variables x and y:

  
byte x = 10, y = 20;  

The following assignment statement will produce a compilation error, because the arithmetic expression on the right-hand side of the assignment operator evaluates to int by default.

// Error: conversion from int to byte:  
byte z = x + y;  

To fix this problem, use a cast:

// OK: explicit conversion:  
byte z = (byte)(x + y);  

It is possible though, to use the following statements where the destination variable has the same storage size or a larger storage size:

int x = 10, y = 20;  
int m = x + y;  
long n = x + y;  

Also, there is no implicit conversion from floating-point types to byte. For example, the following statement generates a compiler error unless an explicit cast is used:

// Error: no implicit conversion from double:  
byte x = 3.0;   
// OK: explicit conversion:  
byte y = (byte)3.0;  

When calling overloaded methods, a cast must be used. Consider, for example, the following overloaded methods that use byte and int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(byte b) {}  

Using the byte cast guarantees that the correct type is called, for example:

// Calling the method with the int parameter:  
SampleMethod(5);  
// Calling the method with the byte parameter:  
SampleMethod((byte)5);  

For information on arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information on implicit numeric conversion rules, see the Implicit Numeric Conversions Table.







char


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The char keyword is used to declare an instance of the System.Char structure that the .NET Framework uses to represent a Unicode character. The value of a Char object is a 16-bit numeric (ordinal) value.

Unicode characters are used to represent most of the written languages throughout the world.

TypeRangeSize.NET Framework type
charU+0000 to U+FFFFUnicode 16-bit characterSystem.Char

Constants of the char type can be written as character literals, hexadecimal escape sequence, or Unicode representation. You can also cast the integral character codes. In the following example four char variables are initialized with the same character X:

            char[] chars = new char[4];

            chars[0] = 'X';        // Character literal
            chars[1] = '\x0058';   // Hexadecimal
            chars[2] = (char)88;   // Cast from integral type
            chars[3] = '\u0058';   // Unicode

            foreach (char c in chars)
            {
                Console.Write(c + " ");
            }
            // Output: X X X X

char can be implicitly converted to ushortintuintlongulongfloatdouble, or decimal. However, there are no implicit conversions from other types to the char type.

The System.Char type provides several static methods for working with char values.







decimal


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The decimal keyword indicates a 128-bit data type. Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations. The approximate range and precision for the decimal type are shown in the following table.

TypeApproximate RangePrecision.NET Framework type
decimal(-7.9 x 1028 to 7.9 x 1028) / (100 to 28)28-29 significant digitsSystem.Decimal

If you want a numeric real literal to be treated as decimal, use the suffix m or M, for example:

  
decimal myMoney = 300.5m;  

Without the suffix m, the number is treated as a double and generates a compiler error.

The integral types are implicitly converted to decimal and the result evaluates to decimal. Therefore you can initialize a decimal variable using an integer literal, without the suffix, as follows:

  
decimal myMoney = 300;  

There is no implicit conversion between floating-point types and the decimal type; therefore, a cast must be used to convert between these two types. For example:

  
      decimal myMoney = 99.9m;  
double x = (double)myMoney;  
myMoney = (decimal)x;  

You can also mix decimal and numeric integral types in the same expression. However, mixing decimal and floating-point types without a cast causes a compilation error.

For more information about implicit numeric conversions, see Implicit Numeric Conversions Table.

For more information about explicit numeric conversions, see Explicit Numeric Conversions Table.

You can format the results by using the String.Format method, or through the Console.Write method, which calls String.Format(). The currency format is specified by using the standard currency format string "C" or "c," as shown in the second example later in this article. For more information about the String.Format method, see String.Format.

The following example causes a compiler error by trying to add double and decimal variables.

double dub = 9;  
// The following line causes an error that reads "Operator '+' cannot be applied to   
// operands of type 'double' and 'decimal'"  
Console.WriteLine(dec + dub);   
  
// You can fix the error by using explicit casting of either operand.  
Console.WriteLine(dec + (decimal)dub);  
Console.WriteLine((double)dec + dub);  
  

The result is the following error:

Operator '+' cannot be applied to operands of type 'double' and 'decimal'

In this example, a decimal and an int are mixed in the same expression. The result evaluates to the decimal type.

    public class TestDecimal
    {
        static void Main()
        {
            decimal d = 9.1m;
            int y = 3;
            Console.WriteLine(d + y);   // Result converted to decimal
        }
    }
    // Output: 12.1

In this example, the output is formatted by using the currency format string. Notice that x is rounded because the decimal places exceed $0.99. The variable y, which represents the maximum exact digits, is displayed exactly in the correct format.

    public class TestDecimalFormat
    {
        static void Main()
        {
            decimal x = 0.999m;
            decimal y = 9999999999999999999999999999m;
            Console.WriteLine("My amount = {0:C}", x);
            Console.WriteLine("Your amount = {0:C}", y);
        }
    }
    /* Output:
        My amount = $1.00
        Your amount = $9,999,999,999,999,999,999,999,999,999.00
    */





double


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The double keyword signifies a simple type that stores 64-bit floating-point values. The following table shows the precision and approximate range for the double type.

TypeApproximate rangePrecision.NET Framework type
double±5.0 × 10−324 to ±1.7 × 1030815-16 digitsSystem.Double

By default, a real numeric literal on the right side of the assignment operator is treated as double. However, if you want an integer number to be treated as double, use the suffix d or D, for example:

  
double x = 3D;  

You can mix numeric integral types and floating-point types in an expression. In this case, the integral types are converted to floating-point types. The evaluation of the expression is performed according to the following rules:

  • If one of the floating-point types is double, the expression evaluates to double, or bool in relational or Boolean expressions.

  • If there is no double type in the expression, it evaluates to float, or bool in relational or Boolean expressions.

A floating-point expression can contain the following sets of values:

  • Positive and negative zero.

  • Positive and negative infinity.

  • Not-a-Number value (NaN).

  • The finite set of nonzero values.

For more information about these values, see IEEE Standard for Binary Floating-Point Arithmetic, available on the IEEE Web site.

In the following example, an int, a short, a float, and a double are added together giving a double result.

    // Mixing types in expressions
    class MixedTypes
    {
        static void Main()
        {
            int x = 3;
            float y = 4.5f;
            short z = 5;
            double w = 1.7E+3;
            // Result of the 2nd argument is a double:
            Console.WriteLine("The sum is {0}", x + y + z + w);
        }
    }
    // Output: The sum is 1712.5





enum


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The enum keyword is used to declare an enumeration, a distinct type that consists of a set of named constants called the enumerator list.

Usually it is best to define an enum directly within a namespace so that all classes in the namespace can access it with equal convenience. However, an enum can also be nested within a class or struct.

By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. For example, in the following enumeration, Sat is 0Sun is 1Mon is 2, and so forth.

  
enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};  

Enumerators can use initializers to override the default values, as shown in the following example.

  
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};  

In this enumeration, the sequence of elements is forced to start from 1 instead of 0. However, including a constant that has the value of 0 is recommended. For more information, see Enumeration Types.

Every enumeration type has an underlying type, which can be any integral type except char. The default underlying type of enumeration elements is int. To declare an enum of another integral type, such as byte, use a colon after the identifier followed by the type, as shown in the following example.

  
enum Days : byte {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};  

The approved types for an enum are bytesbyteshortushortintuintlong, or ulong.

A variable of type Days can be assigned any value in the range of the underlying type; the values are not limited to the named constants.

The default value of an enum E is the value produced by the expression (E)0.

System_CAPS_ICON_note.jpg Note

An enumerator cannot contain white space in its name.

The underlying type specifies how much storage is allocated for each enumerator. However, an explicit cast is necessary to convert from enum type to an integral type. For example, the following statement assigns the enumerator Sun to a variable of the type int by using a cast to convert from enum to int.

  
int x = (int)Days.Sun;  

When you apply System.FlagsAttribute to an enumeration that contains elements that can be combined with a bitwise OR operation, the attribute affects the behavior of the enum when it is used with some tools. You can notice these changes when you use tools such as the Console class methods and the Expression Evaluator. (See the third example.)

Just as with any constant, all references to the individual values of an enum are converted to numeric literals at compile time. This can create potential versioning issues as described in Constants.

Assigning additional values to new versions of enums, or changing the values of the enum members in a new version, can cause problems for dependent source code. Enum values often are used in switch statements. If additional elements have been added to the enum type, the default section of the switch statement can be selected unexpectedly.

If other developers use your code, you should provide guidelines about how their code should react if new elements are added to any enum types.

In the following example, an enumeration, Days, is declared. Two enumerators are explicitly converted to integer and assigned to integer variables.

    public class EnumTest
    {
        enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

        static void Main()
        {
            int x = (int)Days.Sun;
            int y = (int)Days.Fri;
            Console.WriteLine("Sun = {0}", x);
            Console.WriteLine("Fri = {0}", y);
        }
    }
    /* Output:
       Sun = 0
       Fri = 5
    */

In the following example, the base-type option is used to declare an enum whose members are of type long. Notice that even though the underlying type of the enumeration is long, the enumeration members still must be explicitly converted to type long by using a cast.

    public class EnumTest2
    {
        enum Range : long { Max = 2147483648L, Min = 255L };
        static void Main()
        {
            long x = (long)Range.Max;
            long y = (long)Range.Min;
            Console.WriteLine("Max = {0}", x);
            Console.WriteLine("Min = {0}", y);
        }
    }
    /* Output:
       Max = 2147483648
       Min = 255
    */

The following code example illustrates the use and effect of the System.FlagsAttribute attribute on an enum declaration.

    // Add the attribute Flags or FlagsAttribute.
    [Flags]
    public enum CarOptions
    {
        // The flag for SunRoof is 0001.
        SunRoof = 0x01,
        // The flag for Spoiler is 0010.
        Spoiler = 0x02,
        // The flag for FogLights is 0100.
        FogLights = 0x04,
        // The flag for TintedWindows is 1000.
        TintedWindows = 0x08,
    }

    class FlagTest
    {
        static void Main()
        {
            // The bitwise OR of 0001 and 0100 is 0101.
            CarOptions options = CarOptions.SunRoof | CarOptions.FogLights;

            // Because the Flags attribute is specified, Console.WriteLine displays
            // the name of each enum element that corresponds to a flag that has
            // the value 1 in variable options.
            Console.WriteLine(options);
            // The integer value of 0101 is 5.
            Console.WriteLine((int)options);
        }
    }
    /* Output:
       SunRoof, FogLights
       5
    */

If you remove Flags, the example displays the following values:

5

5




float


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The float keyword signifies a simple type that stores 32-bit floating-point values. The following table shows the precision and approximate range for the float type.

TypeApproximate rangePrecision.NET Framework type
float-3.4 × 1038to +3.4 × 10387 digitsSystem.Single

By default, a real numeric literal on the right side of the assignment operator is treated as double. Therefore, to initialize a float variable, use the suffix f or F, as in the following example:

  
float x = 3.5F;  

If you do not use the suffix in the previous declaration, you will get a compilation error because you are trying to store a double value into a float variable.

You can mix numeric integral types and floating-point types in an expression. In this case, the integral types are converted to floating-point types. The evaluation of the expression is performed according to the following rules:

  • If one of the floating-point types is double, the expression evaluates to double or bool in relational or Boolean expressions.

  • If there is no double type in the expression, the expression evaluates to float or bool in relational or Boolean expressions.

A floating-point expression can contain the following sets of values:

  • Positive and negative zero

  • Positive and negative infinity

  • Not-a-Number value (NaN)

  • The finite set of nonzero values

For more information about these values, see IEEE Standard for Binary Floating-Point Arithmetic, available on the IEEE Web site.

In the following example, an int, a short, and a float are included in a mathematical expression giving a float result. (Remember that float is an alias for the System.Single type.) Notice that there is no double in the expression.

    class FloatTest 
    {
        static void Main() 
        {
            int x = 3;
            float y = 4.5f;
            short z = 5;
            var result = x * y / z;
            Console.WriteLine("The result is {0}", result);
            Type type = result.GetType();
            Console.WriteLine("result is of type {0}", type.ToString());
        }
    }
    /* Output: 
      The result is 2.7
      result is of type System.Single //'float' is alias for 'Single'
     */




int


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The int keyword denotes an integral type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework typeDefault Value
int-2,147,483,648 to 2,147,483,647Signed 32-bit integerSystem.Int320

You can declare and initialize a variable of the type int like this example:

  
int i = 123;  

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: intuintlongulong. In this example, it is of the type int.

There is a predefined implicit conversion from int to longfloatdouble, or decimal. For example:

// '123' is an int, so an implicit conversion takes place here:  
float f = 123;  

There is a predefined implicit conversion from sbytebyteshortushort, or char to int. For example, the following assignment statement will produce a compilation error without a cast:

long aLong = 22;  
int i1 = aLong;       // Error: no implicit conversion from long.  
int i2 = (int)aLong;  // OK: explicit conversion.  

Notice also that there is no implicit conversion from floating-point types to int. For example, the following statement generates a compiler error unless an explicit cast is used:

  
      int x = 3.0;         // Error: no implicit conversion from double.  
int y = (int)3.0;    // OK: explicit conversion.  

For more information on arithmetic expressions with mixed floating-point types and integral types, see float and double.




long


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The long keyword denotes an integral type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
long–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Signed 64-bit integerSystem.Int64

You can declare and initialize a long variable like this example:

  
long long1 = 4294967296;  

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: intuintlongulong. In the preceding example, it is of the type long because it exceeds the range of uint (see Integral Types Table for the storage sizes of integral types).

You can also use the suffix L with the long type like this:

  
long long2 = 4294967296L;  

When you use the suffix L, the type of the literal integer is determined to be either long or ulong according to its size. In the case it is long because it less than the range of ulong.

A common use of the suffix is with calling overloaded methods. Consider, for example, the following overloaded methods that use long and int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(long l) {}  

Using the suffix L guarantees that the correct type is called, for example:

SampleMethod(5);    // Calling the method with the int parameter  
SampleMethod(5L);   // Calling the method with the long parameter  

You can use the long type with other numeric integral types in the same expression, in which case the expression is evaluated as long (or bool in the case of relational or Boolean expressions). For example, the following expression evaluates as long:

898L + 88  

System_CAPS_ICON_note.jpg Note

You can also use the lowercase letter "l" as a suffix. However, this generates a compiler warning because the letter "l" is easily confused with the digit "1." Use "L" for clarity.

For information on arithmetic expressions with mixed floating-point types and integral types, see float and double.

There is a predefined implicit conversion from long to floatdouble, or decimal. Otherwise a cast must be used. For example, the following statement will produce a compilation error without an explicit cast:

int x = L;        // Error: no implicit conversion from long to int  
int x = (int)L;   // OK: explicit conversion to int  

There is a predefined implicit conversion from sbytebyteshortushortintuint, or char to long.

Notice also that there is no implicit conversion from floating-point types to long. For example, the following statement generates a compiler error unless an explicit cast is used:

  
      long x = 3.0;         // Error: no implicit conversion from double  
long y = (long)3.0;   // OK: explicit conversion  




sbyte


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The sbyte keyword indicates an integral type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
sbyte-128 to 127Signed 8-bit integerSystem.SByte

You can declare and initialize an sbyte variable in this manner:

  
sbyte sByte1 = 127;  

In the previous declaration, the integer literal 127 is implicitly converted from int to sbyte. If the integer literal exceeds the range of sbyte, a compilation error will occur.

A cast must be used when calling overloaded methods. Consider, for example, the following overloaded methods that use sbyteand int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(sbyte b) {}  

Using the sbyte cast guarantees that the correct type is called, for example:

// Calling the method with the int parameter:  
SampleMethod(5);  
// Calling the method with the sbyte parameter:  
SampleMethod((sbyte)5);  

There is a predefined implicit conversion from sbyte to shortintlongfloatdouble, or decimal.

You cannot implicitly convert nonliteral numeric types of larger storage size to sbyte (see Integral Types Table for the storage sizes of integral types). Consider, for example, the following two sbyte variables x and y:

  
sbyte x = 10, y = 20;  

The following assignment statement will produce a compilation error, because the arithmetic expression on the right side of the assignment operator evaluates to int by default.

  
sbyte z = x + y;   // Error: conversion from int to sbyte  

To fix this problem, cast the expression as in the following example:

  
sbyte z = (sbyte)(x + y);   // OK: explicit conversion  

It is possible though to use the following statements, where the destination variable has the same storage size or a larger storage size:

  
      sbyte x = 10, y = 20;  
int m = x + y;  
long n = x + y;  

Notice also that there is no implicit conversion from floating-point types to sbyte. For example, the following statement generates a compiler error unless an explicit cast is used:

  
      sbyte x = 3.0;         // Error: no implicit conversion from double  
sbyte y = (sbyte)3.0;  // OK: explicit conversion  

For information about arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information about implicit numeric conversion rules, see the Implicit Numeric Conversions Table.




short


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The short keyword denotes an integral data type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
short-32,768 to 32,767Signed 16-bit integerSystem.Int16

You can declare and initialize a short variable like this example:

  
short x = 32767;  

In the preceding declaration, the integer literal 32767 is implicitly converted from int to short. If the integer literal does not fit into a short storage location, a compilation error will occur.

A cast must be used when calling overloaded methods. Consider, for example, the following overloaded methods that use shortand int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(short s) {}  

Using the short cast guarantees that the correct type is called, for example:

SampleMethod(5);         // Calling the method with the int parameter  
SampleMethod((short)5);  // Calling the method with the short parameter  

There is a predefined implicit conversion from short to intlongfloatdouble, or decimal.

You cannot implicitly convert nonliteral numeric types of larger storage size to short (see Integral Types Table for the storage sizes of integral types). Consider, for example, the following two short variables x and y:

  
short x = 5, y = 12;  

The following assignment statement will produce a compilation error, because the arithmetic expression on the right-hand side of the assignment operator evaluates to int by default.

short   z = x + y; // Error: no conversion from int to short

To fix this problem, use a cast:

short   z = (  short  )(x + y); // OK: explicit conversion

It is possible though to use the following statements, where the destination variable has the same storage size or a larger storage size:

int m = x + y;  
long n = x + y;  

There is no implicit conversion from floating-point types to short. For example, the following statement generates a compiler error unless an explicit cast is used:

  
      short x = 3.0;          // Error: no implicit conversion from double  
short y = (short)3.0;   // OK: explicit conversion  

For information on arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information on implicit numeric conversion rules, see the Implicit Numeric Conversions Table.




struct


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

struct type is a value type that is typically used to encapsulate small groups of related variables, such as the coordinates of a rectangle or the characteristics of an item in an inventory. The following example shows a simple struct declaration:

public struct Book  
{  
    public decimal price;  
    public string title;  
    public string author;  
}  

Structs can also contain constructorsconstantsfieldsmethodspropertiesindexersoperatorsevents, and nested types, although if several such members are required, you should consider making your type a class instead.

For examples, see Using Structs.

Structs can implement an interface but they cannot inherit from another struct. For that reason, struct members cannot be declared as protected.

For more information, see Structs.

For examples and more information, see Using Structs.




uint


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The uint keyword signifies an integral type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
uint0 to 4,294,967,295Unsigned 32-bit integerSystem.UInt32

Note The uint type is not CLS-compliant. Use int whenever possible.

You can declare and initialize a variable of the type uint like this example:

  
uint myUint = 4294967290;  

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: intuintlongulong. In this example, it is uint:

  
uint uInt1 = 123;  

You can also use the suffix u or U, such as this:

  
uint uInt2 = 123U;  

When you use the suffix U or u, the type of the literal is determined to be either uint or ulong according to the numeric value of the literal. For example:

Console.WriteLine(44U.GetType());  
Console.WriteLine(323442434344U.GetType());  

This code displays System.UInt32, followed by System.UInt64 -- the underlying types for uint and ulong respectively -- because the second literal is too large to be stored by the uint type.

There is a predefined implicit conversion from uint to longulongfloatdouble, or decimal. For example:

float myFloat = 4294967290;   // OK: implicit conversion to float  

There is a predefined implicit conversion from byteushort, or char to uint. Otherwise you must use a cast. For example, the following assignment statement will produce a compilation error without a cast:

long aLong = 22;  
// Error -- no implicit conversion from long:  
uint uInt1 = aLong;   
// OK -- explicit conversion:  
uint uInt2 = (uint)aLong;  

Notice also that there is no implicit conversion from floating-point types to uint. For example, the following statement generates a compiler error unless an explicit cast is used:

// Error -- no implicit conversion from double:  
uint x = 3.0;  
// OK -- explicit conversion:  
uint y = (uint)3.0;   

For information about arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information about implicit numeric conversion rules, see the Implicit Numeric Conversions Table.




ulong


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The ulong keyword denotes an integral type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
ulong0 to 18,446,744,073,709,551,615Unsigned 64-bit integerSystem.UInt64

You can declare and initialize a ulong variable like this example:

  
ulong uLong = 9223372036854775808;  

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: intuintlongulong. In the example above, it is of the type ulong.

You can also use suffixes to specify the type of the literal according to the following rules:

  • If you use L or l, the type of the literal integer will be either long or ulong according to its size.

    System_CAPS_ICON_note.jpg Note

    You can use the lowercase letter "l" as a suffix. However, this generates a compiler warning because the letter "l" is easily confused with the digit "1." Use "L" for clarity.

  • If you use U or u, the type of the literal integer will be either uint or ulong according to its size.

  • If you use UL, ul, Ul, uL, LU, lu, Lu, or lU, the type of the literal integer will be ulong.

    For example, the output of the following three statements will be the system type UInt64, which corresponds to the alias ulong:

    Console.WriteLine(9223372036854775808L.GetType());  
    Console.WriteLine(123UL.GetType());  
    Console.WriteLine((123UL + 456).GetType());  
    
    

A common use of the suffix is with calling overloaded methods. Consider, for example, the following overloaded methods that use ulong and int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(ulong l) {}  

Using a suffix with the ulong parameter guarantees that the correct type is called, for example:

SampleMethod(5);    // Calling the method with the int parameter  
SampleMethod(5UL);  // Calling the method with the ulong parameter  

There is a predefined implicit conversion from ulong to floatdouble, or decimal.

There is no implicit conversion from ulong to any integral type. For example, the following statement will produce a compilation error without an explicit cast:

long long1 = UL;   // Error: no implicit conversion from ulong  

There is a predefined implicit conversion from byteushortuint, or char to ulong.

Also, there is no implicit conversion from floating-point types to ulong. For example, the following statement generates a compiler error unless an explicit cast is used:

// Error -- no implicit conversion from double:  
ulong x = 3.0;  
// OK -- explicit conversion:  
ulong y = (ulong)3.0;    

For information on arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information on implicit numeric conversion rules, see the Implicit Numeric Conversions Table.






ushort


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The ushort keyword indicates an integral data type that stores values according to the size and range shown in the following table.

TypeRangeSize.NET Framework type
ushort0 to 65,535Unsigned 16-bit integerSystem.UInt16

You can declare and initialize a ushort variable such as this example:

  
ushort myShort = 65535;  

In the previous declaration, the integer literal 65535 is implicitly converted from int to ushort. If the integer literal exceeds the range of ushort, a compilation error will occur.

A cast must be used when you call overloaded methods. Consider, for example, the following overloaded methods that use ushort and int parameters:

public static void SampleMethod(int i) {}  
public static void SampleMethod(ushort s) {}  

Using the ushort cast guarantees that the correct type is called, for example:

// Calls the method with the int parameter:  
SampleMethod(5);  
// Calls the method with the ushort parameter:  
SampleMethod((ushort)5);    

There is a predefined implicit conversion from ushort to intuintlongulongfloatdouble, or decimal.

There is a predefined implicit conversion from byte or char to ushort. Otherwise a cast must be used to perform an explicit conversion. Consider, for example, the following two ushort variables x and y:

  
ushort x = 5, y = 12;  

The following assignment statement will produce a compilation error, because the arithmetic expression on the right side of the assignment operator evaluates to int by default.

  
ushort z = x + y;   // Error: conversion from int to ushort  

To fix this problem, use a cast:

  
ushort z = (ushort)(x + y);   // OK: explicit conversion   

It is possible though to use the following statements, where the destination variable has the same storage size or a larger storage size:

int m = x + y;  
long n = x + y;  

Notice also that there is no implicit conversion from floating-point types to ushort. For example, the following statement generates a compiler error unless an explicit cast is used:

// Error -- no implicit conversion from double:  
ushort x = 3.0;   
// OK -- explicit conversion:  
ushort y = (ushort)3.0;  

For information about arithmetic expressions with mixed floating-point types and integral types, see float and double.

For more information about implicit numeric conversion rules, see the Implicit Numeric Conversions Table.







Reference Types


https://msdn.microsoft.com/en-us/library/490f96s2.aspx




class


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

Classes are declared using the keyword class, as shown in the following example:

  
      class TestClass  
{  
    // Methods, properties, fields, events, delegates   
    // and nested classes go here.  
}  

Only single inheritance is allowed in C#. In other words, a class can inherit implementation from one base class only. However, a class can implement more than one interface. The following table shows examples of class inheritance and interface implementation:

InheritanceExample
Noneclass ClassA { }
Singleclass DerivedClass: BaseClass { }
None, implements two interfacesclass ImplClass: IFace1, IFace2 { }
Single, implements one interfaceclass ImplDerivedClass: BaseClass, IFace1 { }

Classes that you declare directly within a namespace, not nested within other classes, can be either public or internal. Classes are internal by default.

Class members, including nested classes, can be publicprotected internalprotectedinternal, or private. Members are private by default.

For more information, see Access Modifiers.

You can declare generic classes that have type parameters. For more information, see Generic Classes.

A class can contain declarations of the following members:

The following example demonstrates declaring class fields, constructors, and methods. It also demonstrates object instantiation and printing instance data. In this example, two classes are declared, the Child class, which contains two private fields (name and age) and two public methods. The second class, StringTest, is used to contain Main.

    class Child
    {
        private int age;
        private string name;

        // Default constructor:
        public Child()
        {
            name = "N/A";
        }

        // Constructor:
        public Child(string name, int age)
        {
            this.name = name;
            this.age = age;
        }

        // Printing method:
        public void PrintChild()
        {
            Console.WriteLine("{0}, {1} years old.", name, age);
        }
    }

    class StringTest
    {
        static void Main()
        {
            // Create objects by using the new operator:
            Child child1 = new Child("Craig", 11);
            Child child2 = new Child("Sally", 10);

            // Create an object using the default constructor:
            Child child3 = new Child();

            // Display results:
            Console.Write("Child #1: ");
            child1.PrintChild();
            Console.Write("Child #2: ");
            child2.PrintChild();
            Console.Write("Child #3: ");
            child3.PrintChild();
        }
    }
    /* Output:
        Child #1: Craig, 11 years old.
        Child #2: Sally, 10 years old.
        Child #3: N/A, 0 years old.
    */

Notice, in the preceding example, that the private fields (name and age) can only be accessed through the public methods of the Child class. For example, you cannot print the child's name, from the Main method, using a statement like this:

Console.Write(child1.name);   // Error  

Accessing private members of Child from Main would only be possible if Main were a member of the class.

Types declared inside a class without an access modifier default to private, so the data members in this example would still be private if the keyword were removed.

Finally, notice that for the object created using the default constructor (child3), the age field was initialized to zero by default.






delegate


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The declaration of a delegate type is similar to a method signature. It has a return value and any number of parameters of any type:

public delegate void TestDelegate(string message);  
public delegate int TestDelegate(MyType m, long num);  

delegate is a reference type that can be used to encapsulate a named or an anonymous method. Delegates are similar to function pointers in C++; however, delegates are type-safe and secure. For applications of delegates, see Delegates and Generic Delegates.

Delegates are the basis for Events.

A delegate can be instantiated by associating it either with a named or anonymous method. For more information, see Named Methods and Anonymous Methods.

The delegate must be instantiated with a method or lambda expression that has a compatible return type and input parameters. For more information on the degree of variance that is allowed in the method signature, see Variance in Delegates. For use with anonymous methods, the delegate and the code to be associated with it are declared together. Both ways of instantiating delegates are discussed in this section.

    // Declare delegate -- defines required signature:
    delegate double MathAction(double num);

    class DelegateTest
    {
        // Regular method that matches signature:
        static double Double(double input)
        {
            return input * 2;
        }

        static void Main()
        {
            // Instantiate delegate with named method:
            MathAction ma = Double;

            // Invoke delegate ma:
            double multByTwo = ma(4.5);
            Console.WriteLine("multByTwo: {0}", multByTwo);

            // Instantiate delegate with anonymous method:
            MathAction ma2 = delegate(double input)
            {
                return input * input;
            };

            double square = ma2(5);
            Console.WriteLine("square: {0}", square);

            // Instantiate delegate with lambda expression
            MathAction ma3 = s => s * s * s;
            double cube = ma3(4.375);

            Console.WriteLine("cube: {0}", cube);
        }
        // Output:
        // multByTwo: 9
        // square: 25
        // cube: 83.740234375
    }




dynamic


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time. The dynamic type simplifies access to COM APIs such as the Office Automation APIs, and also to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM).

Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.

The following example contrasts a variable of type dynamic to a variable of type object. To verify the type of each variable at compile time, place the mouse pointer over dyn or obj in the WriteLine statements. IntelliSense shows dynamic for dyn and object for obj.

    class Program
    {
        static void Main(string[] args)
        {
            dynamic dyn = 1;
            object obj = 1;

            // Rest the mouse pointer over dyn and obj to see their
            // types at compile time.
            System.Console.WriteLine(dyn.GetType());
            System.Console.WriteLine(obj.GetType());
        }
    }

The WriteLine statements display the run-time types of dyn and obj. At that point, both have the same type, integer. The following output is produced:

System.Int32

System.Int32

To see the difference between dyn and obj at compile time, add the following two lines between the declarations and the WriteLine statements in the previous example.

dyn = dyn + 3;  
obj = obj + 3;  

A compiler error is reported for the attempted addition of an integer and an object in expression obj + 3. However, no error is reported for dyn + 3. The expression that contains dyn is not checked at compile time because the type of dyn is dynamic.

The dynamic keyword can appear directly or as a component of a constructed type in the following situations:

  • In declarations, as the type of a property, field, indexer, parameter, return value, local variable, or type constraint. The following class definition uses dynamic in several different declarations.

        class ExampleClass
        {
            // A dynamic field.
            static dynamic field;
    
            // A dynamic property.
            dynamic prop { get; set; }
    
            // A dynamic return type and a dynamic parameter type.
            public dynamic exampleMethod(dynamic d)
            {
                // A dynamic local variable.
                dynamic local = "Local variable";
                int two = 2;
    
                if (d is int)
                {
                    return local;
                }
                else
                {
                    return two;
                }
            }
        }
    

  • In explicit type conversions, as the target type of a conversion.

            static void convertToDynamic()
            {
                dynamic d;
                int i = 20;
                d = (dynamic)i;
                Console.WriteLine(d);
    
                string s = "Example string.";
                d = (dynamic)s;
                Console.WriteLine(d);
    
                DateTime dt = DateTime.Today;
                d = (dynamic)dt;
                Console.WriteLine(d);
    
            }
            // Results:
            // 20
            // Example string.
            // 2/17/2009 9:12:00 AM
    

  • In any context where types serve as values, such as on the right side of an is operator or an as operator, or as the argument to typeof as part of a constructed type. For example, dynamic can be used in the following expressions.

                int i = 8;
                dynamic d;
                // With the is operator.
                // The dynamic type behaves like object. The following
                // expression returns true unless someVar has the value null.
                if (someVar is dynamic) { }
    
                // With the as operator.
                d = i as dynamic;
    
                // With typeof, as part of a constructed type.
                Console.WriteLine(typeof(List<dynamic>));
    
                // The following statement causes a compiler error.
                //Console.WriteLine(typeof(dynamic));
    

The following example uses dynamic in several declarations. The Main method also contrasts compile-time type checking with run-time type checking.

using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // The following line causes a compiler error because exampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to exampleMethod
            // with two arguments does not produce an error at compile time.
            // However, itdoes cause a run-time error. 
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable



interface


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

An interface contains only the signatures of methodspropertiesevents or indexers. A class or struct that implements the interface must implement the members of the interface that are specified in the interface definition. In the following example, class ImplementationClass must implement a method named SampleMethod that has no parameters and returns void.

For more information and examples, see Interfaces.

    interface ISampleInterface
    {
        void SampleMethod();
    }

    class ImplementationClass : ISampleInterface
    {
        // Explicit interface member implementation: 
        void ISampleInterface.SampleMethod()
        {
            // Method implementation.
        }

        static void Main()
        {
            // Declare an interface instance.
            ISampleInterface obj = new ImplementationClass();

            // Call the member.
            obj.SampleMethod();
        }
    }

An interface can be a member of a namespace or a class and can contain signatures of the following members:

An interface can inherit from one or more base interfaces.

When a base type list contains a base class and interfaces, the base class must come first in the list.

A class that implements an interface can explicitly implement members of that interface. An explicitly implemented member cannot be accessed through a class instance, but only through an instance of the interface.

For more details and code examples on explicit interface implementation, see Explicit Interface Implementation.

The following example demonstrates interface implementation. In this example, the interface contains the property declaration and the class contains the implementation. Any instance of a class that implements IPoint has integer properties x and y.

    interface IPoint
    {
       // Property signatures:
       int x
       {
          get;
          set;
       }

       int y
       {
          get;
          set;
       }
    }

    class Point : IPoint
    {
       // Fields:
       private int _x;
       private int _y;

       // Constructor:
       public Point(int x, int y)
       {
          _x = x;
          _y = y;
       }

       // Property implementation:
       public int x
       {
          get
          {
             return _x;
          }

          set
          {
             _x = value;
          }
       }

       public int y
       {
          get
          {
             return _y;
          }
          set
          {
             _y = value;
          }
       }
    }

    class MainClass
    {
       static void PrintPoint(IPoint p)
       {
          Console.WriteLine("x={0}, y={1}", p.x, p.y);
       }

       static void Main()
       {
          Point p = new Point(2, 3);
          Console.Write("My Point: ");
          PrintPoint(p);
       }
    }
    // Output: My Point: x=2, y=3






object


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The object type is an alias for Object in the .NET Framework. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from Object. You can assign values of any type to variables of type object. When a variable of a value type is converted to object, it is said to be boxed. When a variable of type object is converted to a value type, it is said to be unboxed. For more information, see Boxing and Unboxing.

The following sample shows how variables of type object can accept values of any data type and how variables of type objectcan use methods on Object from the .NET Framework.

class ObjectTest
{
   public int i = 10;
}

class MainClass2
{
   static void Main()
   {
      object a;
      a = 1;   // an example of boxing
      Console.WriteLine(a);
      Console.WriteLine(a.GetType());
      Console.WriteLine(a.ToString());

      a = new ObjectTest();
      ObjectTest classRef;
      classRef = (ObjectTest)a;
      Console.WriteLine(classRef.i);
   }
}
/* Output
    1
    System.Int32
    1
 * 10
*/





string


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The string type represents a sequence of zero or more Unicode characters. string is an alias for String in the .NET Framework.

Although string is a reference type, the equality operators (== and !=) are defined to compare the values of string objects, not references. This makes testing for string equality more intuitive. For example:

  
      string a = "hello";  
string b = "h";  
// Append to contents of 'b'  
b += "ello";  
Console.WriteLine(a == b);  
Console.WriteLine((object)a == (object)b);  

This displays "True" and then "False" because the content of the strings are equivalent, but a and b do not refer to the same string instance.

The + operator concatenates strings:

  
string a = "good " + "morning";  

This creates a string object that contains "good morning".

Strings are immutable--the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to b. The string "h" is then eligible for garbage collection.

  
      string b = "h";  
b += "ello";  

The [] operator can be used for readonly access to individual characters of a string:

  
      string str = "test";  
char x = str[2];  // x = 's';  

String literals are of type string and can be written in two forms, quoted and @-quoted. Quoted string literals are enclosed in double quotation marks ("):

"good morning"  // a string literal  

String literals can contain any character literal. Escape sequences are included. The following example uses escape sequence \\for backslash, \u0066 for the letter f, and \n for newline.

  
      string a = "\\\u0066\n";  
Console.WriteLine(a);  

System_CAPS_ICON_note.jpg Note

The escape code \udddd (where dddd is a four-digit number) represents the Unicode character U+dddd. Eight-digit Unicode escape codes are also recognized: \Udddddddd.

Verbatim string literals start with @ and are also enclosed in double quotation marks. For example:

@"good morning"  // a string literal  

The advantage of verbatim strings is that escape sequences are not processed, which makes it easy to write, for example, a fully qualified file name:

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"  

To include a double quotation mark in an @-quoted string, double it:

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.  

Another use of the @ symbol is to use referenced (/reference) identifiers that are C# keywords.

For more information about strings in C#, see Strings.

    class SimpleStringTest 
    {
       static void Main()
       {
          string a = "\u0068ello ";
          string b = "world";
          Console.WriteLine( a + b );
          Console.WriteLine( a + b == "Hello World" ); // == performs a case-sensitive comparison
       }
    }
    /* Output:
        hello world
        False
     */





Interpolated Strings


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

Used to construct strings. An interpolated string expression looks like a template string that contains expressions. An interpolated string expression creates a string by replacing the contained expressions with the ToString represenations of the expressions’ results. An interpolated string is easier to understand with respect to arguments than Composite Formatting. Here is an example of an interpolated string:

Console.WriteLine($"Name = {name}, hours = {hours:hh}")  

The structure of an interpolated string is as follows:

$ " <text> { <interpolation-expression> <optional-comma-field-width> <optional-colon-format> } <text> ... } "  

You can use an interpolated string anywhere you can use a string literal. When running your program would execute the code with the interpolated string literal, the code computes a new string literal by evaluating the interpolation expressions. This computation occurs each time the code with the interpolated string executes.

To include a curly brace ("{" or "}") in an interpolated string use two curly braces, "{{" or "}}". See the Implicit Conversions section for more details.

There are implicit type conversions from an interpolated string:

var s = $"hello, {name}"  
System.IFormattable s = $"Hello, {name}"  
System.FormattableString s = $"Hello, {name}"  
  

The first example produces a string value where all the string interpolation values have been computed. It is the final result and has type string. All occurrences of double curly braces (“{{“ and “}}”) are converted to a single curly brace.

The second example produces an IFormattable variable that allows you to convert the string with invariant context. This is useful for getting numeric and data formats correct in different languages. All occurrences of double curly braces (“{{“ and “}}”) remain as double curly braces, until you format the string with ToString. All contained interpolation expressions are converted to {0}, {1}, and so on.

s.ToString(null, System.Globalization.CultureInfo.InvariantCulture);  

The third example produces a FormattableString, which allows you to inspect the objects that result from the interpolation computations. Inspecting objects and how they render as strings might, for example, help you protect against an injection attack if you were building a query. With FormattableString, you have convenience operations to produce the InvariantCulture and CurrentCulture string results. All occurrences of double curly braces (“{{“ and “}}”) remain as double curly braces, until you format. All contained interpolation expressions are converted to {0}, {1}, and so on.

$"Name = {name}, hours = {hours:hh}"  
var s = $"hello, {name}"  
System.IFormattable s = $"Hello, {name}"  
System.FormattableString s = $"Hello, {name}"  
$"{person.Name, 20} is {person.Age:D3} year {(p.Age == 1 ? "" : "s")} old."  
  

You do not need to quote the quotation characters within the contained interpolation expressions because interpolated string expressions start with $, and the compiler scans the contained interpolation expressions as balanced text until it finds a comma, colon, or close curly brace. For the same reasons, the last example uses parentheses to allow the conditional expression (p.Age == 1 ? "" : "s") to be inside the interpolation expression without the colon starting a format specification. Outside of the contained interpolation expression (but still within the interpolated string expression) you escape quotation characters as you normally would.

expression:  
    interpolated-string-expression  
  
interpolated-string-expression:  
    interpolated-string-start interpolations interpolated-string-end  
  
interpolations:  
    single-interpolation  
    single-interpolation interpolated-string-mid interpolations  
  
single-interpolation:  
    interpolation-start  
    interpolation-start : regular-string-literal  
  
interpolation-start:  
    expression  
    expression , expression  





void


https://msdn.microsoft.com/en-us/library/yah0tteb.aspx


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

When used as the return type for a method, void specifies that the method doesn't return a value.

void isn't allowed in the parameter list of a method. A method that takes no parameters and returns no value is declared as follows:

public void SampleMethod()  
{  
    // Body of the method.  
}  
  

void is also used in an unsafe context to declare a pointer to an unknown type. For more information, see Pointer types.

void is an alias for the .NET Framework System.Void type.






var


https://msdn.microsoft.com/en-us/library/bb383973.aspx


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit type var. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of i are functionally equivalent:

var i = 10; // implicitly typed  
int i = 10; //explicitly typed  

For more information, see Implicitly Typed Local Variables and Type Relationships in LINQ Query Operations.

The following example shows two query expressions. In the first expression, the use of var is permitted but is not required, because the type of the query result can be stated explicitly as an IEnumerable<string>. However, in the second expression, varmust be used because the result is a collection of anonymous types, and the name of that type is not accessible except to the compiler itself. Note that in Example #2, the foreach iteration variable item must also be implicitly typed.

            // Example #1: var is optional because
            // the select clause specifies a string
            string[] words = { "apple", "strawberry", "grape", "peach", "banana" };
            var wordQuery = from word in words
                            where word[0] == 'g'
                            select word;

            // Because each element in the sequence is a string, 
            // not an anonymous type, var is optional here also.
            foreach (string s in wordQuery)
            {
                Console.WriteLine(s);
            }

            // Example #2: var is required because
            // the select clause specifies an anonymous type
            var custQuery = from cust in customers
                            where cust.City == "Phoenix"
                            select new { cust.Name, cust.Phone };

            // var must be used because each item 
            // in the sequence is an anonymous type
            foreach (var item in custQuery)
            {
                Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
            }





Reference Tables for Types


https://msdn.microsoft.com/en-us/library/ya5y69ds.aspx





Built-In Types Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table shows the keywords for built-in C# types, which are aliases of predefined types in the System namespace.

C# Type.NET Framework Type
boolSystem.Boolean
byteSystem.Byte
sbyteSystem.SByte
charSystem.Char
decimalSystem.Decimal
doubleSystem.Double
floatSystem.Single
intSystem.Int32
uintSystem.UInt32
longSystem.Int64
ulongSystem.UInt64
objectSystem.Object
shortSystem.Int16
ushortSystem.UInt16
stringSystem.String

All of the types in the table, except object and string, are referred to as simple types.

The C# type keywords and their aliases are interchangeable. For example, you can declare an integer variable by using either of the following declarations:

int x = 123;  
System.Int32 x = 123;  

To display the actual type for any C# type, use the system method GetType(). For example, the following statement displays the system alias that represents the type of myVariable:

Console.WriteLine(myVariable.GetType());  

You can also use the typeof operator.




Integral Types Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table shows the sizes and ranges of the integral types, which constitute a subset of simple types.

TypeRangeSize
sbyte-128 to 127Signed 8-bit integer
byte0 to 255Unsigned 8-bit integer
charU+0000 to U+ffffUnicode 16-bit character
short-32,768 to 32,767Signed 16-bit integer
ushort0 to 65,535Unsigned 16-bit integer
int-2,147,483,648 to 2,147,483,647Signed 32-bit integer
uint0 to 4,294,967,295Unsigned 32-bit integer
long-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Signed 64-bit integer
ulong0 to 18,446,744,073,709,551,615Unsigned 64-bit integer

If the value represented by an integer literal exceeds the range of ulong, a compilation error will occur.




Floating-Point Types Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table shows the precision and approximate ranges for the floating-point types.

TypeApproximate rangePrecision
float±1.5e−45 to ±3.4e387 digits
double±5.0e−324 to ±1.7e30815-16 digits




Default Values Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table shows the default values of value types returned by the default constructors. Default constructors are invoked by using the new operator, as follows:

int myInt = new int();  

The preceding statement has the same effect as the following statement:

int myInt = 0;  

Remember that using uninitialized variables in C# is not allowed.

Value typeDefault value
boolfalse
byte0
char'\0'
decimal0.0M
double0.0D
enumThe value produced by the expression (E)0, where E is the enum identifier.
float0.0F
int0
long0L
sbyte0
short0
structThe value produced by setting all value-type fields to their default values and all reference-type fields to null.
uint0
ulong0
ushort0




Value Types Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table lists the C# value types by category.

Value typeCategoryType Suffix
boolBoolean
byteUnsigned, numeric, integral
charUnsigned, numeric, integral
decimalNumeric, decimalM or m
doubleNumeric, floating-pointD or d
enumEnumeration
floatNumeric, floating-pointF or f
intSigned, numeric, integral
longSigned, numeric, integralL or l
sbyteSigned, numeric, integral
shortSigned, numeric, integral
structUser-defined structure
uintUnsigned, numeric, integralU or u
ulongUnsigned, numeric, integralUL or ul
ushortUnsigned, numeric, integral




Implicit Numeric Conversions Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

The following table shows the predefined implicit numeric conversions. Implicit conversions might occur in many situations, including method invoking and assignment statements.

FromTo
sbyteshortintlongfloatdouble, or decimal
byteshortushortintuintlongulongfloatdouble, or decimal
shortintlongfloatdouble, or decimal
ushortintuintlongulongfloatdouble, or decimal
intlongfloatdouble, or decimal
uintlongulongfloatdouble, or decimal
longfloatdouble, or decimal
charushortintuintlongulongfloatdouble, or decimal
floatdouble
ulongfloatdouble, or decimal
  • Precision but not magnitude might be lost in the conversions from intuintlong, or ulong to float and from long or ulong to double.

  • There are no implicit conversions to the char type.

  • There are no implicit conversions between floating-point types and the decimal type.

  • A constant expression of type int can be converted to sbytebyteshortushortuint, or ulong, provided the value of the constant expression is within the range of the destination type.





Explicit Numeric Conversions Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

Explicit numeric conversion is used to convert any numeric type to any other numeric type, for which there is no implicit conversion, by using a cast expression. The following table shows these conversions.

For more information about conversions, see Casting and Type Conversions.

FromTo
sbytebyteushortuintulong, or char
byteSbyte or char
shortsbytebyteushortuintulong, or char
ushortsbytebyteshort, or char
intsbytebyteshortushortuintulong,or char
uintsbytebyteshortushortint, or char
longsbytebyteshortushortintuintulong, or char
ulongsbytebyteshortushortintuintlong, or char
charsbytebyte, or short
floatsbytebyteshortushortintuintlongulongchar,or decimal
doublesbytebyteshortushortintuintlongulongcharfloat,or decimal
decimalsbytebyteshortushortintuintlongulongcharfloat, or double
  • The explicit numeric conversion may cause loss of precision or result in throwing exceptions.

  • When you convert a decimal value to an integral type, this value is rounded towards zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, an OverflowException is thrown.

  • When you convert from a double or float value to an integral type, the value is truncated. If the resulting integral value is outside the range of the destination value, the result depends on the overflow checking context. In a checked context, an OverflowException is thrown, while in an unchecked context, the result is an unspecified value of the destination type.

  • When you convert double to float, the double value is rounded to the nearest float value. If the double value is too small or too large to fit into the destination type, the result will be zero or infinity.

  • When you convert float or double to decimal, the source value is converted to decimal representation and rounded to the nearest number after the 28th decimal place if required. Depending on the value of the source value, one of the following results may occur:

    • If the source value is too small to be represented as a decimal, the result becomes zero.

    • If the source value is NaN (not a number), infinity, or too large to be represented as a decimal, an OverflowException is thrown.

  • When you convert decimal to float or double, the decimal value is rounded to the nearest double or float value.

For more information on explicit conversion, see Explicit in the C# Language Specification. For more information on how to access the spec, see C# Language Specification.






Formatting Numeric Results Table


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017 RC, see Visual Studio 2017 RC Documentation.

You can format numeric results by using the String.Format method, or through the Console.Write or Console.WriteLine method, which calls String.Format. The format is specified by using format strings. The following table contains the supported standard format strings. The format string takes the following form: Axx, where A is the format specifier and xx is the precision specifier. The format specifier controls the type of formatting applied to the numeric value, and the precision specifier controls the number of significant digits or decimal places of the formatted output. The value of the precision specifier ranges from 0 to 99.

For more information about standard and custom formatting strings, see Formatting Types. For more information about the String.Format method, see String.Format.

Format SpecifierDescriptionExamplesOutput
C or cCurrencyConsole.Write("{0:C}", 2.5);

Console.Write("{0:C}", -2.5);
$2.50

($2.50)
D or dDecimalConsole.Write("{0:D5}", 25);00025
E or eScientificConsole.Write("{0:E}", 250000);2.500000E+005
F or fFixed-pointConsole.Write("{0:F2}", 25);

Console.Write("{0:F0}", 25);
25.00

25
G or gGeneralConsole.Write("{0:G}", 2.5);2.5
N or nNumberConsole.Write("{0:N}", 2500000);2,500,000.00
X or xHexadecimalConsole.Write("{0:X}", 250);

Console.Write("{0:X}", 0xffff);
FA

FFFF












'프로그래밍 > C#' 카테고리의 다른 글

Getting Started with C#  (0) 2017.02.13
클래스 종류 헤드라인  (0) 2017.01.04
helpful classes  (0) 2016.11.24
Operators  (0) 2016.11.14
IEnumerable Interface  (0) 2016.11.14
:
Posted by 지훈2
2016. 11. 24. 02:29

helpful classes 프로그래밍/C#2016. 11. 24. 02:29


  1. Dispatcher Class
  2. Thread Class
  3. ThreadPool Class
  4. WebClient Class
  5. GC Class




Dispatcher Class


https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher(v=vs.110).aspx


Provides services for managing the queue of work items for a thread.

Namespace:   System.Windows.Threading
Assembly:  WindowsBase (in WindowsBase.dll)

Inheritance Hierarchy

System.Object
  System.Windows.Threading.Dispatcher


Remarks

The Dispatcher maintains a prioritized queue of work items for a specific thread.

When a Dispatcher is created on a thread, it becomes the only Dispatcher that can be associated with the thread, even if the Dispatcher is shut down.

If you attempt to get the CurrentDispatcher for the current thread and a Dispatcher is not associated with the thread, a Dispatcher will be created. A Dispatcher is also created when you create a DispatcherObject. If you create a Dispatcher on a background thread, be sure to shut down the dispatcher before exiting the thread.

If a Dispatcher is shut down, it cannot be restarted.

In WPF, a DispatcherObject can only be accessed by the Dispatcher it is associated with.  For example, a background thread cannot update the contents of a Button that is associated with the Dispatcher on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvokeInvoke is synchronous and BeginInvoke is asynchronous. The operation is added to the queue of the Dispatcher at the specified DispatcherPriority.

If BeginInvoke is called on a Dispatcher that has shut down, the status property of the returned DispatcherOperation is set to Aborted.

All of the methods on Dispatcher, with the exception of DisableProcessing, are free-threaded.

Objects that derive from DispatcherObject have thread affinity.

Objects that derive from Freezable are free-threaded when they are frozen. For more information, see Freezable Objects Overview.

Examples

The following example shows how to place an operation onto a Dispatcher. For the full source code of this example, see Single-Threaded Application with Long-Running Calculation Sample.

First, a delegate is created that accepts no arguments.

public delegate void NextPrimeDelegate();

Next, BeginInvoke(DispatcherPriority, Delegate) is called. This call to BeginInvoke(DispatcherPriority, Delegate) takes two parameters: the priority, which is set to DispatcherPriority.Normal, and the callback, which is passed in through an instance of the delegate NextPrimeDelegate.

startStopButton.Dispatcher.BeginInvoke(
    DispatcherPriority.Normal,
    new NextPrimeDelegate(CheckNextNumber));






Thread Class


https://msdn.microsoft.com/en-us/library/system.threading.thread(v=vs.110).aspx


Creates and controls a thread, sets its priority, and gets its status.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)


Remarks

When a process starts, the common language runtime automatically creates a single foreground thread to execute application code. Along with this main foreground thread, a process can create one or more threads to execute a portion of the program code associated with the process. These threads can execute either in the foreground or in the background. In addition, you can use the ThreadPool class to execute code on worker threads that are managed by the common language runtime.

In this section

Starting a thread
Retrieving Thread objects
Foreground and background threads
Culture and threads
Getting information about and controlling threads
Accessing the source code for the Thread class

Starting a thread

You start a thread by supplying a delegate that represents the method the thread is to execute in its class constructor. You then call the Startmethod to begin execution.

The Thread constructors can take either of two delegate types, depending on whether you can pass an argument to the method to be executed:

  • If the method has no arguments, you pass a ThreadStart delegate to the constructor. It has the signature:

    public delegate void ThreadStart()
    

    The following example creates and starts a thread that executes the ExecuteInForeground method. The method displays information about some thread properties, then executes a loop in which it pauses for half a second and displays the elapsed number of seconds. When the thread has executed for at least five seconds, the loop ends and the thread terminates execution.

    using System;
    using System.Diagnostics;
    using System.Threading;
    
    public class Example
    {
       public static void Main()
       {
          var th = new Thread(ExecuteInForeground);
          th.Start();
          Thread.Sleep(1000);
          Console.WriteLine("Main thread ({0}) exiting...", 
                            Thread.CurrentThread.ManagedThreadId); 
       }
    
       private static void ExecuteInForeground()
       {
          DateTime start = DateTime.Now;
          var sw = Stopwatch.StartNew();
          Console.WriteLine("Thread {0}: {1}, Priority {2}", 
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority);
          do { 
             Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds", 
                               Thread.CurrentThread.ManagedThreadId,
                               sw.ElapsedMilliseconds / 1000.0);
             Thread.Sleep(500);
          } while (sw.ElapsedMilliseconds <= 5000);
          sw.Stop(); 
       }
    }
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.51 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.02 seconds
    //       Thread 3: Elapsed 1.53 seconds
    //       Thread 3: Elapsed 2.05 seconds
    //       Thread 3: Elapsed 2.55 seconds
    //       Thread 3: Elapsed 3.07 seconds
    //       Thread 3: Elapsed 3.57 seconds
    //       Thread 3: Elapsed 4.07 seconds
    //       Thread 3: Elapsed 4.58 seconds
    
  • If the method has an argument, you pass a ParameterizedThreadStart delegate to the constructor. It has the signature:

    public delegate void ParameterizedThreadStart(object obj)
    

    The method executed by the delegate can then cast (in C#) or convert (in Visual Basic) the parameter to the appropriate type.

    The following example is identical to the previous one, except that it calls the Thread(ParameterizedThreadStart) constructor. This version of the ExecuteInForeground method has a single parameter that represents the approximate number of milliseconds the loop is to execute.

    using System;
    using System.Diagnostics;
    using System.Threading;
    
    public class Example
    {
       public static void Main()
       {
          var th = new Thread(ExecuteInForeground);
          th.Start(4500);
          Thread.Sleep(1000);
          Console.WriteLine("Main thread ({0}) exiting...", 
                            Thread.CurrentThread.ManagedThreadId); 
       }
    
       private static void ExecuteInForeground(Object obj)
       {
          int interval;
          try {
             interval = (int) obj;
          }
          catch (InvalidCastException) {
             interval = 5000;
          }
          DateTime start = DateTime.Now;
          var sw = Stopwatch.StartNew();
          Console.WriteLine("Thread {0}: {1}, Priority {2}", 
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority);
          do { 
             Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds", 
                               Thread.CurrentThread.ManagedThreadId,
                               sw.ElapsedMilliseconds / 1000.0);
             Thread.Sleep(500);
          } while (sw.ElapsedMilliseconds <= interval);
          sw.Stop(); 
       }
    }
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.52 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.03 seconds
    //       Thread 3: Elapsed 1.55 seconds
    //       Thread 3: Elapsed 2.06 seconds
    //       Thread 3: Elapsed 2.58 seconds
    //       Thread 3: Elapsed 3.09 seconds
    //       Thread 3: Elapsed 3.61 seconds
    //       Thread 3: Elapsed 4.12 seconds
    

It is not necessary to retain a reference to a Thread object once you have started the thread. The thread continues to execute until the thread procedure is complete.

Retrieving Thread objects

You can use the static (Shared in Visual Basic) CurrentThread property to retrieve a reference to the currently executing thread from the code that the thread is executing. The following example uses the CurrentThread property to display information about the main application thread, another foreground thread, a background thread, and a thread pool thread.

using System;
using System.Threading;

public class Example
{
   static Object obj = new Object();

   public static void Main()
   {
      ThreadPool.QueueUserWorkItem(ShowThreadInformation);
      var th1 = new Thread(ShowThreadInformation);
      th1.Start();
      var th2 = new Thread(ShowThreadInformation);
      th2.IsBackground = true;
      th2.Start();
      Thread.Sleep(500);
      ShowThreadInformation(null); 
   }

   private static void ShowThreadInformation(Object state)
   {
      lock (obj) {
         var th  = Thread.CurrentThread;
         Console.WriteLine("Managed thread #{0}: ", th.ManagedThreadId);
         Console.WriteLine("   Background thread: {0}", th.IsBackground);
         Console.WriteLine("   Thread pool thread: {0}", th.IsThreadPoolThread);
         Console.WriteLine("   Priority: {0}", th.Priority);
         Console.WriteLine("   Culture: {0}", th.CurrentCulture.Name);
         Console.WriteLine("   UI culture: {0}", th.CurrentUICulture.Name);
         Console.WriteLine();
      }   
   }
}
// The example displays output like the following:
//       Managed thread #6:
//          Background thread: True
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #3:
//          Background thread: True
//          Thread pool thread: True
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #4:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #1:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US

Foreground and background threads

Instances of the Thread class represent either foreground threads or background threads. Background threads are identical to foreground threads with one exception: a background thread does not keep a process running if all foreground threads have terminated. Once all foreground threads have been stopped, the runtime stops all background threads and shuts down.

By default, the following threads execute in the foreground:

  • The main application thread.

  • All threads created by calling a Thread class constructor.

The following threads execute in the background by default:

  • Thread pool threads, which are a pool of worker threads maintained by the runtime. You can configure the thread pool and schedule work on thread pool threads by using the ThreadPool class.

    System_CAPS_noteNote

    Task-based asynchronous operations automatically execute on thread pool threads. Task-based asynchronous operations use the Taskand Task<TResult> classes to implement the task-based asynchronous pattern.

  • All threads that enter the managed execution environment from unmanaged code.

You can change a thread to execute in the background by setting the IsBackground property at any time. Background threads are useful for any operation that should continue as long as an application is running but should not prevent the application from terminating, such as monitoring file system changes or incoming socket connections.

The following example illustrates the difference between foreground and background threads. It is like the first example in the Starting a threadsection, except that it sets the thread to execute in the background before starting it. As the output shows, the loop is interrupted before it executes for five seconds.

using System;
using System.Diagnostics;
using System.Threading;

public class Example
{
   public static void Main()
   {
      var th = new Thread(ExecuteInForeground);
      th.IsBackground = true;
      th.Start();
      Thread.Sleep(1000);
      Console.WriteLine("Main thread ({0}) exiting...", 
                        Thread.CurrentThread.ManagedThreadId); 
   }

   private static void ExecuteInForeground()
   {
      DateTime start = DateTime.Now;
      var sw = Stopwatch.StartNew();
      Console.WriteLine("Thread {0}: {1}, Priority {2}", 
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority);
      do { 
         Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds", 
                           Thread.CurrentThread.ManagedThreadId,
                           sw.ElapsedMilliseconds / 1000.0);
         Thread.Sleep(500);
      } while (sw.ElapsedMilliseconds <= 5000);
      sw.Stop(); 
   }
}
// The example displays output like the following:
//       Thread 3: Background, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.51 seconds
//       Main thread (1) exiting...

Culture and threads

Each thread has a culture, represented by the CurrentCulture property, and a UI culture, represented by the CurrentUICulture property. The current culture supports such culture-sensitive operations as parsing and formatting, string comparison and sorting, and also controls the writing system and calendar used by a thread. The current UI culture provides for culture-sensitive retrieval of resources in resource files.

When a new thread is instantiated, its culture and UI culture are defined by the current system culture and UI culture, and not by the culture and UI culture of the thread from which the new thread is created. This means, for example, that if the current system culture is English (United States) and the current culture of the primary application thread is French (France), the culture of a new thread created by calling theThread(ParameterizedThreadStart) constructor from the primary thread is English (United States), and not French (France). For more information, see the "Culture and threads" section of the CultureInfo class topic.

System_CAPS_importantImportant

This is not true of threads that execute asynchronous operations for apps that target the .NET Framework 4.6 and later versions, In this case, the culture and UI culture is part of an asynchronous operations' context; the thread on which an asynchronous operation executes by default inherits the culture and UI culture of the thread from which the asynchronous operation was launched. For more information, see the "Culture and task-based asynchronous operations" section of the CultureInfo class topic.

You can do either of the following to ensure that all of the threads executing in an application share the same culture and UI culture:

For more information and examples, see the "Culture and threads" section of the CultureInfo class topic.

Getting information about and controlling threads

You can retrieve a number of property values that provide information about a thread. In some cases, you can also set these property values to control the operation of the thread. These thread properties include:

  • A name. Name is a write-once property that you can use to identify a thread. Its default value is null.

  • A hash code, which you can retrieve by calling the GetHashCode method. The hash code can be used to uniquely identify a thread; for the lifetime of your thread, its hash code will not collide with the value from any other thread, regardless of the application domain from which you obtain the value.

  • A thread ID. The value of the read-only ManagedThreadId property is assigned by the runtime and uniquely identifies a thread within its process.

    System_CAPS_noteNote

    An operating-system ThreadId has no fixed relationship to a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. Specifically, a sophisticated host can use the CLR Hosting API to schedule many managed threads against the same operating system thread, or to move a managed thread between different operating system threads.

  • The thread's current state. For the duration of its existence, a thread is always in one or more of the states defined by the ThreadStateproperty.

  • A scheduling priority level, which is defined by the ThreadPriority property. Although you can set this value to request a thread's priority, it is not guaranteed to be honored by the operating system.

  • The read-only IsThreadPoolThread property, which indicates whether a thread is a thread pool thread.

  • The IsBackground property. For more information, see the Foreground and background threads section.

Accessing the source code for the Thread class

To view the .NET Framework source code for the Thread class, see the Reference Source. You can browse through the source code online, download the reference for offline viewing, and step through the sources (including patches and updates) during debugging; see instructions.

Examples

The following example demonstrates simple threading functionality.

using System;
using System.Threading;

// Simple threading scenario:  Start a static method running
// on a second thread.
public class ThreadExample {
    // The ThreadProc method is called when the thread starts.
    // It loops ten times, writing to the console and yielding 
    // the rest of its time slice each time, and then ends.
    public static void ThreadProc() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("ThreadProc: {0}", i);
            // Yield the rest of the time slice.
            Thread.Sleep(0);
        }
    }

    public static void Main() {
        Console.WriteLine("Main thread: Start a second thread.");
        // The constructor for the Thread class requires a ThreadStart 
        // delegate that represents the method to be executed on the 
        // thread.  C# simplifies the creation of this delegate.
        Thread t = new Thread(new ThreadStart(ThreadProc));

        // Start ThreadProc.  Note that on a uniprocessor, the new 
        // thread does not get any processor time until the main thread 
        // is preempted or yields.  Uncomment the Thread.Sleep that 
        // follows t.Start() to see the difference.
        t.Start();
        //Thread.Sleep(0);

        for (int i = 0; i < 4; i++) {
            Console.WriteLine("Main thread: Do some work.");
            Thread.Sleep(0);
        }

        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");
        t.Join();
        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.");
        Console.ReadLine();
    }
}

This code produces output similar to the following:

[VB, C++, C#]
Main thread: Start a second thread.
Main thread: Do some work.
ThreadProc: 0
Main thread: Do some work.
ThreadProc: 1
Main thread: Do some work.
ThreadProc: 2
Main thread: Do some work.
ThreadProc: 3
Main thread: Call Join(), to wait until ThreadProc ends.
ThreadProc: 4
ThreadProc: 5
ThreadProc: 6
ThreadProc: 7
ThreadProc: 8
ThreadProc: 9
Main thread: ThreadProc.Join has returned.  Press Enter to end program.






Thread Constructor (ThreadStart)


Initializes a new instance of the Thread class.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public Thread(
	ThreadStart start
)

Parameters

start
Type: System.Threading.ThreadStart

ThreadStart delegate that represents the methods to be invoked when this thread begins executing.

Exceptions

ExceptionCondition
ArgumentNullException

The start parameter is null.

Remarks

A thread does not begin executing when it is created. To schedule the thread for execution, call the Start method.

System_CAPS_noteNote

Visual Basic users can omit the ThreadStart constructor when creating a thread. Use the AddressOf operator when passing your method for example Dim t As New Thread(AddressOf ThreadProc). Visual Basic automatically calls the ThreadStart constructor.

Examples

The following code example shows how to create a thread that executes a static method.

using System;
using System.Threading;

class Test
{
    static void Main() 
    {
        Thread newThread = 
            new Thread(new ThreadStart(Work.DoWork));
        newThread.Start();
    }
}

class Work 
{
    Work() {}

    public static void DoWork() {}
}

The following code example shows how to create a thread that executes an instance method.

using System;
using System.Threading;

class Test
{
    static void Main() 
    {
        Work threadWork = new Work();
        Thread newThread = 
            new Thread(new ThreadStart(threadWork.DoWork));
        newThread.Start();
    }
}

class Work 
{
    public Work() {}

    public void DoWork() {}
}





Thread Constructor (ParameterizedThreadStart)


Initializes a new instance of the Thread class, specifying a delegate that allows an object to be passed to the thread when the thread is started.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public Thread(
	ParameterizedThreadStart start
)

Parameters

start
Type: System.Threading.ParameterizedThreadStart

A delegate that represents the methods to be invoked when this thread begins executing.

Exceptions

ExceptionCondition
ArgumentNullException

start is null.

Remarks

A thread does not begin executing when it is created. To schedule the thread for execution, call the Start method. To pass a data object to the thread, use the Start(Object) method overload.

System_CAPS_noteNote

Visual Basic users can omit the ThreadStart constructor when creating a thread. Use the AddressOf operator when passing your method, for example Dim t As New Thread(AddressOf ThreadProc). Visual Basic automatically calls the ThreadStart constructor.

Examples

The following example shows the syntax for creating and using a ParameterizedThreadStart delegate with a static method and an instance method.

using System;
using System.Threading;

public class Work
{
    public static void Main()
    {
        // Start a thread that calls a parameterized static method.
        Thread newThread = new Thread(Work.DoWork);
        newThread.Start(42);

        // Start a thread that calls a parameterized instance method.
        Work w = new Work();
        newThread = new Thread(w.DoMoreWork);
        newThread.Start("The answer.");
    }

    public static void DoWork(object data)
    {
        Console.WriteLine("Static thread procedure. Data='{0}'",
            data);
    }

    public void DoMoreWork(object data)
    {
        Console.WriteLine("Instance thread procedure. Data='{0}'",
            data);
    }
}
// This example displays output like the following:
//       Static thread procedure. Data='42'
//       Instance thread procedure. Data='The answer.'






ThreadPool Class


https://msdn.microsoft.com/en-us/library/system.threading.threadpool(v=vs.110).aspx


Provides a pool of threads that can be used to execute tasks, post work items, process asynchronous I/O, wait on behalf of other threads, and process timers.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Inheritance Hierarchy

System.Object
  System.Threading.ThreadPool


Remarks

Many applications create threads that spend a great deal of time in the sleeping state, waiting for an event to occur. Other threads might enter a sleeping state only to be awakened periodically to poll for a change or update status information. The thread pool enables you to use threads more efficiently by providing your application with a pool of worker threads that are managed by the system. Examples of operations that use thread pool threads include the following:

  • When you create a Task or Task<TResult> object to perform some task asynchronously, by default the task is scheduled to run on a thread pool thread.

  • Asynchronous timers use the thread pool. Thread pool threads execute callbacks from the System.Threading.Timer class and raise events from the System.Timers.Timer class.

  • When you use registered wait handles, a system thread monitors the status of the wait handles. When a wait operation completes, a worker thread from the thread pool executes the corresponding callback function.

  • When you call the QueueUserWorkItem method to queue a method for execution on a thread pool thread. You do this by passing the method a WaitCallback delegate. The delegate has the signature

    void WaitCallback(Object state)
    

    where state is an object that contains data to be used by the delegate. The actual data can be passed to the delegate by calling the QueueUserWorkItem(WaitCallback, Object) method.

System_CAPS_noteNote

The threads in the managed thread pool are background threads. That is, their IsBackground properties are true. This means that a ThreadPoolthread will not keep an application running after all foreground threads have exited.

System_CAPS_importantImportant

When the thread pool reuses a thread, it does not clear the data in thread local storage or in fields that are marked with the ThreadStaticAttributeattribute. Therefore, when a method examines thread local storage or fields that are marked with the ThreadStaticAttribute attribute, the values it finds might be left over from an earlier use of the thread pool thread.

You can also queue work items that are not related to a wait operation to the thread pool. To request that a work item be handled by a thread in the thread pool, call the QueueUserWorkItem method. This method takes as a parameter a reference to the method or delegate that will be called by the thread selected from the thread pool. There is no way to cancel a work item after it has been queued.

Timer-queue timers and registered wait operations also use the thread pool. Their callback functions are queued to the thread pool.

There is one thread pool per process. Beginning with the .NET Framework 4, the default size of the thread pool for a process depends on several factors, such as the size of the virtual address space. A process can call the GetMaxThreads method to determine the number of threads. The number of threads in the thread pool can be changed by using the SetMaxThreads method. Each thread uses the default stack size and runs at the default priority.

System_CAPS_noteNote

Unmanaged code that hosts the .NET Framework can change the size of the thread pool by using the CorSetMaxThreads function, defined in the mscoree.h file.

The thread pool provides new worker threads or I/O completion threads on demand until it reaches the minimum for each category. When a minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete. Beginning with the .NET Framework 4, the thread pool creates and destroys worker threads in order to optimize throughput, which is defined as the number of tasks that complete per unit of time. Too few threads might not make optimal use of available resources, whereas too many threads could increase resource contention.

System_CAPS_noteNote

When demand is low, the actual number of thread pool threads can fall below the minimum values.

You can use the GetMinThreads method to obtain these minimum values.

System_CAPS_cautionCaution

You can use the SetMinThreads method to increase the minimum number of threads. However, unnecessarily increasing these values can cause performance problems. If too many tasks start at the same time, all of them might appear to be slow. In most cases the thread pool will perform better with its own algorithm for allocating threads.

Examples

In the following example, the main application thread queues a method named ThreadProc to execute on a thread pool thread, sleeps for one second, and then exits. The ThreadProc method simply displays a message.

using System;
using System.Threading;

public class Example 
{
    public static void Main() 
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(ThreadProc);
        Console.WriteLine("Main thread does some work, then sleeps.");
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo) 
    {
        // No state object was passed to QueueUserWorkItem, so stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}
// The example displays output like the following:
//       Main thread does some work, then sleeps.
//       Hello from the thread pool.
//       Main thread exits.

If you comment out the call to the Thread.Sleep method, the main thread exits before method runs on the thread pool thread. The thread pool uses background threads, which do not keep the application running if all foreground threads have terminated. (This is a simple example of a race condition.)






ThreadPool.QueueUserWorkItem Method (WaitCallback)


Queues a method for execution. The method executes when a thread pool thread becomes available.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public static bool QueueUserWorkItem(
	WaitCallback callBack
)

Parameters

callBack
Type: System.Threading.WaitCallback

WaitCallback that represents the method to be executed.

Return Value

Type: System.Boolean

true if the method is successfully queued; NotSupportedException is thrown if the work item could not be queued.

Exceptions

ExceptionCondition
ArgumentNullException

callBack is null.

NotSupportedException

The common language runtime (CLR) is hosted, and the host does not support this action.

Remarks

You can place data required by the queued method in the instance fields of the class in which the method is defined, or you can use the QueueUserWorkItem(WaitCallback, Object) overload that accepts an object containing the necessary data.

System_CAPS_noteNote

Visual Basic users can omit the WaitCallback constructor, and simply use the AddressOf operator when passing the callback method to QueueUserWorkItem. Visual Basic automatically calls the correct delegate constructor.

Version Information

In the .NET Framework version 2.0, the Thread.CurrentPrincipal property value is propagated to worker threads queued using the QueueUserWorkItem method. In earlier versions, the principal information is not propagated.

Examples

The following example uses the QueueUserWorkItem(WaitCallback) method overload to queue a task, which is represented by the ThreadProc method, to execute when a thread becomes available. No task information is supplied with this overload. Therefore, the information that is available to the ThreadProc method is limited to the object the method belongs to.

using System;
using System.Threading;

public class Example 
{
    public static void Main() 
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(ThreadProc);
        Console.WriteLine("Main thread does some work, then sleeps.");
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo) 
    {
        // No state object was passed to QueueUserWorkItem, so stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}
// The example displays output like the following:
//       Main thread does some work, then sleeps.
//       Hello from the thread pool.
//       Main thread exits.





ThreadPool.QueueUserWorkItem Method (WaitCallback, Object)


Queues a method for execution, and specifies an object containing data to be used by the method. The method executes when a thread pool thread becomes available.

Namespace:   System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public static bool QueueUserWorkItem(
	WaitCallback callBack,
	object state
)

Parameters

callBack
Type: System.Threading.WaitCallback

WaitCallback representing the method to execute.

state
Type: System.Object

An object containing data to be used by the method.

Return Value

Type: System.Boolean

true if the method is successfully queued; NotSupportedException is thrown if the work item could not be queued.

Exceptions

ExceptionCondition
NotSupportedException

The common language runtime (CLR) is hosted, and the host does not support this action.

ArgumentNullException

callBack is null.

Remarks

If the callback method requires complex data, you can define a class to contain the data.

System_CAPS_noteNote

Visual Basic users can omit the WaitCallback constructor, and simply use the AddressOf operator when passing the callback method to QueueUserWorkItem. Visual Basic automatically calls the correct delegate constructor.

Version Information

In the .NET Framework version 2.0, the Thread.CurrentPrincipal property value is propagated to worker threads queued using the QueueUserWorkItem method. In earlier versions, the principal information is not propagated.

Examples

The following example shows how to create an object that contains task information. It also demonstrates how to pass that object to a task that is queued for execution by the thread pool.

// This example shows how to create an object containing task
// information, and pass that object to a task queued for
// execution by the thread pool.
using System;
using System.Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public class TaskInfo 
    {
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
    public string Boilerplate;
    public int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    public TaskInfo(string text, int number) {
        Boilerplate = text;
        Value = number;
    }
}

public class Example {
    public static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti);

        Console.WriteLine("Main thread does some work, then sleeps.");

        // If you comment out the Sleep, the main thread exits before
        // the ThreadPool task has a chance to run.  ThreadPool uses 
        // background threads, which do not keep the application 
        // running.  (This is a simple example of a race condition.)
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object stateInfo) 
    {
        TaskInfo ti = (TaskInfo) stateInfo;
        Console.WriteLine(ti.Boilerplate, ti.Value); 
    }
}
// The example displays output like the following:
//       Main thread does some work, then sleeps.
//       This report displays the number 42.
//       Main thread exits.







WebClient Class


Provides common methods for sending data to and receiving data from a resource identified by a URI.

Namespace:   System.Net
Assembly:  System (in System.dll)

Inheritance Hierarchy

System.Object
  System.MarshalByRefObject
    System.ComponentModel.Component
      System.Net.WebClient

Remarks

The WebClient class provides common methods for sending data to or receiving data from any local, intranet, or Internet resource identified by a URI.

The WebClient class uses the WebRequest class to provide access to resources. WebClient instances can access data with any WebRequestdescendant registered with the WebRequest.RegisterPrefix method.

System_CAPS_noteNote

By default, the .NET Framework supports URIs that begin with http:https:, ftp:, and file: scheme identifiers.

The following table describes WebClient methods for uploading data to a resource.

Method

Description

OpenWrite

Retrieves a Stream used to send data to the resource.

OpenWriteAsync

Retrieves a Stream used to send data to the resource, without blocking the calling thread.

UploadData

Sends a byte array to the resource and returns a Byte array containing any response.

UploadDataAsync

Sends a Byte array to the resource, without blocking the calling thread.

UploadFile

Sends a local file to the resource and returns a Byte array containing any response.

UploadFileAsync

Sends a local file to the resource, without blocking the calling thread.

UploadValues

Sends a NameValueCollection to the resource and returns a Byte array containing any response.

UploadValuesAsync

Sends a NameValueCollection to the resource and returns a Byte array containing any response, without blocking the calling thread.

UploadString

Sends a String to the resource, without blocking the calling thread.

UploadStringAsync

Sends a String to the resource, without blocking the calling thread.

The following table describes WebClient methods for downloading data from a resource.

Method

Description

OpenRead

Returns the data from a resource as a Stream.

OpenReadAsync

Returns the data from a resource, without blocking the calling thread.

DownloadData

Downloads data from a resource and returns a Byte array.

DownloadDataAsync

Downloads data from a resource and returns a Byte array, without blocking the calling thread.

DownloadFile

Downloads data from a resource to a local file.

DownloadFileAsync

Downloads data from a resource to a local file, without blocking the calling thread.

DownloadString

Downloads a String from a resource and returns a String.

DownloadStringAsync

Downloads a String from a resource, without blocking the calling thread.

You can use the CancelAsync method to cancel asynchronous operations that have not completed.

WebClient instance does not send optional HTTP headers by default. If your request requires an optional header, you must add the header to the Headers collection. For example, to retain queries in the response, you must add a user-agent header. Also, servers may return 500 (Internal Server Error) if the user agent header is missing.

AllowAutoRedirect is set to true in WebClient instances.

Notes to Inheritors:

Derived classes should call the base class implementation of WebClient to ensure the derived class works as expected.

Examples

The following code example takes the URI of a resource, retrieves it, and displays the response.

using System;
using System.Net;
using System.IO;

public class Test
{
    public static void Main (string[] args)
    {
        if (args == null || args.Length == 0)
        {
            throw new ApplicationException ("Specify the URI of the resource to retrieve.");
        }
        WebClient client = new WebClient ();

        // Add a user agent header in case the 
        // requested URI contains a query.

        client.Headers.Add ("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

        Stream data = client.OpenRead (args[0]);
        StreamReader reader = new StreamReader (data);
        string s = reader.ReadToEnd ();
        Console.WriteLine (s);
        data.Close ();
        reader.Close ();
    }







GC Class


https://msdn.microsoft.com/en-us/library/system.gc(v=vs.110).aspx


Controls the system garbage collector, a service that automatically reclaims unused memory.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)


Remarks

The garbage collector is a common language runtime component that controls the allocation and release of managed memory. The methods in this class influence when garbage collection is performed on an object and when resources allocated by an object are released. Properties in this class provide information about the total amount of memory available in the system and the age category, or generation, of memory allocated to an object.

The garbage collector tracks and reclaims objects allocated in managed memory. Periodically, the garbage collector performs garbage collection to reclaim memory allocated to objects for which there are no valid references. Garbage collection happens automatically when a request for memory cannot be satisfied using available free memory. Alternatively, an application can force garbage collection using the Collect method.

Garbage collection consists of the following steps:

  1. The garbage collector searches for managed objects that are referenced in managed code.

  2. The garbage collector tries to finalize objects that are not referenced.

  3. The garbage collector frees objects that are not referenced and reclaims their memory.

This topic includes the following sections:

The garbage collector and unmanaged resources
Object aging and generations
Disallowing garbage collection

The garbage collector and unmanaged resources

During a collection, the garbage collector will not free an object if it finds one or more references to the object in managed code. However, the garbage collector does not recognize references to an object from unmanaged code, and might free objects that are being used exclusively in unmanaged code unless explicitly prevented from doing so. The KeepAlive method provides a mechanism that prevents the garbage collector from collecting objects that are still in use in unmanaged code.

Aside from managed memory allocations, implementations of the garbage collector do not maintain information about resources held by an object, such as file handles or database connections. When a type uses unmanaged resources that must be released before instances of the type are reclaimed, the type can implement a finalizer.

In most cases, finalizers are implemented by overriding the Object.Finalize method; however, types written in C# or C++ implement destructors, which compilers turn into an override of Object.Finalize. In most cases, if an object has a finalizer, the garbage collector calls it prior to freeing the object. However, the garbage collector is not required to call finalizers in all situations; for example, the SuppressFinalize method explicitly prevents an object's finalizer from being called. Also, the garbage collector is not required to use a specific thread to finalize objects, or guarantee the order in which finalizers are called for objects that reference each other but are otherwise available for garbage collection.

In scenarios where resources must be released at a specific time, classes can implement the IDisposable interface, which contains the IDisposable.Dispose method that performs resource management and cleanup tasks. Classes that implement Dispose must specify, as part of their class contract, if and when class consumers call the method to clean up the object. The garbage collector does not, by default, call the Dispose method; however, implementations of the Dispose method can call methods in the GC class to customize the finalization behavior of the garbage collector.

For more information on object finalization and the dispose pattern, see Cleaning Up Unmanaged Resources.

Object aging and generations

The garbage collector in the common language runtime supports object aging using generations. A generation is a unit of measure of the relative age of objects in memory. The generation number, or age, of an object indicates the generation to which an object belongs. Objects created more recently are part of newer generations, and have lower generation numbers than objects created earlier in the application life cycle. Objects in the most recent generation are in generation 0. This implementation of the garbage collector supports three generations of objects, generations 0, 1, and 2. You can retrieve the value of the MaxGeneration property to determine the maximum generation number supported by the system.

Object aging allows applications to target garbage collection at a specific set of generations rather than requiring the garbage collector to evaluate all generations. Overloads of the Collect method that include a generation parameter allow you to specify the oldest generation to be garbage collected.

Disallowing garbage collection

Starting with the .NET Framework 4.6, the garbage collector supports a no GC region latency mode that can be used during the execution of critical paths in which garbage collection can adversely affect an app's performance. The no GC region latency mode requires that you specify an amount of memory that can be allocated without interference from the garbage collector. If the runtime can allocate that memory, the runtime will not perform a garbage collection while code in the critical path is executing.

You define the beginning of the critical path of the no GC region by calling one of the overloads of the TryStartNoGCRegion. You specify the end of its critical path by calling the EndNoGCRegion method.

Examples

The following example uses several GC methods to get generation and memory information about a block of unused objects and print it to the console. The unused objects are then collected, and the resulting memory totals are displayed.

using System;

namespace GCCollectIntExample
{
    class MyGCCollectClass
    {
        private const long maxGarbage = 1000;

        static void Main()
        {
            MyGCCollectClass myGCCol = new MyGCCollectClass();

            // Determine the maximum number of generations the system
	    // garbage collector currently supports.
            Console.WriteLine("The highest generation is {0}", GC.MaxGeneration);

            myGCCol.MakeSomeGarbage();

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            // Determine the best available approximation of the number 
	    // of bytes currently allocated in managed memory.
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of generation 0 only.
            GC.Collect(0);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of all generations up to and including 2.
            GC.Collect(2);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
            Console.Read();
        }

        void MakeSomeGarbage()
        {
            Version vt;

            for(int i = 0; i < maxGarbage; i++)
            {
                // Create objects and release them to fill up memory
		// with unused objects.
                vt = new Version();
            }
        }
    }
}








GC.Collect()


https://msdn.microsoft.com/en-us/library/xe0c2357(v=vs.110).aspx


Forces an immediate garbage collection of all generations.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public static void Collect()

Remarks

Use this method to try to reclaim all memory that is inaccessible. It performs a blocking garbage collection of all generations.

All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.

Starting with the .NET Framework 4.5.1, you can compact the large object heap (LOH) by setting the GCSettings.LargeObjectHeapCompactionMode property to GCLargeObjectHeapCompactionMode.CompactOnce before calling the Collect method, as the following example illustrates.

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();      

Examples

The following example demonstrates how to use the Collect method to perform a collection on all generations of memory. The code generates a number of unused objects, and then calls the Collect method to clean them from memory.

using System;

class MyGCCollectClass
{
   private const int maxGarbage = 1000;

   static void Main()
   {
      // Put some objects in memory.
      MyGCCollectClass.MakeSomeGarbage();
      Console.WriteLine("Memory used before collection:       {0:N0}", 
                        GC.GetTotalMemory(false));

      // Collect all generations of memory.
      GC.Collect();
      Console.WriteLine("Memory used after full collection:   {0:N0}", 
                        GC.GetTotalMemory(true));
   }

   static void MakeSomeGarbage()
   {
      Version vt;

      // Create objects and release them to fill up memory with unused objects.
      for(int i = 0; i < maxGarbage; i++) {
         vt = new Version();
      }
   }
}
// The output from the example resembles the following:
//       Memory used before collection:       79,392
//       Memory used after full collection:   52,640





GC.Collect(int)


https://msdn.microsoft.com/en-us/library/y46kxc5e(v=vs.110).aspx


Forces an immediate garbage collection from generation 0 through a specified generation.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public static void Collect(
	int generation
)

Parameters

generation
Type: System.Int32

The number of the oldest generation to be garbage collected.

Exceptions

ExceptionCondition
ArgumentOutOfRangeException

generation is not valid.

Remarks

Use this method to try to reclaim memory that is inaccessible. However, using this method does not guarantee that all inaccessible memory in the specified generation is reclaimed.

If object aging is implemented, the garbage collector does not collect objects with a generation number that is higher than the specified generation. If object aging is not implemented, the garbage collector considers all objects during the garbage collection.

Use the MaxGeneration property to determine the maximum valid value of the generation parameter.

To have the garbage collector consider all objects regardless of their generation, use the version of this method that takes no parameters. To have the garbage collector reclaim objects based on a GCCollectionMode setting, use the GC.Collect(Int32, GCCollectionMode) method overload.

Examples

The following example demonstrates how to use the Collect method to perform a collection on individual layers of memory. The code generates a number of unused objects, and then calls the Collect method to clean them from memory.

using System;

namespace GCCollectIntExample
{
    class MyGCCollectClass
    {
        private const long maxGarbage = 1000;

        static void Main()
        {
            MyGCCollectClass myGCCol = new MyGCCollectClass();

            // Determine the maximum number of generations the system
	    // garbage collector currently supports.
            Console.WriteLine("The highest generation is {0}", GC.MaxGeneration);

            myGCCol.MakeSomeGarbage();

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            // Determine the best available approximation of the number 
	    // of bytes currently allocated in managed memory.
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of generation 0 only.
            GC.Collect(0);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of all generations up to and including 2.
            GC.Collect(2);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
            Console.Read();
        }

        void MakeSomeGarbage()
        {
            Version vt;

            for(int i = 0; i < maxGarbage; i++)
            {
                // Create objects and release them to fill up memory
		// with unused objects.
                vt = new Version();
            }
        }
    }
}





GC.GetTotalMemory(bool)


https://msdn.microsoft.com/en-us/library/system.gc.gettotalmemory(v=vs.110).aspx


Retrieves the number of bytes currently thought to be allocated. A parameter indicates whether this method can wait a short interval before returning, to allow the system to collect garbage and finalize objects.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public static long GetTotalMemory(
	bool forceFullCollection
)

Parameters

forceFullCollection
Type: System.Boolean

true to indicate that this method can wait for garbage collection to occur before returning; otherwise, false.

Return Value

Type: System.Int64

A number that is the best available approximation of the number of bytes currently allocated in managed memory.

Remarks

If the forceFullCollection parameter is true, this method waits a short interval before returning while the system collects garbage and finalizes objects. The duration of the interval is an internally specified limit determined by the number of garbage collection cycles completed and the change in the amount of memory recovered between cycles. The garbage collector does not guarantee that all inaccessible memory is collected.

Examples

The following example demonstrates how to use the GetTotalMemory method to get and display the number of bytes currently allocated in managed memory.

using System;

namespace GCCollectIntExample
{
    class MyGCCollectClass
    {
        private const long maxGarbage = 1000;

        static void Main()
        {
            MyGCCollectClass myGCCol = new MyGCCollectClass();

            // Determine the maximum number of generations the system
	    // garbage collector currently supports.
            Console.WriteLine("The highest generation is {0}", GC.MaxGeneration);

            myGCCol.MakeSomeGarbage();

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            // Determine the best available approximation of the number 
	    // of bytes currently allocated in managed memory.
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of generation 0 only.
            GC.Collect(0);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of all generations up to and including 2.
            GC.Collect(2);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
            Console.Read();
        }

        void MakeSomeGarbage()
        {
            Version vt;

            for(int i = 0; i < maxGarbage; i++)
            {
                // Create objects and release them to fill up memory
		// with unused objects.
                vt = new Version();
            }
        }
    }
}





















'프로그래밍 > C#' 카테고리의 다른 글

클래스 종류 헤드라인  (0) 2017.01.04
C# Keywords - Types  (0) 2016.12.29
Operators  (0) 2016.11.14
IEnumerable Interface  (0) 2016.11.14
Predicate<T> Delegate  (0) 2016.10.18
:
Posted by 지훈2
2016. 11. 24. 02:02

Graphics and Multimedia 프로그래밍/WPF2016. 11. 24. 02:02



Graphics and Multimedia


https://msdn.microsoft.com/en-us/library/ms742562(v=vs.110).aspx


Windows Presentation Foundation (WPF) provides support for multimedia, vector graphics, animation, and content composition, making it easy for developers to build interesting user interfaces and content. Using Microsoft Visual Studio, you can create vector graphics or complex animations and integrate media into your applications.

This topic introduces the graphics, animation, and media features of WPF, which enable you to add graphics, transition effects, sound, and video to your applications.

System_CAPS_noteNote

Using WPF types in a Windows service is strongly discouraged. If you attempt to use WPF types in a Windows service, the service may not work as expected.

What's New with Graphics and Multimedia in WPF 4

Several changes have been made related to graphics and animations.

  • Layout Rounding

    When an object edge falls in the middle of a pixel device, the DPI-independent graphics system can create rendering artifacts, such as blurry or semi-transparent edges. Previous versions of WPF included pixel snapping to help handle this case. Silverlight 2 introduced layout rounding, which is another way to move elements so that edges fall on whole pixel boundaries. WPF now supports layout rounding with the UseLayoutRounding attached property on FrameworkElement.

  • Cached Composition

    By using the new BitmapCache and BitmapCacheBrush classes, you can cache a complex part of the visual tree as a bitmap and greatly improve rendering time. The bitmap remains responsive to user input, such as mouse clicks, and you can paint it onto other elements just like any brush.

  • Pixel Shader 3 Support

    WPF 4 builds on top of the ShaderEffect support introduced in WPF 3.5 SP1 by allowing applications to write effects by using Pixel Shader (PS) version 3.0. The PS 3.0 shader model is more sophisticated than PS 2.0, which allows for even more effects on supported hardware.

  • Easing Functions

    You can enhance animations with easing functions, which give you additional control over the behavior of animations. For example, you can apply an ElasticEase to an animation to give the animation a springy behavior. For more information, see the easing types in the System.Windows.Media.Animation namespace.

Graphics and Rendering

WPF includes support for high quality 2-D graphics. The functionality includes brushes, geometries, images, shapes and transformations. For more information, see Graphics. The rendering of graphical elements is based on the Visual class. The structure of visual objects on the screen is described by the visual tree. For more information, see WPF Graphics Rendering Overview.

2-D Shapes

WPF provides a library of commonly used, vector-drawn 2-D shapes, such as rectangles and ellipses, which the following illustration shows.

Ellipses and rectangles

These intrinsic WPF shapes are not just shapes: they are programmable elements that implement many of the features that you expect from most common controls, which include keyboard and mouse input. The following example shows how to handle the MouseUp event raised by clicking an Ellipse element.

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Window1" >
  <Ellipse Fill="LightBlue" MouseUp="ellipseButton_MouseUp" />
</Window>
public partial class Window1  : Window
{
    void ellipseButton_MouseUp(object sender, MouseButtonEventArgs e)
    {
        MessageBox.Show("You clicked the ellipse!");
    }
}

The following illustration shows the output for the preceding XAML markup and code-behind.

A window with the text "you clicked the ellipse!"

For more information, see Shapes and Basic Drawing in WPF Overview. For an introductory sample, see Shape Elements Sample.

2-D Geometries

When the 2-D shapes that WPF provides are not sufficient, you can use WPF support for geometries and paths to create your own. The following illustration shows how you can use geometries to create shapes, as a drawing brush, and to clip other WPF elements.

Various uses of a Path

For more information, see Geometry Overview. For an introductory sample, see Geometries Sample.

2-D Effects

WPF provides a library of 2-D classes that you can use to create a variety of effects. The 2-D rendering capability of WPF provides the ability to paint UI elements that have gradients, bitmaps, drawings, and videos; and to manipulate them by using rotation, scaling, and skewing. The following illustration gives an example of the many effects you can achieve by using WPF brushes.

Illustration of different brushes

For more information, see WPF Brushes Overview. For an introductory sample, see Brushes Sample.

3-D Rendering

WPF provides a set of 3-D rendering capabilities that integrate with 2-D graphics support in WPF in order for you to create more exciting layout, UI, and data visualization. At one end of the spectrum, WPF enables you to render 2-D images onto the surfaces of 3-D shapes, which the following illustration demonstrates.

Visual3D sample screen shot

For more information, see 3-D Graphics Overview. For an introductory sample, see 3-D Solids Sample.

Animation

Use animation to make controls and elements grow, shake, spin, and fade; and to create interesting page transitions, and more. Because WPF enables you to animate most properties, not only can you animate most WPF objects, you can also use WPF to animate custom objects that you create.

Images of an animated cube

For more information, see Animation Overview. For an introductory sample, see Animation Example Gallery.

Media

Images, video, and audio are media-rich ways of conveying information and user experiences.

Images

Images, which include icons, backgrounds, and even parts of animations, are a core part of most applications. Because you frequently need to use images, WPF exposes the ability to work with them in a variety of ways. The following illustration shows just one of those ways.

Styling sample screen shot

For more information, see Imaging Overview.

Video and Audio

A core feature of the graphics capabilities of WPF is to provide native support for working with multimedia, which includes video and audio. The following example shows how to insert a media player into an application.

<MediaElement Source="media\numbers.wmv" Width="450" Height="250" />

MediaElement is capable of playing both video and audio, and is extensible enough to allow the easy creation of custom UIs.

For more information, see the Multimedia Overview




WPF Graphics Rendering Overview


This topic provides an overview of the WPF visual layer. It focuses on the role of the Visual class for rendering support in the WPF model.

Role of the Visual Object

The Visual class is the basic abstraction from which every FrameworkElement object derives. It also serves as the entry point for writing new controls in WPF, and in many ways can be thought of as the window handle (HWND) in the Win32 application model.

The Visual object is a core WPF object, whose primary role is to provide rendering support. User interface controls, such as Button and TextBox, derive from the Visual class, and use it for persisting their rendering data. The Visual object provides support for:

  • Output display: Rendering the persisted, serialized drawing content of a visual.

  • Transformations: Performing transformations on a visual.

  • Clipping: Providing clipping region support for a visual.

  • Hit testing: Determining whether a coordinate or geometry is contained within the bounds of a visual.

  • Bounding box calculations: Determining the bounding rectangle of a visual.

However, the Visual object does not include support for non-rendering features, such as:

  • Event handling

  • Layout

  • Styles

  • Data binding

  • Globalization

Visual is exposed as a public abstract class from which child classes must be derived. The following illustration shows the hierarchy of the visual objects that are exposed in WPF.

Diagram of classes derived from the Visual object

Visual class hierarchy

DrawingVisual Class

The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its runtime performance. For this reason, drawings are ideal for backgrounds and clip art. The DrawingVisual can be used to create a custom visual object. For more information, see Using DrawingVisual Objects.

Viewport3DVisual Class

The Viewport3DVisual provides a bridge between 2D Visual and Visual3D objects. The Visual3D class is the base class for all 3D visual elements. The Viewport3DVisual requires that you define a Camera value and a Viewport value. The camera allows you to view the scene. The viewport establishes where the projection maps onto the 2D surface. For more information on 3D in WPF, see 3-D Graphics Overview.

ContainerVisual Class

The ContainerVisual class is used as a container for a collection of Visual objects. The DrawingVisual class derives from the ContainerVisual class, allowing it to contain a collection of visual objects.

Drawing Content in Visual Objects

Visual object stores its render data as a vector graphics instruction list. Each item in the instruction list represents a low-level set of graphics data and associated resources in a serialized format. There are four different types of render data that can contain drawing content.

Drawing content type

Description

Vector graphics

Represents vector graphics data, and any associated Brush and Pen information.

Image

Represents an image within a region defined by a Rect.

Glyph

Represents a drawing that renders a GlyphRun, which is a sequence of glyphs from a specified font resource. This is how text is represented.

Video

Represents a drawing that renders video.

The DrawingContext allows you to populate a Visual with visual content. When you use a DrawingContext object's draw commands, you are actually storing a set of render data that will later be used by the graphics system; you are not drawing to the screen in real-time.

When you create a WPF control, such as a Button, the control implicitly generates render data for drawing itself. For example, setting the Contentproperty of the Button causes the control to store a rendering representation of a glyph.

Visual describes its content as one or more Drawing objects contained within a DrawingGroup. A DrawingGroup also describes opacity masks, transforms, bitmap effects, and other operations that are applied to its contents. DrawingGroup operations are applied in the following order when content is rendered: OpacityMaskOpacityBitmapEffectClipGeometryGuidelineSet, and then Transform.

The following illustration shows the order in which DrawingGroup operations are applied during the rendering sequence.

DrawingGroup order of operations

Order of DrawingGroup operations

For more information, see Drawing Objects Overview.

Drawing Content at the Visual Layer

You never directly instantiate a DrawingContext; you can, however, acquire a drawing context from certain methods, such as DrawingGroup.Open and DrawingVisual.RenderOpen. The following example retrieves a DrawingContext from a DrawingVisual and uses it to draw a rectangle.

// Create a DrawingVisual that contains a rectangle.
private DrawingVisual CreateDrawingVisualRectangle()
{
    DrawingVisual drawingVisual = new DrawingVisual();

    // Retrieve the DrawingContext in order to create new drawing content.
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    // Create a rectangle and draw it in the DrawingContext.
    Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
    drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);

    // Persist the drawing content.
    drawingContext.Close();

    return drawingVisual;
}

Enumerating Drawing Content at the Visual Layer

In addition to their other uses, Drawing objects also provide an object model for enumerating the contents of a Visual.

System_CAPS_noteNote

When you are enumerating the contents of the visual, you are retrieving Drawing objects, and not the underlying representation of the render data as a vector graphics instruction list.

The following example uses the GetDrawing method to retrieve the DrawingGroup value of a Visual and enumerate it.

public void RetrieveDrawing(Visual v)
{
    DrawingGroup dGroup = VisualTreeHelper.GetDrawing(v);
    EnumDrawingGroup(dGroup);

}

 // Enumerate the drawings in the DrawingGroup.
 public void EnumDrawingGroup(DrawingGroup drawingGroup)
 {
     DrawingCollection dc = drawingGroup.Children;

     // Enumerate the drawings in the DrawingCollection.
     foreach (Drawing drawing in dc)
     {
         // If the drawing is a DrawingGroup, call the function recursively.
         if (drawing.GetType() == typeof(DrawingGroup))
         {
             EnumDrawingGroup((DrawingGroup)drawing);
         }
         else if (drawing.GetType() == typeof(GeometryDrawing))
         {
             // Perform action based on drawing type.  
         }
         else if (drawing.GetType() == typeof(ImageDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(GlyphRunDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(VideoDrawing))
         {
             // Perform action based on drawing type.
         }
     }
 }

How Visual Objects are Used to Build Controls

Many of the objects in WPF are composed of other visual objects, meaning they can contain varying hierarchies of descendant objects. Many of the user interface elements in WPF, such as controls, are composed of multiple visual objects, representing different types of rendering elements. For example, the Button control can contain a number of other objects, including ClassicBorderDecoratorContentPresenter, and TextBlock.

The following code shows a Button control defined in markup.

<Button Click="OnClick">OK</Button>

If you were to enumerate the visual objects that comprise the default Button control, you would find the hierarchy of visual objects illustrated below:

Diagram of visual tree hierarchy

Diagram of visual tree hierarchy

The Button control contains a ClassicBorderDecorator element, which in turn, contains a ContentPresenter element. The ClassicBorderDecoratorelement is responsible for drawing a border and a background for the Button. The ContentPresenter element is responsible for displaying the contents of the Button. In this case, since you are displaying text, the ContentPresenter element contains a TextBlock element. The fact that the Button control uses a ContentPresenter means that the content could be represented by other elements, such as an Image or a geometry, such as an EllipseGeometry.

Control Templates

The key to the expansion of a control into a hierarchy of controls is the ControlTemplate. A control template specifies the default visual hierarchy for a control. When you explicitly reference a control, you implicitly reference its visual hierarchy. You can override the default values for a control template to create a customized visual appearance for a control. For example, you could modify the background color value of the Button control so that it uses a linear gradient color value instead of a solid color value. For more information, see Button Styles and Templates.

A user interface element, such as a Button control, contains several vector graphics instruction lists that describe the entire rendering definition of a control. The following code shows a Button control defined in markup.

<Button Click="OnClick">
  <Image Source="images\greenlight.jpg"></Image>
</Button>

If you were to enumerate the visual objects and vector graphics instruction lists that comprise the Button control, you would find the hierarchy of objects illustrated below:

Diagram of visual tree and rendering data

Diagram of visual tree and rendering data

The Button control contains a ClassicBorderDecorator element, which in turn, contains a ContentPresenter element. The ClassicBorderDecoratorelement is responsible for drawing all the discrete graphic elements that make up the border and background of a button. The ContentPresenterelement is responsible for displaying the contents of the Button. In this case, since you are displaying an image, the ContentPresenter element contains a Image element.

There are a number of points to note about the hierarchy of visual objects and vector graphics instruction lists:

  • The ordering in the hierarchy represents the rendering order of the drawing information. From the root visual element, child elements are traversed, left to right, top to bottom. If an element has visual child elements, they are traversed before the element’s siblings.

  • Non-leaf node elements in the hierarchy, such as ContentPresenter, are used to contain child elements—they do not contain instruction lists.

  • If a visual element contains both a vector graphics instruction list and visual children, the instruction list in the parent visual element is rendered before drawings in any of the visual child objects.

  • The items in the vector graphics instruction list are rendered left to right.

Visual Tree

The visual tree contains all visual elements used in an application's user interface. Since a visual element contains persisted drawing information, you can think of the visual tree as a scene graph, containing all the rendering information needed to compose the output to the display device. This tree is the accumulation of all visual elements created directly by the application, whether in code or in markup. The visual tree also contains all visual elements created by the template expansion of elements such as controls and data objects.

The following code shows a StackPanel element defined in markup.

<StackPanel>
  <Label>User name:</Label>
  <TextBox />
  <Button Click="OnClick">OK</Button>
</StackPanel>

If you were to enumerate the visual objects that comprise the StackPanel element in the markup example, you would find the hierarchy of visual objects illustrated below:

Diagram of visual tree hierarchy

Diagram of visual tree hierarchy

Rendering Order

The visual tree determines the rendering order of WPF visual and drawing objects. The order of traversal starts with the root visual, which is the top-most node in the visual tree. The root visual’s children are then traversed, left to right. If a visual has children, its children are traversed before the visual’s siblings. This means that the content of a child visual is rendered in front of the visual's own content.

Diagram of visual tree rendering order

Diagram of visual tree rendering order

Root Visual

The root visual is the top-most element in a visual tree hierarchy. In most applications, the base class of the root visual is either Window or NavigationWindow. However, if you were hosting visual objects in a Win32 application, the root visual would be the top-most visual you were hosting in the Win32 window. For more information, see Tutorial: Hosting Visual Objects in a Win32 Application.

Relationship to the Logical Tree

The logical tree in WPF represents the elements of an application at run time. Although you do not manipulate this tree directly, this view of the application is useful for understanding property inheritance and event routing. Unlike the visual tree, the logical tree can represent non-visual data objects, such as ListItem. In many cases, the logical tree maps very closely to an application's markup definitions. The following code shows a DockPanel element defined in markup.

<DockPanel>
  <ListBox>
    <ListBoxItem>Dog</ListBoxItem>
    <ListBoxItem>Cat</ListBoxItem>
    <ListBoxItem>Fish</ListBoxItem>
  </ListBox>
  <Button Click="OnClick">OK</Button>
</DockPanel>

If you were to enumerate the logical objects that comprise the DockPanel element in the markup example, you would find the hierarchy of logical objects illustrated below:

Tree diagram

Diagram of logical tree

Both the visual tree and logical tree are synchronized with the current set of application elements, reflecting any addition, deletion, or modification of elements. However, the trees present different views of the application. Unlike the visual tree, the logical tree does not expand a control's ContentPresenter element. This means there is not a direct one-to-one correspondence between a logical tree and a visual tree for the same set of objects. In fact, invoking the LogicalTreeHelper object's GetChildren method and the VisualTreeHelper object's GetChild method using the same element as a parameter yields differing results.

For more information on the logical tree, see Trees in WPF.

Viewing the Visual Tree with XamlPad

The WPF tool, XamlPad, provides an option for viewing and exploring the visual tree that corresponds to the currently defined XAML content. Click the Show Visual Tree button on the menu bar to display the visual tree. The following illustrates the expansion of XAML content into visual tree nodes in the Visual Tree Explorer panel of XamlPad:

Visual Tree Explorer panel in XamlPad

Visual Tree Explorer panel in XamlPad

Notice how the LabelTextBox, and Button controls each display a separate visual object hierarchy in the Visual Tree Explorer panel of XamlPad. This is because WPF controls have a ControlTemplate that contains the visual tree of that control. When you explicitly reference a control, you implicitly reference its visual hierarchy.

Profiling Visual Performance

WPF provides a suite of performance profiling tools that allow you to analyze the run-time behavior of your application and determine the types of performance optimizations you can apply. The Visual Profiler tool provides a rich, graphical view of performance data by mapping directly to the application's visual tree. In this screenshot, the CPU Usage section of the Visual Profiler gives you a precise breakdown of an object's use of WPF services, such as rendering and layout.

Visual Profiler display output

Visual Profiler display output

Visual Rendering Behavior

WPF introduces several features that affect the rendering behavior of visual objects: retained mode graphics, vector graphics, and device independent graphics.

Retained Mode Graphics

One of the keys to understanding the role of the Visual object is to understand the difference between immediate mode and retained modegraphics systems. A standard Win32 application based on GDI or GDI+ uses an immediate mode graphics system. This means that the application is responsible for repainting the portion of the client area that is invalidated, due to an action such as a window being resized, or an object changing its visual appearance.

Diagram of Win32 rendering sequence

Diagram of Win32 rendering sequence

In contrast, WPF uses a retained mode system. This means application objects that have a visual appearance define a set of serialized drawing data. Once the drawing data is defined, the system is responsible thereafter for responding to all repaint requests for rendering the application objects. Even at run time, you can modify or create application objects, and still rely on the system for responding to paint requests. The power in a retained mode graphics system is that drawing information is always persisted in a serialized state by the application, but rendering responsibility left to the system. The following diagram shows how the application relies on WPF for responding to paint requests.

Diagram of WPF rendering sequence

Diagram of WPF rendering sequence

Intelligent Redrawing

One of the biggest benefits in using retained mode graphics is that WPF can efficiently optimize what needs to be redrawn in the application. Even if you have a complex scene with varying levels of opacity, you generally do not need to write special-purpose code to optimize redrawing. Compare this with Win32 programming in which you can spend a great deal of effort in optimizing your application by minimizing the amount of redrawing in the update region. See Redrawing in the Update Region for an example of the type of complexity involved in optimizing redrawing in Win32 applications.

Vector Graphics

WPF uses vector graphics as its rendering data format. Vector graphics—which include Scalable Vector Graphics (SVG), Windows metafiles (.wmf), and TrueType fonts—store rendering data and transmit it as a list of instructions that describe how to recreate an image using graphics primitives. For example, TrueType fonts are outline fonts that describe a set of lines, curves, and commands, rather than an array of pixels. One of the key benefits of vector graphics is the ability to scale to any size and resolution.

Unlike vector graphics, bitmap graphics store rendering data as a pixel-by-pixel representation of an image, pre-rendered for a specific resolution. One of the key differences between bitmap and vector graphic formats is fidelity to the original source image. For example, when the size of a source image is modified, bitmap graphics systems stretch the image, whereas vector graphics systems scale the image, preserving the image fidelity.

The following illustration shows a source image that has been resized by 300%. Notice the distortions that appear when the source image is stretched as a bitmap graphics image rather than scaled as a vector graphics image.

Differences between raster and vector graphics

Differences between raster and vector graphics

The following markup shows two Path elements defined. The second element uses a ScaleTransform to resize the drawing instructions of the first element by 300%. Notice that the drawing instructions in the Path elements remain unchanged.

<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" />

<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" >
  <Path.RenderTransform>
    <ScaleTransform ScaleX="3.0" ScaleY="3.0" />
  </Path.RenderTransform>
</Path>

About Resolution and Device-Independent Graphics

There are two system factors that determine the size of text and graphics on your screen: resolution and DPI. Resolution describes the number of pixels that appear on the screen. As the resolution gets higher, pixels get smaller, causing graphics and text to appear smaller. A graphic displayed on a monitor set to 1024 x 768 will appear much smaller when the resolution is changed to 1600 x 1200.

The other system setting, DPI, describes the size of a screen inch in pixels. Most Windows systems have a DPI of 96, which means a screen inch is 96 pixels. Increasing the DPI setting makes the screen inch larger; decreasing the DPI makes the screen inch smaller. This means that a screen inch isn't the same size as a real-world inch; on most systems, it's probably not. As you increase the DPI, DPI-aware graphics and text become larger because you've increased the size of the screen inch. Increasing the DPI can make text easier to read, especially at high resolutions.

Not all applications are DPI-aware: some use hardware pixels as the primary unit of measurement; changing the system DPI has no effect on these applications. Many other applications use DPI-aware units to describe font sizes, but use pixels to describe everything else. Making the DPI too small or too large can cause layout problems for these applications, because the applications' text scales with the system's DPI setting, but the applications' UI does not. This problem has been eliminated for applications developed using WPF.

WPF supports automatic scaling by using the device independent pixel as its primary unit of measurement, instead of hardware pixels; graphics and text scale properly without any extra work from the application developer. The following illustration shows an example of how WPF text and graphics are appear at different DPI settings.

Graphics and text at different DPI settings

Graphics and text at different DPI settings

VisualTreeHelper Class

The VisualTreeHelper class is a static helper class that provides low-level functionality for programming at the visual object level, which is useful in very specific scenarios, such as developing high-performance custom controls. In most case, the higher-level WPF framework objects, such as Canvasand TextBlock, offer greater flexibility and ease of use.

Hit Testing

The VisualTreeHelper class provides methods for hit testing on visual objects when the default hit test support does not meet your needs. You can use the HitTest methods in the VisualTreeHelper class to determine whether a geometry or point coordinate value is within the boundary of a given object, such as a control or graphic element. For example, you could use hit testing to determine whether a mouse click within the bounding rectangle of an object falls within the geometry of a circle You can also choose to override the default implementation of hit testing to perform your own custom hit test calculations.

For more information on hit testing, see Hit Testing in the Visual Layer.

Enumerating the Visual Tree

The VisualTreeHelper class provides functionality for enumerating the members of a visual tree. To retrieve a parent, call the GetParent method. To retrieve a child, or direct descendant, of a visual object, call the GetChild method. This method returns a child Visual of the parent at the specified index.

The following example shows how to enumerate all the descendants of a visual object, which is a technique you might want to use if you were interested in serializing all the rendering information of a visual object hierarchy.

// Enumerate all the descendants of the visual object.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
    {
        // Retrieve child visual at specified index value.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);

        // Do processing of the child visual object.

        // Enumerate children of the child visual object.
        EnumVisual(childVisual);
    }
}

In most cases, the logical tree is a more useful representation of the elements in a WPF application. Although you do not modify the logical tree directly, this view of the application is useful for understanding property inheritance and event routing. Unlike the visual tree, the logical tree can represent non-visual data objects, such as ListItem. For more information on the logical tree, see Trees in WPF.

The VisualTreeHelper class provides methods for returning the bounding rectangle of visual objects. You can return the bounding rectangle of a visual object by calling GetContentBounds. You can return the bounding rectangle of all the descendants of a visual object, including the visual object itself, by calling GetDescendantBounds. The following code shows how you would calculate the bounding rectangle of a visual object and all its descendants.

// Return the bounding rectangle of the parent visual object and all of its descendants.
Rect rectBounds = VisualTreeHelper.GetDescendantBounds(parentVisual);



Graphics



Bitmap Effects


Bitmap Effects Overview


Bitmap effects enable designers and developers to apply visual effects to rendered Windows Presentation Foundation (WPF) content. For example, bitmap effects allow you to easily apply a DropShadowBitmapEffect effect or a blur effect to an image or a button.

System_CAPS_importantImportant

In the .NET Framework 4 or later, the BitmapEffect class is obsolete. If you try to use the BitmapEffect class, you will get an obsolete exception. The non-obsolete alternative to the BitmapEffect class is the Effect class. In most situations, the Effect class is significantly faster.

WPF Bitmap Effects

Bitmap effects (BitmapEffect object) are simple pixel processing operations. A bitmap effect takes a BitmapSource as an input and produces a new BitmapSource after applying the effect, such as a blur or drop shadow. Each bitmap effect exposes properties that can control the filtering properties, such as Radius of BlurBitmapEffect.

As a special case, in WPF, effects can be set as properties on live Visual objects, such as a Button or TextBox. The pixel processing is applied and rendered at run-time. In this case, at the time of rendering, a Visual is automatically converted to its BitmapSource equivalent and is fed as input to the BitmapEffect. The output replaces the Visual object's default rendering behavior. This is why BitmapEffect objects force visuals to render in software only i.e. no hardware acceleration on visuals when effects are applied.

System_CAPS_noteNote

 WPF bitmap effects are rendered in software mode. Any object that applies an effect will also be rendered in software. Performance is degraded the most when using Bitmap effects on large visuals or animating properties of a Bitmap effect. This is not to say that you should not use Bitmap effects in this way at all, but you should use caution and test thoroughly to ensure that your users are getting the experience you expect.

System_CAPS_noteNote

 WPF bitmap effects do not support partial trust execution. An application must have full trust permissions to use bitmap effects.

How to Apply an Effect

BitmapEffect is a property on Visual. Therefore applying effects to Visuals, such as a ButtonImageDrawingVisual, or UIElement, is as easy as setting a property. BitmapEffect can be set to a single BitmapEffect object or multiple effects can be chained by using the BitmapEffectGroup object.

The following example demonstrates how to apply a BitmapEffect in Extensible Application Markup Language (XAML).

<Button  Width="200">You Can't Read This!
  <Button.BitmapEffect>

  <!-- <BitmapEffectGroup> would go here if you wanted to apply more 
         then one effect to the Button. However, in this example only  
         one effect is being applied so BitmapEffectGroup does not need  
         to be included. -->

    <!-- The larger the Radius, the more blurring. The default range is 20.
         In addition, the KernelType is set to a box kernel. A box kernel
         creates less disruption (less blur) then the default Gaussian kernel. -->
    <BlurBitmapEffect Radius="10" KernelType="Box" />

  </Button.BitmapEffect>
</Button>

The following example demonstrates how to apply a BitmapEffect in code.

// Get a reference to the Button.
Button myButton = (Button)sender;

// Initialize a new BlurBitmapEffect that will be applied
// to the Button.
BlurBitmapEffect myBlurEffect = new BlurBitmapEffect();

// Set the Radius property of the blur. This determines how 
// blurry the effect will be. The larger the radius, the more
// blurring. 
myBlurEffect.Radius = 10;

// Set the KernelType property of the blur. A KernalType of "Box"
// creates less blur than the Gaussian kernal type.
myBlurEffect.KernelType = KernelType.Box;

// Apply the bitmap effect to the Button.
myButton.BitmapEffect = myBlurEffect;
System_CAPS_noteNote

When a BitmapEffect is applied to a layout container, such as DockPanel or Canvas, the effect is applied to the visual tree of the element or visual, including all of its child elements.

WPF also provides unmanaged interfaces to create custom effects that can be used in managed WPF applications. For additional reference material for creating custom bitmap effects, see the Unmanaged WPF Bitmap Effect documentation.




Brushes


WPF Brushes Overview


Everything visible on your screen is visible because it was painted by a brush. For example, a brush is used to describe the background of a button, the foreground of text, and the fill of a shape. This topic introduces the concepts of painting with Windows Presentation Foundation (WPF) brushes and provides examples. Brushes enable you to paint user interface (UI) objects with anything from simple, solid colors to complex sets of patterns and images.

Painting with a Brush

Brush "paints" an area with its output. Different brushes have different types of output. Some brushes paint an area with a solid color, others with a gradient, pattern, image, or drawing. The following illustration shows examples of each of the different Brush types.

Brush types

Brush examples

Most visual objects enable you to specify how they are painted. The following table lists some common objects and properties with which you can use a Brush.

The following sections describe the different Brush types and provide an example of each.

Paint with a Solid Color

SolidColorBrush paints an area with a solid Color. There are a variety of ways to specify the Color of a SolidColorBrush: for example, you can specify its alpha, red, blue, and green channels or use one of the predefined color provided by the Colors class.

The following example uses a SolidColorBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A rectangle painted using a SolidColorBrush

A Rectangle painted using a SolidColorBrush

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create a SolidColorBrush and use it to
// paint the rectangle.
SolidColorBrush myBrush = new SolidColorBrush(Colors.Red);
exampleRectangle.Fill = myBrush;
<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <SolidColorBrush Color="Red" />
  </Rectangle.Fill>
</Rectangle>

For more information about the SolidColorBrush class, see Painting with Solid Colors and Gradients Overview.

Paint with a Linear Gradient

LinearGradientBrush paints an area with a linear gradient. A linear gradient blends two or more colors across a line, the gradient axis. You use GradientStop objects to specify the colors in the gradient and their positions.

The following example uses a LinearGradientBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A rectangle painted using a LinearGradientBrush

A Rectangle painted using a LinearGradientBrush

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create a LinearGradientBrush and use it to
// paint the rectangle.
LinearGradientBrush myBrush = new LinearGradientBrush();
myBrush.GradientStops.Add(new GradientStop(Colors.Yellow, 0.0));
myBrush.GradientStops.Add(new GradientStop(Colors.Orange, 0.5));
myBrush.GradientStops.Add(new GradientStop(Colors.Red, 1.0));

exampleRectangle.Fill = myBrush;
<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <LinearGradientBrush>
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Orange" Offset="0.5" />
      <GradientStop Color="Red" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>

For more information about the LinearGradientBrush class, see Painting with Solid Colors and Gradients Overview.

Paint with a Radial Gradient

RadialGradientBrush paints an area with a radial gradient. A radial gradient blends two or more colors across a circle. As with the LinearGradientBrush class, you use GradientStop objects to specify the colors in the gradient and their positions.

The following example uses a RadialGradientBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A rectangle painted using a RadialGradientBrush

A Rectangle painted using a RadialGradientBrush

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create a RadialGradientBrush and use it to
// paint the rectangle.
RadialGradientBrush myBrush = new RadialGradientBrush();
myBrush.GradientOrigin = new Point(0.75, 0.25);
myBrush.GradientStops.Add(new GradientStop(Colors.Yellow, 0.0));
myBrush.GradientStops.Add(new GradientStop(Colors.Orange, 0.5));
myBrush.GradientStops.Add(new GradientStop(Colors.Red, 1.0));

exampleRectangle.Fill = myBrush;
<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <RadialGradientBrush GradientOrigin="0.75,0.25">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Orange" Offset="0.5" />
      <GradientStop Color="Red" Offset="1.0" />
    </RadialGradientBrush>
  </Rectangle.Fill>
</Rectangle>

For more information about the RadialGradientBrush class, see Painting with Solid Colors and Gradients Overview.

Paint with an Image

An ImageBrush paints an area with a ImageSource.

The following example uses an ImageBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A Rectangle painted by an ImageBrush

A Rectangle painted using a Image

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create an ImageBrush and use it to
// paint the rectangle.
ImageBrush myBrush = new ImageBrush();
myBrush.ImageSource = 
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

exampleRectangle.Fill = myBrush;
<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg"  />
  </Rectangle.Fill>
</Rectangle>

For more information about the ImageBrush class, see Painting with Images, Drawings, and Visuals.

Paint with a Drawing

DrawingBrush paints an area with a Drawing. A Drawing can contain shapes, images, text, and media.

The following example uses a DrawingBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A rectangle painted using a DrawingBrush

A Rectangle painted using a DrawingBrush

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create a DrawingBrush and use it to
// paint the rectangle.
DrawingBrush myBrush = new DrawingBrush();

GeometryDrawing backgroundSquare =
    new GeometryDrawing(
        Brushes.White,
        null,
        new RectangleGeometry(new Rect(0, 0, 100, 100)));

GeometryGroup aGeometryGroup = new GeometryGroup();
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));

LinearGradientBrush checkerBrush = new LinearGradientBrush();
checkerBrush.GradientStops.Add(new GradientStop(Colors.Black, 0.0));
checkerBrush.GradientStops.Add(new GradientStop(Colors.Gray, 1.0));

GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);

DrawingGroup checkersDrawingGroup = new DrawingGroup();
checkersDrawingGroup.Children.Add(backgroundSquare);
checkersDrawingGroup.Children.Add(checkers);

myBrush.Drawing = checkersDrawingGroup;
myBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
myBrush.TileMode = TileMode.Tile;

exampleRectangle.Fill = myBrush;
<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <DrawingBrush Viewport="0,0,0.25,0.25" TileMode="Tile">
      <DrawingBrush.Drawing>
        <DrawingGroup>
          <GeometryDrawing Brush="White">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0,0,100,100" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>

          <GeometryDrawing>
            <GeometryDrawing.Geometry>
              <GeometryGroup>
                <RectangleGeometry Rect="0,0,50,50" />
                <RectangleGeometry Rect="50,50,50,50" />
              </GeometryGroup>
            </GeometryDrawing.Geometry>
            <GeometryDrawing.Brush>
              <LinearGradientBrush>
                <GradientStop Offset="0.0" Color="Black" />
                <GradientStop Offset="1.0" Color="Gray" />
              </LinearGradientBrush>
            </GeometryDrawing.Brush>
          </GeometryDrawing>
        </DrawingGroup>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Rectangle.Fill>
</Rectangle>

For more information about the DrawingBrush class, see Painting with Images, Drawings, and Visuals.

Paint with a Visual

VisualBrush paints an area with a Visual object. Examples of Visual objects include ButtonPage, and MediaElement. A VisualBrush also enables you to project content from one portion of your application into another area; it's very useful for creating reflection effects and magnifying portions of the screen.

The following example uses a VisualBrush to paint the Fill of a Rectangle. The following illustration shows the painted rectangle.

A rectangle painted using a VisualBrush

A Rectangle painted using a VisualBrush

Rectangle exampleRectangle = new Rectangle();
exampleRectangle.Width = 75;
exampleRectangle.Height = 75;

// Create a VisualBrush and use it
// to paint the rectangle.
VisualBrush myBrush = new VisualBrush();

//
// Create the brush's contents.
//
StackPanel aPanel = new StackPanel();

// Create a DrawingBrush and use it to
// paint the panel.
DrawingBrush myDrawingBrushBrush = new DrawingBrush();
GeometryGroup aGeometryGroup = new GeometryGroup();
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));
RadialGradientBrush checkerBrush = new RadialGradientBrush();
checkerBrush.GradientStops.Add(new GradientStop(Colors.MediumBlue, 0.0));
checkerBrush.GradientStops.Add(new GradientStop(Colors.White, 1.0));
GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);
myDrawingBrushBrush.Drawing = checkers;
aPanel.Background = myDrawingBrushBrush;

// Create some text.
TextBlock someText = new TextBlock();
someText.Text = "Hello, World";
FontSizeConverter fSizeConverter = new FontSizeConverter();
someText.FontSize = (double)fSizeConverter.ConvertFromString("10pt");
someText.Margin = new Thickness(10);

aPanel.Children.Add(someText);

myBrush.Visual = aPanel;
exampleRectangle.Fill = myBrush;

<Rectangle Width="75" Height="75">
  <Rectangle.Fill>
    <VisualBrush TileMode="Tile">
      <VisualBrush.Visual>
        <StackPanel>
          <StackPanel.Background>
            <DrawingBrush>
              <DrawingBrush.Drawing>
                <GeometryDrawing>
                  <GeometryDrawing.Brush>
                    <RadialGradientBrush>
                      <GradientStop Color="MediumBlue" Offset="0.0" />
                      <GradientStop Color="White" Offset="1.0" />
                    </RadialGradientBrush>
                  </GeometryDrawing.Brush>
                  <GeometryDrawing.Geometry>
                    <GeometryGroup>
                      <RectangleGeometry Rect="0,0,50,50" />
                      <RectangleGeometry Rect="50,50,50,50" />
                    </GeometryGroup>
                  </GeometryDrawing.Geometry>
                </GeometryDrawing>
              </DrawingBrush.Drawing>
            </DrawingBrush>
          </StackPanel.Background>
          <TextBlock FontSize="10pt" Margin="10">Hello, World!</TextBlock>
        </StackPanel>
      </VisualBrush.Visual>
    </VisualBrush>
  </Rectangle.Fill>
</Rectangle>

For more information about the VisualBrush class, see Painting with Images, Drawings, and Visuals.

Paint using Predefined and System Brushes

For convenience, Windows Presentation Foundation (WPF) provides a set of predefined and system brushes that you can use to paint objects.

Common Brush Features

Brush objects provide an Opacity property that can be used to make a brush transparent or partially transparent. An Opacity value of 0 makes a brush completely transparent, while an Opacity value of 1 makes a brush completely opaque. The following example uses the Opacity property to make a SolidColorBrush 25 percent opaque.

<Rectangle Width="100" Height="100">
  <Rectangle.Fill>
    <SolidColorBrush Color="Blue" Opacity="0.25" />
  </Rectangle.Fill>
</Rectangle>
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 100;
myRectangle.Height = 100;
SolidColorBrush partiallyTransparentSolidColorBrush
    = new SolidColorBrush(Colors.Blue);
partiallyTransparentSolidColorBrush.Opacity = 0.25;
myRectangle.Fill = partiallyTransparentSolidColorBrush;

If the brush contains colors that are partially transparent, the opacity value of the color is combined through multiplication with the opacity value of the brush. For example, if a brush has an opacity value of 0.5 and a color used in the brush also has an opacity value of 0.5, the output color has an opacity value of 0.25.

System_CAPS_noteNote

It's more efficient to change the opacity value of a brush than it is to change the opacity of an entire element using its UIElement.Opacityproperty.

You can rotate, scale, skew, and translate a brush's content by using its Transform or RelativeTransform properties. For more information, see Brush Transformation Overview.

Because they are Animatable objects, Brush objects can be animated. For more information, see Animation Overview.

Freezable Features

Because it inherits from the Freezable class, the Brush class provides several special features: Brush objects can be declared as resources, shared among multiple objects, and cloned. In addition, all the Brush types except VisualBrush can be made read-only to improve performance and made thread-safe.

For more information about the different features provided by Freezable objects, see Freezable Objects Overview.

For more information on why VisualBrush objects cannot be frozen, see the VisualBrush type page.




Brush Transformation Overview


The Brush class provides two transformation properties: Transform and RelativeTransform. The properties enable you to rotate, scale, skew, and translate a brush's contents. This topic describes the differences between these two properties and provides examples of their usage.

Prerequisites

To understand this topic, you should understand the features of the brush that you are transforming. For LinearGradientBrush and RadialGradientBrush, see the Painting with Solid Colors and Gradients Overview. For ImageBrushDrawingBrush, or VisualBrush, see Painting with Images, Drawings, and Visuals. You should also be familiar with the 2D transforms described in the Transforms Overview.

Differences between the Transform and RelativeTransform Properties

When you apply a transform to a brush's Transform property, you need to know the size of the painted area if you want to transform the brush contents about its center. Suppose the painted area is 200 device independent pixels wide and 150 tall. If you used a RotateTransform to rotate the brush's output 45 degrees about its center, you'd give the RotateTransform a CenterX of 100 and a CenterY of 75.

When you apply a transform to a brush's RelativeTransform property, that transform is applied to the brush before its output is mapped to the painted area. The following list describes the order in which a brush’s contents are processed and transformed.

  1. Process the brush’s contents. For a GradientBrush, this means determining the gradient area. For a TileBrush, the Viewbox is mapped to the Viewport. This becomes the brush’s output.

  2. Project the brush’s output onto the 1 x 1 transformation rectangle.

  3. Apply the brush’s RelativeTransform, if it has one.

  4. Project the transformed output onto the area to paint.

  5. Apply the brush’s Transform, if it has one.

Because the RelativeTransform is applied while the brush’s output is mapped to a 1 x 1 rectangle, transform center and offset values appear to be relative. For example, if you used a RotateTransform to rotate the brush's output 45 degrees about its center, you'd give the RotateTransform a CenterX of 0.5 and a CenterY of 0.5.

The following illustration shows the output of several brushes that have been rotated by 45 degrees using the RelativeTransform and Transformproperties.

RelativeTransform and Transform properties

Using RelativeTransform with a TileBrush

Because tile brushes are more complex than other brushes, applying a RelativeTransform to one might produce unexpected results. For example, take the following image.

The source image

The following example uses an ImageBrush to paint a rectangular area with the preceding image. It applies a RotateTransform to the ImageBrushobject's RelativeTransform property, and sets its Stretch property to UniformToFill, which should preserve the image's aspect ratio when it is stretched to completely fill the rectangle.

<Rectangle Width="200" Height="100" Stroke="Black" StrokeThickness="1">
  <Rectangle.Fill>
    <ImageBrush Stretch="UniformToFill">
      <ImageBrush.ImageSource>
        <BitmapImage UriSource="sampleImages\square.jpg" />
      </ImageBrush.ImageSource>
      <ImageBrush.RelativeTransform>
        <RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
      </ImageBrush.RelativeTransform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

This example produces the following output:

The transformed output

Notice that the image is distorted, even though the brush's Stretch was set to UniformToFill. That's because the relative transform is applied after the brush's Viewbox is mapped to its Viewport. The following list describes each step of the process:

  1. Project the brush's contents (Viewbox) onto its base tile (Viewport) using the brush's Stretch setting.

    Stretch the Viewbox to fit the Viewport
  2. Project the base tile onto the 1 x 1 transformation rectangle.

    Map the Viewport to the transformation rectangle
  3. Apply the RotateTransform.

    Apply the relative transform
  4. Project the transformed base tile onto the area to paint.

    Project the transformed brush onto the output area

Example: Rotate an ImageBrush 45 Degrees

The following example applies a RotateTransform to the RelativeTransform property of an ImageBrush. The RotateTransform object's CenterX and CenterY properties are both set to 0.5, the relative coordinates of the content's center point. As a result, the brush's contents are rotated about its center.

//
// Create an ImageBrush with a relative transform and
// use it to paint a rectangle.
//
ImageBrush relativeTransformImageBrush = new ImageBrush();
relativeTransformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's RelativeTransform property.
RotateTransform aRotateTransform = new RotateTransform();
aRotateTransform.CenterX = 0.5; 
aRotateTransform.CenterY = 0.5;
aRotateTransform.Angle = 45;
relativeTransformImageBrush.RelativeTransform = aRotateTransform;

// Use the brush to paint a rectangle.
Rectangle relativeTransformImageBrushRectangle = new Rectangle();
relativeTransformImageBrushRectangle.Width = 175;
relativeTransformImageBrushRectangle.Height = 90;
relativeTransformImageBrushRectangle.Stroke = Brushes.Black;
relativeTransformImageBrushRectangle.Fill = relativeTransformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.RelativeTransform>
        <RotateTransform CenterX="0.5" CenterY="0.5" Angle="45" />
      </ImageBrush.RelativeTransform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

The next example also applies a RotateTransform to an ImageBrush, but uses the Transform property instead of the RelativeTransform property. To rotate the brush about its center, the RotateTransform object's CenterX and CenterY must be set to absolute coordinates. Because the rectangle being painted by the brush is 175 by 90 pixels, its center point is (87.5, 45).

//
// Create an ImageBrush with a transform and
// use it to paint a rectangle.
//
ImageBrush transformImageBrush = new ImageBrush();
transformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's Transform property.
RotateTransform anotherRotateTransform = new RotateTransform();
anotherRotateTransform.CenterX = 87.5;
anotherRotateTransform.CenterY = 45;
anotherRotateTransform.Angle = 45;
transformImageBrush.Transform = anotherRotateTransform;

// Use the brush to paint a rectangle.
Rectangle transformImageBrushRectangle = new Rectangle();
transformImageBrushRectangle.Width = 175;
transformImageBrushRectangle.Height = 90;
transformImageBrushRectangle.Stroke = Brushes.Black;
transformImageBrushRectangle.Fill = transformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.Transform>
        <RotateTransform CenterX="87.5" CenterY="45" Angle="45" />
      </ImageBrush.Transform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

The following illustration shows the brush without a transform, with the transform applied to the RelativeTransform property, and with the transform applied to the Transform property.

Brush RelativeTransform and Transform settings

This example is part of a larger sample. For the complete sample, see the Brushes Sample. For more information about brushes, see the WPF Brushes Overview.




Brush Transformation Overview


The Brush class provides two transformation properties: Transform and RelativeTransform. The properties enable you to rotate, scale, skew, and translate a brush's contents. This topic describes the differences between these two properties and provides examples of their usage.

Prerequisites

To understand this topic, you should understand the features of the brush that you are transforming. For LinearGradientBrush and RadialGradientBrush, see the Painting with Solid Colors and Gradients Overview. For ImageBrushDrawingBrush, or VisualBrush, see Painting with Images, Drawings, and Visuals. You should also be familiar with the 2D transforms described in the Transforms Overview.

Differences between the Transform and RelativeTransform Properties

When you apply a transform to a brush's Transform property, you need to know the size of the painted area if you want to transform the brush contents about its center. Suppose the painted area is 200 device independent pixels wide and 150 tall. If you used a RotateTransform to rotate the brush's output 45 degrees about its center, you'd give the RotateTransform a CenterX of 100 and a CenterY of 75.

When you apply a transform to a brush's RelativeTransform property, that transform is applied to the brush before its output is mapped to the painted area. The following list describes the order in which a brush’s contents are processed and transformed.

  1. Process the brush’s contents. For a GradientBrush, this means determining the gradient area. For a TileBrush, the Viewbox is mapped to the Viewport. This becomes the brush’s output.

  2. Project the brush’s output onto the 1 x 1 transformation rectangle.

  3. Apply the brush’s RelativeTransform, if it has one.

  4. Project the transformed output onto the area to paint.

  5. Apply the brush’s Transform, if it has one.

Because the RelativeTransform is applied while the brush’s output is mapped to a 1 x 1 rectangle, transform center and offset values appear to be relative. For example, if you used a RotateTransform to rotate the brush's output 45 degrees about its center, you'd give the RotateTransform a CenterX of 0.5 and a CenterY of 0.5.

The following illustration shows the output of several brushes that have been rotated by 45 degrees using the RelativeTransform and Transformproperties.

RelativeTransform and Transform properties

Using RelativeTransform with a TileBrush

Because tile brushes are more complex than other brushes, applying a RelativeTransform to one might produce unexpected results. For example, take the following image.

The source image

The following example uses an ImageBrush to paint a rectangular area with the preceding image. It applies a RotateTransform to the ImageBrushobject's RelativeTransform property, and sets its Stretch property to UniformToFill, which should preserve the image's aspect ratio when it is stretched to completely fill the rectangle.

<Rectangle Width="200" Height="100" Stroke="Black" StrokeThickness="1">
  <Rectangle.Fill>
    <ImageBrush Stretch="UniformToFill">
      <ImageBrush.ImageSource>
        <BitmapImage UriSource="sampleImages\square.jpg" />
      </ImageBrush.ImageSource>
      <ImageBrush.RelativeTransform>
        <RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
      </ImageBrush.RelativeTransform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

This example produces the following output:

The transformed output

Notice that the image is distorted, even though the brush's Stretch was set to UniformToFill. That's because the relative transform is applied after the brush's Viewbox is mapped to its Viewport. The following list describes each step of the process:

  1. Project the brush's contents (Viewbox) onto its base tile (Viewport) using the brush's Stretch setting.

    Stretch the Viewbox to fit the Viewport
  2. Project the base tile onto the 1 x 1 transformation rectangle.

    Map the Viewport to the transformation rectangle
  3. Apply the RotateTransform.

    Apply the relative transform
  4. Project the transformed base tile onto the area to paint.

    Project the transformed brush onto the output area

Example: Rotate an ImageBrush 45 Degrees

The following example applies a RotateTransform to the RelativeTransform property of an ImageBrush. The RotateTransform object's CenterX and CenterY properties are both set to 0.5, the relative coordinates of the content's center point. As a result, the brush's contents are rotated about its center.

//
// Create an ImageBrush with a relative transform and
// use it to paint a rectangle.
//
ImageBrush relativeTransformImageBrush = new ImageBrush();
relativeTransformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's RelativeTransform property.
RotateTransform aRotateTransform = new RotateTransform();
aRotateTransform.CenterX = 0.5; 
aRotateTransform.CenterY = 0.5;
aRotateTransform.Angle = 45;
relativeTransformImageBrush.RelativeTransform = aRotateTransform;

// Use the brush to paint a rectangle.
Rectangle relativeTransformImageBrushRectangle = new Rectangle();
relativeTransformImageBrushRectangle.Width = 175;
relativeTransformImageBrushRectangle.Height = 90;
relativeTransformImageBrushRectangle.Stroke = Brushes.Black;
relativeTransformImageBrushRectangle.Fill = relativeTransformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.RelativeTransform>
        <RotateTransform CenterX="0.5" CenterY="0.5" Angle="45" />
      </ImageBrush.RelativeTransform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

The next example also applies a RotateTransform to an ImageBrush, but uses the Transform property instead of the RelativeTransform property. To rotate the brush about its center, the RotateTransform object's CenterX and CenterY must be set to absolute coordinates. Because the rectangle being painted by the brush is 175 by 90 pixels, its center point is (87.5, 45).

//
// Create an ImageBrush with a transform and
// use it to paint a rectangle.
//
ImageBrush transformImageBrush = new ImageBrush();
transformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's Transform property.
RotateTransform anotherRotateTransform = new RotateTransform();
anotherRotateTransform.CenterX = 87.5;
anotherRotateTransform.CenterY = 45;
anotherRotateTransform.Angle = 45;
transformImageBrush.Transform = anotherRotateTransform;

// Use the brush to paint a rectangle.
Rectangle transformImageBrushRectangle = new Rectangle();
transformImageBrushRectangle.Width = 175;
transformImageBrushRectangle.Height = 90;
transformImageBrushRectangle.Stroke = Brushes.Black;
transformImageBrushRectangle.Fill = transformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.Transform>
        <RotateTransform CenterX="87.5" CenterY="45" Angle="45" />
      </ImageBrush.Transform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

The following illustration shows the brush without a transform, with the transform applied to the RelativeTransform property, and with the transform applied to the Transform property.

Brush RelativeTransform and Transform settings

This example is part of a larger sample. For the complete sample, see the Brushes Sample. For more information about brushes, see the WPF Brushes Overview.




Opacity Masks Overview


Opacity masks enable you to make portions of an element or visual either transparent or partially transparent. To create an opacity mask, you apply a Brush to the OpacityMask property of an element or Visual. The brush is mapped to the element or visual, and the opacity value of each brush pixel is used to determine the resulting opacity of each corresponding pixel of the element or visual.

This topic contains the following sections.

Prerequisites

This overview assumes that you are familiar with Brush objects. For an introduction to using brushes, see Painting with Solid Colors and Gradients Overview. For information about ImageBrush and DrawingBrush, see Painting with Images, Drawings, and Visuals.

Creating Visual Effects with Opacity Masks

An opacity mask works by mapping its contents to the element or visual. The alpha channel of each of the brush's pixels are then used to determine the resulting opacity of the element or visual's corresponding pixels; the actual color of the brush is ignored. If a given portion of the brush is transparent, the corresponding portion of the element or visual becomes transparent. If a given portion of the brush is opaque, the opacity of the corresponding portion of the element or visual is unchanged. The opacity specified by the opacity mask is combined with any opacity settings present in the element or visual. For example, if an element is 25 percent opaque and an opacity mask is applied that transitions from fully opaque to fully transparent, the result is an element that transitions from 25 percent opacity to fully transparent.

System_CAPS_noteNote

Although the examples in this overview demonstrate the use of opacity masks on image elements, an opacity mask may be applied to any element or Visual, including panels and controls.

Opacity masks are used to create interesting visual effects, such as to create images or buttons that fade from view, to add textures to elements, or to combine gradients to produce glass-like surfaces. The following illustration demonstrates the use of an opacity mask. A checkered background is used to show the transparent portions of the mask.

Object with a LinearGradientBrush opacity mask

Opacity masking example

Creating an Opacity Mask

To create an opacity mask, you create a Brush and apply it to the OpacityMask property of an element or visual. You can use any type of Brush as an opacity mask.

  • LinearGradientBrushRadialGradientBrush: Used to make an element or visual fade from view.

    The following image shows a LinearGradientBrush used as an opacity mask.

    An object with an LinearGradientBrush opacity mask

    LinearGradientBrush Opacity Masking Example

  • ImageBrush: Used to create texture and soft or torn edge effects.

    The following image shows an ImageBrush used as an opacity mask.

    Object that has an ImageBrush opacity mask

    LinearGradientBrush opacity masking example

  • DrawingBrush: Used to create complex opacity masks from patterns of shapes, images, and gradients.

    The following image shows a DrawingBrush used as an opacity mask.

    Object with a DrawingBrush opacity mask

    DrawingBrush opacity masking example

The gradient brushes (LinearGradientBrush and RadialGradientBrush) are particularly well-suited for use as an opacity mask. Because a SolidColorBrush fills an area with a uniform color, they make poor opacity masks; using a SolidColorBrush is equivalent to setting the element's or visual's OpacityMask property.

Using a Gradient as an Opacity Mask

To create a gradient fill, you specify two or more gradient stops. Each gradient stop contains describes a color and a position (see Painting with Solid Colors and Gradients Overview for more information about creating and using gradients). The process is the same when using a gradient as an opacity mask, except that, instead of blending colors, the opacity mask gradient blends alpha channel values. So the actual color of the gradient's contents do not matter; only the alpha channel, or opacity, of each color matters. The following is an example.

<!--With the opacity mask:--> 
<Image
  Width="200" Height="150"
  Source="sampleImages\Waterlilies.jpg"
  Margin="10"
  HorizontalAlignment="Left"
  Grid.Column="2" Grid.Row="3">
  <Image.OpacityMask>
    <LinearGradientBrush StartPoint="0.1,0.1" EndPoint="0.75,0.75">
      <LinearGradientBrush.GradientStops>
        <GradientStop Offset="0" Color="Black"/>
        <GradientStop Offset="1" Color="Transparent"/>
      </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
  </Image.OpacityMask>
</Image>

Specifying Gradient Stops for an Opacity Mask

In the previous example, the system-defined color Black is used as the starting color of the gradient. Because all of the colors in the Colors class, except Transparent, are fully opaque, they can be used to simply define a starting color for a gradient opacity mask.

For additional control over alpha values when defining an opacity mask, you can specify the alpha channel of colors using ARGB hexadecimal notation in markup or using the Color.FromScRgb method.

  

Specifying Color Opacity in "XAML"

In Extensible Application Markup Language (XAML), you use ARGB hexadecimal notation to specify the opacity of individual colors. ARGB hexadecimal notation uses the following syntax:

 #aarrggbb 

The aa in the previous line represents a two-digit hexadecimal value used to specify the opacity of the color. The rrgg, and bb each represent a two digit hexadecimal value used to specify the amount of red, green, and blue in the color. Each hexadecimal digit may have a value from 0-9 or A-F. 0 is the smallest value, and F is the greatest. An alpha value of 00 specifies a color that is completely transparent, while an alpha value of FF creates a color that is fully opaque. In the following example, hexadecimal ARGB notation is used to specify two colors. The first is fully opaque, while the second is completely transparent.

<Canvas.OpacityMask>
  <RadialGradientBrush>
    <RadialGradientBrush.GradientStops>
      <GradientStop Offset="0" Color="#FF000000"/>
      <GradientStop Offset="1" Color="#00000000"/>
  </RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Canvas.OpacityMask>

Using an Image as an Opacity Mask

Images can also be used as an opacity mask. The following image shows an example. A checkered background is used to show the transparent portions of the mask.

An object with an ImageBrush opacity mask

Opacity masking example

To use an image as an opacity mask, use an ImageBrush to contain the image. When creating an image to be used as an opacity mask, save the image in a format that supports multiple levels of transparency, such as Portable Network Graphics (PNG). The following example shows the code used to create the previous illustration.

<!-- With the Opacity Mask-->
<Image
  Height="150"
  Width="200"
  Source="sampleImages/Waterlilies.jpg"
  HorizontalAlignment="Left"
  Margin="10"
  Grid.Column="2" Grid.Row="1">
  <Image.OpacityMask>
    <ImageBrush ImageSource="sampleImages/tornedges.png"/>
  </Image.OpacityMask>
</Image>

          

Using a Tiled Image as an Opacity Mask

In the following example, the same image is used with another ImageBrush, but the brush's tiling features are used to produce tiles of the image 50 pixels square.

<!-- With the Opacity Mask -->
<Image
  Height="150"
  Width="200"
  Source="sampleImages/Waterlilies.jpg"
  HorizontalAlignment="Left"
  Margin="10"
  Grid.Column="2" Grid.Row="2">

  <Image.OpacityMask>
    <ImageBrush
      Viewport="0,0,50,50"
      ViewportUnits="Absolute"
      TileMode="Tile" 
      ImageSource="sampleImages/tornedges.png"/>
  </Image.OpacityMask>
</Image>

           

Creating an Opacity Mask from a Drawing

Drawings can be used an opacity mask. The shapes contained within the drawing can themselves be filled with gradients, solid colors, images, or even other drawings. The following image shows an example of a drawing used as an opacity mask. A checkered background is used to show the transparent portions of the mask.

An object with a DrawingBrush opacity mask

DrawingBrush opacity masking example

To use a drawing as an opacity mask, use a DrawingBrush to contain the drawing. The following example shows the code used to create the previous illustration:

<!-- With the Opacity Mask-->
<Image 
      Grid.Row="4" Grid.Column="5"
      Height="150"
      Width="200"
      Source="sampleImages/Waterlilies.jpg">
  <Image.OpacityMask>
    <DrawingBrush>
      <DrawingBrush.Drawing>
        <GeometryDrawing>
          <GeometryDrawing.Brush>
            <RadialGradientBrush>
              <RadialGradientBrush.GradientStops>
                <GradientStop Offset="0" Color="Black" />
                <GradientStop Offset="1" Color="Transparent" />
              </RadialGradientBrush.GradientStops>
            </RadialGradientBrush>
          </GeometryDrawing.Brush>
          <GeometryDrawing.Geometry>
            <RectangleGeometry Rect="0.05,0.05 0.9,0.9" />
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Thickness="0.1" Brush="Black" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Image.OpacityMask>
</Image>

       

Using a Tiled Drawing as an Opacity Mask

Like the ImageBrush, the DrawingBrush can be made to tile its drawing. In the following example, a drawing brush is used to create a tiled opacity mask.

<!-- With the Opacity Mask-->
<Button
   Grid.Row="8" Grid.Column="5"
  Height="100"
  Width="200"
  FontFamily="MS Gothic"
  FontSize="16">
  A Button
  <Button.OpacityMask>
    <DrawingBrush Viewport="0,0,0.25,0.25" TileMode="Tile">
      <DrawingBrush.Drawing>
        <GeometryDrawing>
          <GeometryDrawing.Brush>
            <RadialGradientBrush>
              <RadialGradientBrush.GradientStops>
                <GradientStop Offset="0" Color="Black" />
                <GradientStop Offset="1" Color="Transparent" />
              </RadialGradientBrush.GradientStops>
            </RadialGradientBrush>
          </GeometryDrawing.Brush>
          <GeometryDrawing.Geometry>
            <RectangleGeometry Rect="0.05,0.05 0.9,0.9" />
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Thickness="0.1" Brush="Black" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Button.OpacityMask>
</Button>




Painting with Solid Colors and Gradients Overview


This topic describes how to use SolidColorBrushLinearGradientBrush, and RadialGradientBrush objects to paint with solid colors, linear gradients, and radial gradients.

Painting an Area with a Solid Color

One of the most common operations in any platform is to paint an area with a solid Color. To accomplish this task, Windows Presentation Foundation (WPF) provides the SolidColorBrush class. The following sections describe the different ways to paint with a SolidColorBrush.

              

Using a SolidColorBrush in "XAML"

To paint an area with a solid color in XAML, use one of the following options.

  • Select a predefined solid color brush by name. For example, you can set a button's Background to "Red" or "MediumBlue". For a list of other predefined solid color brushes, see the static properties of the Brushes class. The following is an example.

    <!-- This button's background is painted with a red SolidColorBrush,
         described using a named color. -->
    <Button Background="Red">A Button</Button>
    
  • Choose a color from the 32-bit color palette by specifying the amounts of red, green, and blue to combine into a single solid color. The format for specifying a color from the 32-bit palette is "#rrggbb", where rr is a two digit hexadecimal number specifying the relative amount of red, gg specifies the amount of green, and bb specifies the amount of blue. Additionally, the color can be specified as "#aarrggbb" where aa specifies the alpha value, or transparency, of the color. This approach enables you to create colors that are partially transparent. In the following example, the Background of a Button is set to fully-opaque red using hexadecimal notation.

    <!-- This button's background is painted with a red SolidColorBrush,
         described using hexadecimal notation. -->
    <Button Background="#FFFF0000">A Button</Button>
    
  • Use property tag syntax to describe a SolidColorBrush. This syntax is more verbose but enables you to specify additional settings, such as the brush's opacity. In the following example, the Background properties of two Button elements are set to fully-opaque red. The first brush's color is described using a predefined color name. The second brush's color is described using hexadecimal notation.

    <!-- Both of these buttons' backgrounds are painted with red 
         SolidColorBrush objects, described using object element
         syntax. -->
    <Button>A Button
    
      <Button.Background>
        <SolidColorBrush Color="Red" />
      </Button.Background>
    </Button>
    
    <Button>A Button
    
      <Button.Background>
        <SolidColorBrush Color="#FFFF0000" />
      </Button.Background>
    </Button>  
    

Painting with a SolidColorBrush in Code

To paint an area with a solid color in code, use one of the following options.

  • Use one of the predefined brushes provided by the Brushes class. In the following example, the Background of a Button is set to Red.

    Button myButton = new Button();
    myButton.Content = "A Button";
    myButton.Background = Brushes.Red;  
    
  • Create a SolidColorBrush and set its Color property using a Color structure. You can use a predefined color from the Colors class or you can create a Color using the static FromArgb method.

    The following example shows how to set the Color property of a SolidColorBrush using a predefined color.

    Button myButton = new Button();
    myButton.Content = "A Button";
    
    SolidColorBrush mySolidColorBrush = new SolidColorBrush();
    mySolidColorBrush.Color = Colors.Red;
    myButton.Background = mySolidColorBrush;
    

The static FromArgb enables you to specify the color's alpha, red, green, and blue values. The typical range for each of these values is 0-255. For example, an alpha value of 0 indicates that a color is completely transparent, while a value of 255 indicates the color is completely opaque. Likewise, a red value of 0 indicates that a color has no red in it, while a value of 255 indicates a color has the maximum amount of red possible. In the following example, a brush's color is described by specifying alpha, red, green, and blue values.

Button myButton = new Button();
myButton.Content = "A Button";

SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = 
    Color.FromArgb(
        255, // Specifies the transparency of the color.
        255, // Specifies the amount of red.
        0, // specifies the amount of green.
        0); // Specifies the amount of blue.

myButton.Background = mySolidColorBrush;

For additional ways to specify color, see the Color reference topic.

Painting an Area with a Gradient

A gradient brush paints an area with multiple colors that blend into each other along an axis. You can use them to create impressions of light and shadow, giving your controls a three-dimensional feel. You can also use them to simulate glass, chrome, water, and other smooth surfaces. WPF provides two types of gradient brushes: LinearGradientBrush and RadialGradientBrush.

         

Linear Gradients

LinearGradientBrush paints an area with a gradient defined along a line, the gradient axis. You specify the gradient's colors and their location along the gradient axis using GradientStop objects. You may also modify the gradient axis, which enables you to create horizontal and vertical gradients and to reverse the gradient direction. The gradient axis is described in the next section. By default, a diagonal gradient is created.

    

The following example shows the code that creates a linear gradient with four colors.

<!-- This rectangle is painted with a diagonal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle diagonalFillRectangle = new Rectangle();
diagonalFillRectangle.Width = 200;
diagonalFillRectangle.Height = 100;

// Create a diagonal linear gradient with four stops.   
LinearGradientBrush myLinearGradientBrush =
    new LinearGradientBrush();
myLinearGradientBrush.StartPoint = new Point(0,0);
myLinearGradientBrush.EndPoint = new Point(1,1);
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
diagonalFillRectangle.Fill = myLinearGradientBrush;

This code produces the following gradient:

A diagonal linear gradient

Note: The gradient examples in this topic use the default coordinate system for setting start points and end points. The default coordinate system is relative to a bounding box: 0 indicates 0 percent of the bounding box and 1 indicates 100 percent of the bounding box. You can change this coordinate system by setting the MappingMode property to the value Absolute. An absolute coordinate system is not relative to a bounding box. Values are interpreted directly in local space.

The GradientStop is the basic building block of a gradient brush. A gradient stop specifies a Color at an Offset along the gradient axis.

  • The gradient stop's Color property specifies the color of the gradient stop. You may set the color by using a predefined color (provided by the Colors class) or by specifying ScRGB or ARGB values. In XAML, you may also use hexadecimal notation to describe a color. For more information, see the Color structure.

  • The gradient stop's Offset property specifies the position of the gradient stop's color on the gradient axis. The offset is a Double that ranges from 0 to 1. The closer a gradient stop's offset value is to 0, the closer the color is to the start of the gradient. The closer the gradient's offset value is to 1, the closer the color is to the end of the gradient.

The color of each point between gradient stops is linearly interpolated as a combination of the color specified by the two bounding gradient stops. The following illustration highlights the gradient stops in the previous example. The circles mark the position of gradient stops and a dashed line shows the gradient axis.

Gradient stops in a linear gradient

The first gradient stop specifies the color yellow at an offset of 0.0. The second gradient stop specifies the color red at an offset of 0.25. The points between these two stops gradually change from yellow to red as you move from left to right along the gradient axis. The third gradient stop specifies the color blue at an offset of 0.75. The points between the second and third gradient stops gradually change from red to blue. The fourth gradient stop specifies the color lime green at an offset of 1.0. The points between the third and fourth gradient stops gradually change from blue to lime green.

                             

The Gradient Axis

As previously mentioned, a linear gradient brush's gradient stops are positioned along a line, the gradient axis. You may change the orientation and size of the line using the brush's StartPoint and EndPoint properties. By manipulating the brush's StartPoint and EndPoint, you can create horizontal and vertical gradients, reverse the gradient direction, condense the gradient spread, and more.

By default, the linear gradient brush's StartPoint and EndPoint are relative to the area being painted. The point (0,0) represents the upper-left corner of the area being painted, and (1,1) represents the lower-right corner of the area being painted. The default StartPoint of a LinearGradientBrush is (0,0), and its default EndPoint is (1,1), which creates a diagonal gradient starting at the upper-left corner and extending to the lower-right corner of the area being painted. The following illustration shows the gradient axis of a linear gradient brush with default StartPoint and EndPoint.

Gradient axis for a diagonal linear gradient

The following example shows how to create a horizontal gradient by specifying the brush's StartPoint and EndPoint. Notice that the gradient stops are the same as in the previous examples; by simply changing the StartPoint and EndPoint, the gradient has been changed from diagonal to horizontal.

<!-- This rectangle is painted with a horizontal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle horizontalFillRectangle = new Rectangle();
horizontalFillRectangle.Width = 200;
horizontalFillRectangle.Height = 100;

// Create a horizontal linear gradient with four stops.   
LinearGradientBrush myHorizontalGradient =
    new LinearGradientBrush();
myHorizontalGradient.StartPoint = new Point(0,0.5);
myHorizontalGradient.EndPoint = new Point(1,0.5);
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
horizontalFillRectangle.Fill = myHorizontalGradient; 

The following illustration shows the gradient that is created. The gradient axis is marked with a dashed line, and the gradient stops are marked with circles.

Gradient axis for a horizontal linear gradient

The next example shows how to create a vertical gradient.

<!-- This rectangle is painted with a vertical gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle verticalFillRectangle = new Rectangle();
verticalFillRectangle.Width = 200;
verticalFillRectangle.Height = 100;

// Create a vertical linear gradient with four stops.   
LinearGradientBrush myVerticalGradient =
    new LinearGradientBrush();
myVerticalGradient.StartPoint = new Point(0.5,0);
myVerticalGradient.EndPoint = new Point(0.5,1);
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
verticalFillRectangle.Fill = myVerticalGradient;  

The following illustration shows the gradient that is created. The gradient axis is marked with a dashed line, and the gradient stops are marked with circles.

Gradient axis for a vertical gradient

                                   

Radial Gradients

Like a LinearGradientBrush, a RadialGradientBrush paints an area with colors that blend together along an axis. The previous examples showed how a linear gradient brush's axis is a straight line. A radial gradient brush's axis is defined by a circle; its colors "radiate" outward from its origin.

In the following example, a radial gradient brush is used to paint the interior of a rectangle.

<!-- This rectangle is painted with a diagonal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <RadialGradientBrush 
      GradientOrigin="0.5,0.5" Center="0.5,0.5" 
      RadiusX="0.5" RadiusY="0.5">
      <GradientStop Color="Yellow" Offset="0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1" />
    </RadialGradientBrush>
  </Rectangle.Fill>
</Rectangle>

RadialGradientBrush myRadialGradientBrush = new RadialGradientBrush();
myRadialGradientBrush.GradientOrigin = new Point(0.5,0.5);
myRadialGradientBrush.Center = new Point(0.5,0.5);
myRadialGradientBrush.RadiusX = 0.5;
myRadialGradientBrush.RadiusY = 0.5;
myRadialGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myRadialGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));
myRadialGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));
myRadialGradientBrush.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

Rectangle myRectangle = new Rectangle();
myRectangle.Width = 200;
myRectangle.Height = 100;
myRectangle.Fill = myRadialGradientBrush;

The following illustration shows the gradient created in the previous example. The brush's gradient stops have been highlighted. Notice that, even though the results are different, the gradient stops in this example are identical to the gradient stops in the previous linear gradient brush examples.

Gradient stops in a radial gradient

The GradientOrigin specifies the start point of a radial gradient brush's gradient axis. The gradient axis radiates from the gradient origin to the gradient circle. A brush's gradient circle is defined by its CenterRadiusX, and RadiusY properties.

The following illustration shows several radial gradients with different GradientOriginCenterRadiusX, and RadiusY settings.

RadialGradientBrush settings

RadialGradientBrushes with different GradientOrigin, Center, RadiusX, and RadiusY settings.

   

Specifying Transparent or Partially-Transparent Gradient Stops

Because gradient stops do not provide an opacity property, you must specify the alpha channel of colors using ARGB hexadecimal notation in markup or use the Color.FromScRgb method to create gradient stops that are transparent or partially transparent. The following sections explain how to create partially transparent gradient stops in XAML and code. For information about setting the opacity of the entire brush, see the Specifying the Opacity of a Brush section.

Specifying Color Opacity in "XAML"

In XAML, you use ARGB hexadecimal notation to specify the opacity of individual colors. ARGB hexadecimal notation uses the following syntax:

 #aarrggbb 

The aa in the previous line represents a two-digit hexadecimal value used to specify the opacity of the color. The rrgg, and bb each represent a two digit hexadecimal value used to specify the amount of red, green, and blue in the color. Each hexadecimal digit may have a value from 0-9 or A-F. 0 is the smallest value, and F is the greatest. An alpha value of 00 specifies a color that is completely transparent, while an alpha value of FF creates a color that is fully opaque. In the following example, hexadecimal ARGB notation is used to specify two colors. The first is partially transparent (it has an alpha value of x20), while the second is completely opaque.

<Rectangle Width="100" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0,0">

      <!-- This gradient stop is partially transparent. -->
      <GradientStop Color="#200000FF" Offset="0.0" />

      <!-- This gradient stop is fully opaque. -->
      <GradientStop Color="#FF0000FF" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>

Specifying Color Opacity in Code

When using code, the static FromArgb method enables you to specify an alpha value when you create a color. The method takes four parameters of type Byte. The first parameter specifies the alpha channel of the color; the other three parameters specify the red, green, and blue values of the color. Each value should be between 0 to 255, inclusive. An alpha value of 0 specifies that the color is completely transparent, while an alpha value of 255 specifies that the color is completely opaque. In the following example, the FromArgb method is used to produce two colors. The first color is partially transparent (it has an alpha value of 32), while the second is fully opaque.

LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();

// This gradient stop is partially transparent.
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Color.FromArgb(32, 0, 0, 255), 0.0));

// This gradient stop is fully opaque. 
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Color.FromArgb(255, 0, 0, 255), 1.0));

Rectangle myRectangle = new Rectangle();
myRectangle.Width = 100;
myRectangle.Height = 100;
myRectangle.Fill = myLinearGradientBrush;

Alternatively, you may use the FromScRgb method, which enables you to use ScRGB values to create a color.

Painting with Images, Drawings, Visuals, and Patterns

ImageBrushDrawingBrush, and VisualBrush classes enable you to paint an area with images, drawings, or visuals. For information about painting with images, drawings, and patterns, see Painting with Images, Drawings, and Visuals.




Painting with Images, Drawings, and Visuals


This topic describes how to use ImageBrushDrawingBrush, and VisualBrush objects to paint an area with an image, a Drawing, or a Visual.

Prerequisites

To understand this topic, you should be familiar with the different types of brushes Windows Presentation Foundation (WPF) provides and their basic features. For an introduction, see the WPF Brushes Overview.

Paint an Area with an Image

An ImageBrush paints an area with an ImageSource. The most common type of ImageSource to use with an ImageBrush is a BitmapImage, which describes a bitmap graphic. You can use a DrawingImage to paint using a Drawing object, but it is simpler to use a DrawingBrush instead. For more information about ImageSource objects, see the Imaging Overview.

To paint with an ImageBrush, create a BitmapImage and use it to load the bitmap content. Then, use the BitmapImage to set the ImageSource property of the ImageBrush. Finally, apply the ImageBrush to the object you want to paint. In Extensible Application Markup Language (XAML), you can also just set the ImageSource property of the ImageBrush with the path of the image to load. 

Like all Brush objects, an ImageBrush can be used to paint objects such as shapes, panels, controls, and text. The following illustration shows some effects that can be achieved with an ImageBrush.

ImageBrush output examples

Objects painted by an ImageBrush

By default, an ImageBrush stretches its image to completely fill the area being painted, possibly distorting the image if the painted area has a different aspect ratio than the image. You can change this behavior by changing the Stretch property from its default value of Fill to NoneUniform, or UniformToFill. Because ImageBrush is a type of TileBrush, you can specify exactly how an image brush fills the output area and even create patterns. For more information about advanced TileBrush features, see the TileBrush Overview.

Example: Paint an Object with a Bitmap Image

The following example uses an ImageBrush to paint the Background of a Canvas.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.BrushExamples.ImageBrushExample"
  WindowTitle="ImageBrush Example"
  Background="White">

  <StackPanel>

    <Canvas
      Height="200" Width="300">
      <Canvas.Background>
        <ImageBrush ImageSource="sampleImages\Waterlilies.jpg" />
      </Canvas.Background>
    </Canvas>


  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Microsoft.Samples.BrushExamples
{

    public class ImageBrushExample : Page
    {

        public ImageBrushExample()
        {

            StackPanel mainPanel = new StackPanel();
            canvasBackgroundExample(mainPanel);
            this.Content = mainPanel;

        }


        private void canvasBackgroundExample(Panel mainPanel)
        {

            BitmapImage theImage = new BitmapImage
                (new Uri("sampleImages\\Waterlilies.jpg", UriKind.Relative));

            ImageBrush myImageBrush = new ImageBrush(theImage);

            Canvas myCanvas = new Canvas();
            myCanvas.Width = 300;
            myCanvas.Height = 200;
            myCanvas.Background = myImageBrush;

            mainPanel.Children.Add(myCanvas);


        }

    }

}

Paint an Area with a Drawing

DrawingBrush enables you to paint an area with shapes, text, images, and video. Shapes inside a drawing brush may themselves be painted with a solid color, gradient, image, or even another DrawingBrush. The following illustration demonstrates some uses of a DrawingBrush.

DrawingBrush output examples

Objects painted by a DrawingBrush

DrawingBrush paints an area with a Drawing object. A Drawing object describes visible content, such as a shape, bitmap, video, or a line of text. Different types of drawings describe different types of content. The following is a list of the different types of drawing objects.

For more information about Drawing objects, see the Drawing Objects Overview.

    

Like an ImageBrush, a DrawingBrush stretches its Drawing to fill its output area. You can override this behavior by changing the Stretch property from its default setting of Fill. For more information, see the Stretch property.

  

Example: Paint an Object with a Drawing

      

The following example shows how to paint an object with a drawing of three ellipses. A GeometryDrawing is used to describe the ellipses.

<Button Content="A Button">
  <Button.Background>
    <DrawingBrush>
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="LightBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="25,50" />
              <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="50,50" />
              <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="75,50" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Thickness="1" Brush="Gray" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Button.Background>
</Button>
// Create a DrawingBrush.
DrawingBrush myDrawingBrush = new DrawingBrush();

// Create a drawing.
GeometryDrawing myGeometryDrawing = new GeometryDrawing();
myGeometryDrawing.Brush = Brushes.LightBlue;
myGeometryDrawing.Pen = new Pen(Brushes.Gray, 1);
GeometryGroup ellipses = new GeometryGroup();
ellipses.Children.Add(new EllipseGeometry(new Point(25,50), 12.5, 25));
ellipses.Children.Add(new EllipseGeometry(new Point(50,50), 12.5, 25));
ellipses.Children.Add(new EllipseGeometry(new Point(75,50), 12.5, 25));

myGeometryDrawing.Geometry = ellipses;
myDrawingBrush.Drawing = myGeometryDrawing;

Button myButton = new Button();
myButton.Content = "A Button";

// Use the DrawingBrush to paint the button's background.
myButton.Background = myDrawingBrush;

Paint an Area with a Visual

The most versatile and powerful of all the brushes, the VisualBrush paints an area with a Visual. A Visual is a low-level graphical type that serves as the ancestor of many useful graphical components. For example, the WindowFrameworkElement, and Control classes are all types of Visual objects. Using a VisualBrush, you can paint areas with almost any Windows Presentation Foundation (WPF) graphical object.

System_CAPS_noteNote

Although VisualBrush is a type of Freezable object, it cannot be frozen (made read-only) when its Visual property is set to a value other than null.

There are two ways to specify the Visual content of a VisualBrush.

When you define a new Visual for a VisualBrush and that Visual is a UIElement (such as a panel or control), the layout system runs on the UIElement and its child elements when the AutoLayoutContent property is set to true. However, the root UIElement is essentially isolated from the rest of the system: styles, and external layout can't permeate this boundary. Therefore, you should explicitly specify the size of the root UIElement, because its only parent is the VisualBrush and therefore it cannot automatically size itself to the area being painted. For more information about layout in Windows Presentation Foundation (WPF), see the Layout.

Like ImageBrush and DrawingBrush, a VisualBrush stretches its content to fill its output area. You can override this behavior by changing the Stretch property from its default setting of Fill. For more information, see the Stretch property.

Example: Paint an Object with a Visual

In the following example, several controls and a panel are used to paint a rectangle.

<Rectangle Width="150" Height="150" Stroke="Black" Margin="5,0,5,0">
  <Rectangle.Fill>
    <VisualBrush>
      <VisualBrush.Visual>
        <StackPanel Background="White">
          <Rectangle Width="25" Height="25" Fill="Red" Margin="2" />
          <TextBlock FontSize="10pt" Margin="2">Hello, World!</TextBlock>
          <Button Margin="2">A Button</Button>
        </StackPanel>
      </VisualBrush.Visual>
    </VisualBrush>
  </Rectangle.Fill>
</Rectangle>
VisualBrush myVisualBrush = new VisualBrush();

// Create the visual brush's contents.
StackPanel myStackPanel = new StackPanel();
myStackPanel.Background = Brushes.White;

Rectangle redRectangle = new Rectangle();
redRectangle.Width = 25;
redRectangle.Height =25; 
redRectangle.Fill = Brushes.Red;
redRectangle.Margin = new Thickness(2);
myStackPanel.Children.Add(redRectangle);

TextBlock someText = new TextBlock();
FontSizeConverter myFontSizeConverter = new FontSizeConverter();
someText.FontSize = (double)myFontSizeConverter.ConvertFrom("10pt");
someText.Text = "Hello, World!";
someText.Margin = new Thickness(2);
myStackPanel.Children.Add(someText);

Button aButton = new Button();
aButton.Content = "A Button";
aButton.Margin = new Thickness(2);
myStackPanel.Children.Add(aButton);

// Use myStackPanel as myVisualBrush's content.
myVisualBrush.Visual = myStackPanel;

// Create a rectangle to paint.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 150;
myRectangle.Height = 150;
myRectangle.Stroke = Brushes.Black;
myRectangle.Margin = new Thickness(5,0,5,0);

// Use myVisualBrush to paint myRectangle.
myRectangle.Fill = myVisualBrush;

Example: Create a Reflection

The preceding example showed how to create a new Visual for use as a background. You can also use a VisualBrush to display an existing visual; this capability enables you to produce interesting visual effects, such as reflections and magnification. The following example uses a VisualBrush to create a reflection of a Border that contains several elements. The following illustration shows the output that this example produces.

A reflected Visual object

A reflected Visual object

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
namespace SDKSample
{
    public partial class ReflectionExample : Page
    {
        public ReflectionExample()
        {
            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());

            this.Background = Brushes.Black;
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(50);

            Border myReflectedBorder = new Border();
            this.RegisterName("ReflectedVisual", myReflectedBorder);

            // Create a gradient background for the border.
            GradientStop firstStop = new GradientStop();
            firstStop.Offset = 0.0;
            Color firstStopColor = new Color();
            firstStopColor.R = 204;
            firstStopColor.G = 204;
            firstStopColor.B = 255;
            firstStopColor.A = 255;
            firstStop.Color = firstStopColor;
            GradientStop secondStop = new GradientStop();
            secondStop.Offset = 1.0;
            secondStop.Color = Colors.White;

            GradientStopCollection myGradientStopCollection = new GradientStopCollection();
            myGradientStopCollection.Add(firstStop);
            myGradientStopCollection.Add(secondStop);

            LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
            myLinearGradientBrush.StartPoint = new Point(0, 0.5);
            myLinearGradientBrush.EndPoint = new Point(1, 0.5);
            myLinearGradientBrush.GradientStops = myGradientStopCollection;

            myReflectedBorder.Background = myLinearGradientBrush;

            // Add contents to the border.
            StackPanel borderStackPanel = new StackPanel();
            borderStackPanel.Orientation = Orientation.Horizontal;
            borderStackPanel.Margin = new Thickness(10);

            TextBlock myTextBlock = new TextBlock();
            myTextBlock.TextWrapping = TextWrapping.Wrap;
            myTextBlock.Width = 200;
            myTextBlock.Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit." +
                               " Suspendisse vel ante. Donec luctus tortor sit amet est." +
                               " Nullam pulvinar odio et wisi." +
                               " Pellentesque quis magna. Sed pellentesque." +
                               " Nulla euismod." +
                               "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.";

            borderStackPanel.Children.Add(myTextBlock);

            StackPanel ellipseStackPanel = new StackPanel();

            Ellipse ellipse1 = new Ellipse();
            ellipse1.Margin = new Thickness(10);
            ellipse1.Height = 50;
            ellipse1.Width = 50;
            ellipse1.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse1);
            Ellipse ellipse2 = new Ellipse();
            ellipse2.Margin = new Thickness(10);
            ellipse2.Height = 50;
            ellipse2.Width = 50;
            ellipse2.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse2);
            Ellipse ellipse3 = new Ellipse();
            ellipse3.Margin = new Thickness(10);
            ellipse3.Height = 50;
            ellipse3.Width = 50;
            ellipse3.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse3);
            borderStackPanel.Children.Add(ellipseStackPanel);

            myReflectedBorder.Child = borderStackPanel;

            // Create divider rectangle
            Rectangle dividerRectangle = new Rectangle();
            dividerRectangle.Height = 1;
            dividerRectangle.Fill = Brushes.Gray;
            dividerRectangle.HorizontalAlignment = HorizontalAlignment.Stretch;

            // Create the object to contain the reflection.
            Rectangle reflectionRectangle = new Rectangle();

            // Bind the height of the rectangle to the border height.
            Binding heightBinding = new Binding();
            heightBinding.ElementName = "ReflectedVisual";
            heightBinding.Path = new PropertyPath(Rectangle.HeightProperty);
            BindingOperations.SetBinding(reflectionRectangle, Rectangle.HeightProperty, heightBinding);

            // Bind the width of the rectangle to the border width.
            Binding widthBinding = new Binding();
            widthBinding.ElementName = "ReflectedVisual";
            widthBinding.Path = new PropertyPath(Rectangle.WidthProperty);
            BindingOperations.SetBinding(reflectionRectangle, Rectangle.WidthProperty, widthBinding);

            // Creates the reflection.
            VisualBrush myVisualBrush = new VisualBrush();
            myVisualBrush.Opacity = 0.75;
            myVisualBrush.Stretch = Stretch.None;
            Binding reflectionBinding = new Binding();
            reflectionBinding.ElementName = "ReflectedVisual";
            BindingOperations.SetBinding(myVisualBrush, VisualBrush.VisualProperty, reflectionBinding);

            ScaleTransform myScaleTransform = new ScaleTransform();
            myScaleTransform.ScaleX = 1;
            myScaleTransform.ScaleY = -1;
            TranslateTransform myTranslateTransform = new TranslateTransform();
            myTranslateTransform.Y = 1;

            TransformGroup myTransformGroup = new TransformGroup();
            myTransformGroup.Children.Add(myScaleTransform);
            myTransformGroup.Children.Add(myTranslateTransform);

            myVisualBrush.RelativeTransform = myTransformGroup;

            reflectionRectangle.Fill = myVisualBrush;

            // Create a gradient background for the border.
            GradientStop firstStop2 = new GradientStop();
            firstStop2.Offset = 0.0;
            Color c1 = new Color();
            c1.R = 0;
            c1.G = 0;
            c1.B = 0;
            c1.A = 255;
            firstStop2.Color = c1;
            GradientStop secondStop2 = new GradientStop();
            secondStop2.Offset = 0.5;
            Color c2 = new Color();
            c2.R = 0;
            c2.G = 0;
            c2.B = 0;
            c2.A = 51;
            firstStop2.Color = c2;
            GradientStop thirdStop = new GradientStop();
            thirdStop.Offset = 0.75;
            Color c3 = new Color();
            c3.R = 0;
            c3.G = 0;
            c3.B = 0;
            c3.A = 0;
            thirdStop.Color = c3;

            GradientStopCollection myGradientStopCollection2 = new GradientStopCollection();
            myGradientStopCollection2.Add(firstStop2);
            myGradientStopCollection2.Add(secondStop2);
            myGradientStopCollection2.Add(thirdStop);

            LinearGradientBrush myLinearGradientBrush2 = new LinearGradientBrush();
            myLinearGradientBrush2.StartPoint = new Point(0.5, 0);
            myLinearGradientBrush2.EndPoint = new Point(0.5, 1);
            myLinearGradientBrush2.GradientStops = myGradientStopCollection2;

            reflectionRectangle.OpacityMask = myLinearGradientBrush2;

            BlurBitmapEffect myBlurBitmapEffect = new BlurBitmapEffect();
            myBlurBitmapEffect.Radius = 1.5;

            reflectionRectangle.BitmapEffect = myBlurBitmapEffect;

            myStackPanel.Children.Add(myReflectedBorder);
            myStackPanel.Children.Add(dividerRectangle);
            myStackPanel.Children.Add(reflectionRectangle);
            this.Content = myStackPanel;

        }
        /*
    <Rectangle 
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">

      <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <GradientStop Color="#FF000000" Offset="0.0" />
          <GradientStop Color="#33000000" Offset="0.5" />
          <GradientStop Color="#00000000" Offset="0.75" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

*/

    }
}
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  Background="Black">


  <StackPanel Margin="50">

    <!-- The object to reflect. -->
    <Border Name="ReflectedVisual" Width="400">
      <Border.Background>
        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
          <GradientStop Offset="0.0" Color="#CCCCFF" />
          <GradientStop Offset="1.0" Color="White" />
        </LinearGradientBrush>
      </Border.Background>
      <StackPanel Orientation="Horizontal" Margin="10">        
        <TextBlock TextWrapping="Wrap" Width="200" Margin="10">
          Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
          Suspendisse vel ante. Donec luctus tortor sit amet est.
          Nullam pulvinar odio et wisi.
          Pellentesque quis magna. Sed pellentesque.
          Nulla euismod.
          Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
        </TextBlock>
        <StackPanel>
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
        </StackPanel>
      </StackPanel>
    </Border>

    <Rectangle Height="1" Fill="Gray" HorizontalAlignment="Stretch" />

    <!-- The object to contain the reflection.-->
    <Rectangle 
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">
      <Rectangle.Fill>

        <!-- Creates the reflection. -->
        <VisualBrush 
          Opacity="0.75" Stretch="None"
          Visual="{Binding ElementName=ReflectedVisual}">
          <VisualBrush.RelativeTransform>

            <!-- Flip the reflection. -->
            <TransformGroup>
              <ScaleTransform ScaleX="1" ScaleY="-1" />
              <TranslateTransform  Y="1" />
            </TransformGroup>
          </VisualBrush.RelativeTransform>
        </VisualBrush>
      </Rectangle.Fill>

      <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <GradientStop Color="#FF000000" Offset="0.0" />
          <GradientStop Color="#33000000" Offset="0.5" />
          <GradientStop Color="#00000000" Offset="0.75" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

For additional examples that show how to magnify portions of the screen and how to create reflections, see the VisualBrush Sample.

TileBrush Features

ImageBrushDrawingBrush, and VisualBrush are types of TileBrush objects. TileBrush objects provide you with a great deal of control over how an area is painted with an image, drawing, or visual. For example, instead of just painting an area with a single stretched image, you can paint an area with a series of image tiles that create a pattern.

    

TileBrush has three primary components: content, tiles, and the output area.

TileBrush components

Components of a TileBrush with a single tile

Components of a tiled TileBrush

Components of a TileBrush with multiple tiles

For more information about the tiling features of TileBrush objects, see the TileBrush Overview.




TileBrush Overview


TileBrush objects provide you with a great deal of control over how an area is painted with an image, Drawing, or Visual. This topic describes how to useTileBrush features to gain more control over how an ImageBrush, DrawingBrush, or VisualBrush paints an area.

Prerequisites

To understand this topic, it's helpful to understand how to use the basic features of the ImageBrushDrawingBrush, or VisualBrush class. For an introduction to these types, see the Painting with Images, Drawings, and Visuals.

Painting an Area with Tiles

ImageBrushDrawingBrush, are VisualBrush are types of TileBrush objects. Tile brushes provide you with a great deal of control over how an area is painted with an image, drawing, or visual. For example, instead of just painting an area with a single stretched image, you can paint an area with a series of image tiles that create a pattern.

Painting an area with a tile brush involves three components: content, the base tile, and the output area.

TileBrush components

Components of a TileBrush with a single tile

Components of a tiled TileBrush

Components of a TileBrush with a TileMode of Tile

The output area is the area being painted, such as the Fill of an Ellipse or the Background of a Button. The next sections describe the other two components of a TileBrush.

Brush Content

There are three different types of TileBrush and each paints with a different type of content.

You can specify the position and dimensions of TileBrush content by using the Viewbox property, although it is common to leave the Viewbox set to its default value. By default, the Viewbox is configured to completely contain the brush's contents. For more information about configuring theViewbox, see the Viewbox property page.

The Base Tile

TileBrush projects its content onto a base tile. The Stretch property controls how TileBrush content is stretched to fill the base tile. The Stretchproperty accepts the following values, defined by the Stretch enumeration:

  • None: The brush's content is not stretched to fill the tile.

  • Fill: The brush's content is scaled to fit the tile. Because the content's height and width are scaled independently, the original aspect ratio of the content might not be preserved. That is, the brush's content might be warped in order to completely fill the output tile.

  • Uniform: The brush's content is scaled so that it fits completely within the tile. The content's aspect ratio is preserved.

  • UniformToFill: The brush's content is scaled so that it completely fills the output area while preserving the content's original aspect ratio.

The following image illustrates the different Stretch settings.

Different TileBrush Stretch settings

In the following example, the content of an ImageBrush is set so that it does not stretch to fill the output area.

<Rectangle
  Width="125" Height="175"
  Stroke="Black"
  StrokeThickness="1"
  Margin="0,0,5,0">
  <Rectangle.Fill>
    <ImageBrush 
      Stretch="None"
      ImageSource="sampleImages\testImage.gif"/>
  </Rectangle.Fill>
</Rectangle>
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 125;
myRectangle.Height = 175;
myRectangle.Stroke = Brushes.Black;
myRectangle.StrokeThickness = 1;
myRectangle.Margin = new Thickness(0,5,0,0);

// Load the image.
BitmapImage theImage = 
    new BitmapImage(
        new Uri("sampleImages\\testImage.gif", UriKind.Relative));   
ImageBrush myImageBrush = new ImageBrush(theImage);

// Configure the brush so that it
// doesn't stretch its image to fill
// the rectangle.
myImageBrush.Stretch = Stretch.None;

// Use the ImageBrush to paint the rectangle's background.
myRectangle.Fill = myImageBrush;

By default, a TileBrush generates a single tile (the base tile) and stretches that tile to completely fill the output area. You can change the size and position of the base tile by setting the Viewport and ViewportUnits properties.

Base Tile Size

The Viewport property determines the size and position of the base tile, and the ViewportUnits property determines whether the Viewport is specified using absolute or relative coordinates. If the coordinates are relative, they are relative to the size of the output area. The point (0,0) represents the top left corner of the output area, and (1,1) represents the bottom right corner of the output area. To specify that the Viewportproperty uses absolute coordinates, set the ViewportUnits property to Absolute.

The following illustration shows the difference in output between a TileBrush with relative versus absolute ViewportUnits. Notice that the illustrations each show a tiled pattern; the next section describes how to specify tile pattern.

Absolute and Relative Viewport Units

In the following example, an image is used to create a tile that has a width and height of 50%. The base tile is located at (0,0) of the output area.

<Rectangle
 Width="50" Height="100">
  <Rectangle.Fill>

    <!-- Paints an area with 4 tiles. -->
    <ImageBrush ImageSource="sampleImages\cherries_larger.jpg"
      Viewport="0,0,0.5,0.5"
      ViewportUnits="RelativeToBoundingBox" 
      TileMode="Tile" />
  </Rectangle.Fill>
</Rectangle>
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 50;
myRectangle.Height = 100;

// Load the image.
BitmapImage theImage = 
    new BitmapImage(
        new Uri("sampleImages\\cherries_larger.jpg", UriKind.Relative));   
ImageBrush myImageBrush = new ImageBrush(theImage);

// Create tiles that are 1/4 the size of 
// the output area.
myImageBrush.Viewport = new Rect(0,0,0.25,0.25);
myImageBrush.ViewportUnits = BrushMappingMode.RelativeToBoundingBox;

// Set the tile mode to Tile.
myImageBrush.TileMode = TileMode.Tile;

// Use the ImageBrush to paint the rectangle's background.
myRectangle.Fill = myImageBrush;

The next example sets the tiles of an ImageBrush to 25 by 25 device independent pixels. Because the ViewportUnits are absolute, the ImageBrush tiles are always 25 by 25 pixels, regardless of the size of the area being painted.

<Rectangle
 Width="50" Height="100">
  <Rectangle.Fill>

    <!-- Paints an area with 25 x 25 tiles. -->
    <ImageBrush ImageSource="sampleImages\cherries_larger.jpg"
      Viewport="0,0,25,25"
      ViewportUnits="Absolute" 
      TileMode="Tile" />
  </Rectangle.Fill>
</Rectangle>
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 50;
myRectangle.Height = 100;

// Load the image.       
BitmapImage theImage =
    new BitmapImage(
        new Uri("sampleImages\\cherries_larger.jpg", UriKind.Relative));
ImageBrush myImageBrush = new ImageBrush(theImage);

// Create tiles that are 25 x 25, regardless of the size
// of the output area.
myImageBrush.Viewport = new Rect(0, 0, 25, 25);
myImageBrush.ViewportUnits = BrushMappingMode.Absolute;

// Set the tile mode to Tile.
myImageBrush.TileMode = TileMode.Tile;

// Use the ImageBrush to paint the rectangle's background.
myRectangle.Fill = myImageBrush;

Tiling Behavior

TileBrush produces a tiled pattern when its base tile does not completely fill the output area and a tiling mode other then None is specified. When a tile brush's tile does not completely fill the output area, its TileMode property specifies whether the base tile should be duplicated to fill the output area and, if so, how the base tile should be duplicated. The TileMode property accepts the following values, defined by the TileMode enumeration:

  • None: Only the base tile is drawn.

  • Tile: The base tile is drawn and the remaining area is filled by repeating the base tile such that the right edge of one tile is adjacent to the left edge of the next, and similarly for bottom and top.

  • FlipX: The same as Tile, but alternate columns of tiles are flipped horizontally.

  • FlipY: The same as Tile, but alternate rows of tiles are flipped vertically.

  • FlipXY: A combination of FlipX and FlipY.

The following image illustrates the different tiling modes.

Different TileBrush TileMode settings

In the following example, an image is used to paint a rectangle that is 100 pixels wide and 100 pixels tall. By setting the brush's Viewport has been set to 0,0,0.25,0.25, the brush's base tile is made to be 1/4 of the output area. The brush's TileMode is set to FlipXY. so that it fills the rectangle with rows of tiles.

<Rectangle
 Width="100" Height="100" >
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\triangle.jpg"
      Viewport="0,0,0.25,0.25" 
      TileMode="FlipXY"
      />
  </Rectangle.Fill>    
</Rectangle>
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 100;
myRectangle.Height = 100;

// Load the image.
BitmapImage theImage = 
    new BitmapImage(
        new Uri("sampleImages\\triangle.jpg", UriKind.Relative));   
ImageBrush myImageBrush = new ImageBrush(theImage);

// Create tiles that are 1/4 the size of 
// the output area.
myImageBrush.Viewport = new Rect(0,0,0.25,0.25);

// Set the tile mode to FlipXY.
myImageBrush.TileMode = TileMode.FlipXY;

// Use the ImageBrush to paint the rectangle's background.
myRectangle.Fill = myImageBrush;




How-to Topics


Animate the Color or Opacity of a SolidColorBrush


This example shows how to animate the Color and Opacity of a SolidColorBrush.

Example

The following example uses three animations to animate the Color and Opacity of a SolidColorBrush.

  • The first animation, a ColorAnimation, changes the brush's color to Gray when the mouse enters the rectangle.

  • The next animation, another ColorAnimation, changes the brush's color to Orange when the mouse leaves the rectangle.

  • The final animation, a DoubleAnimation, changes the brush's opacity to 0.0 when the left mouse button is pressed.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Input;

namespace Microsoft.Samples.Animation
{
    /// <summary>
    /// This example shows how to animate the Opacity and Color 
    /// properties of a SolidColorBrush.
    /// </summary>
    public class SolidColorBrushExample : Page
    {

        public SolidColorBrushExample()
        {
            Title = "SolidColorBrush Animation Example";
            Background = Brushes.White;

            // Create a NameScope for the page so
            // that Storyboards can be used.
            NameScope.SetNameScope(this, new NameScope());

            // Create a Rectangle.
            Rectangle aRectangle = new Rectangle();
            aRectangle.Width = 100;
            aRectangle.Height = 100;

            // Create a SolidColorBrush to paint
            // the rectangle's fill. The Opacity
            // and Color properties of the brush
            // will be animated.
            SolidColorBrush myAnimatedBrush = new SolidColorBrush();
            myAnimatedBrush.Color = Colors.Orange;
            aRectangle.Fill = myAnimatedBrush;

            // Register the brush's name with the page
            // so that it can be targeted by storyboards.
            this.RegisterName("MyAnimatedBrush", myAnimatedBrush);

            //
            // Animate the brush's color to gray when
            // the mouse enters the rectangle.
            //
            ColorAnimation mouseEnterColorAnimation = new ColorAnimation();
            mouseEnterColorAnimation.To = Colors.Gray;
            mouseEnterColorAnimation.Duration = TimeSpan.FromSeconds(1);
            Storyboard.SetTargetName(mouseEnterColorAnimation, "MyAnimatedBrush");
            Storyboard.SetTargetProperty(
                mouseEnterColorAnimation, new PropertyPath(SolidColorBrush.ColorProperty));
            Storyboard mouseEnterStoryboard = new Storyboard();
            mouseEnterStoryboard.Children.Add(mouseEnterColorAnimation);
            aRectangle.MouseEnter += delegate(object sender, MouseEventArgs e)
            {
                mouseEnterStoryboard.Begin(this);
            };

            //
            // Animate the brush's color to orange when
            // the mouse leaves the rectangle.
            //
            ColorAnimation mouseLeaveColorAnimation = new ColorAnimation();
            mouseLeaveColorAnimation.To = Colors.Orange;
            mouseLeaveColorAnimation.Duration = TimeSpan.FromSeconds(1);
            Storyboard.SetTargetName(mouseLeaveColorAnimation, "MyAnimatedBrush");
            Storyboard.SetTargetProperty(
                mouseLeaveColorAnimation, new PropertyPath(SolidColorBrush.ColorProperty));
            Storyboard mouseLeaveStoryboard = new Storyboard();
            mouseLeaveStoryboard.Children.Add(mouseLeaveColorAnimation);
            aRectangle.MouseLeave += delegate(object sender, MouseEventArgs e)
            {
                mouseLeaveStoryboard.Begin(this);
            };

            //
            // Animate the brush's opacity to 0 and back when
            // the left mouse button is pressed over the rectangle.
            //
            DoubleAnimation opacityAnimation = new DoubleAnimation();
            opacityAnimation.To = 0.0;
            opacityAnimation.Duration = TimeSpan.FromSeconds(0.5);
            opacityAnimation.AutoReverse = true;
            Storyboard.SetTargetName(opacityAnimation, "MyAnimatedBrush");
            Storyboard.SetTargetProperty(
                opacityAnimation, new PropertyPath(SolidColorBrush.OpacityProperty));
            Storyboard mouseLeftButtonDownStoryboard = new Storyboard();
            mouseLeftButtonDownStoryboard.Children.Add(opacityAnimation);
            aRectangle.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
            {
                mouseLeftButtonDownStoryboard.Begin(this);
            };

            StackPanel mainPanel = new StackPanel();
            mainPanel.Margin = new Thickness(20);
            mainPanel.Children.Add(aRectangle);
            Content = mainPanel;
        }

    }
}

For a more complete sample, which shows how to animate different types of brushes, see the Brushes Sample. For more information about animation, see the Animation Overview.

For consistency with other animation examples, the code versions of this example use a Storyboard object to apply their animations. However, when applying a single animation in code, it's simpler to use the BeginAnimation method instead of using a Storyboard. For an example, see How to: Animate a Property Without Using a Storyboard.




Animate the Position or Color of a Gradient Stop


This example shows how to animate the Color and Offset of GradientStop objects.

Example

The following example animates three gradient stops inside a LinearGradientBrush. The example uses three animations, each of which animates a different gradient stop:

  • The first animation, a DoubleAnimation, animates the first gradient stop's Offset from 0.0 to 1.0 and then back to 0.0. As a result, the first color in the gradient shifts from the left side to the right side of the rectangle and then back to the left side.

  • The second animation, a ColorAnimation, animates the second gradient stop's Color from Purple to Yellow and then back to Purple. As a result, the middle color in the gradient changes from purple to yellow and back to purple.

  • The third animation, another ColorAnimation, animates the opacity of the third gradient stop's Color by -1 and then back. As a result, the third color in the gradient fades away and then becomes opaque again.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace BrushesIntroduction
{
    public class GradientStopAnimationExample : Page
    {
        public GradientStopAnimationExample()
        {
            Title = "GradientStop Animation Example";
            Background = Brushes.White;

            // Create a NameScope for the page so that
            // Storyboards can be used.
            NameScope.SetNameScope(this, new NameScope());

            // Create a rectangle. This rectangle will
            // be painted with a gradient.
            Rectangle aRectangle = new Rectangle();
            aRectangle.Width = 200;
            aRectangle.Height = 100;
            aRectangle.Stroke = Brushes.Black;
            aRectangle.StrokeThickness = 1;

            // Create a LinearGradientBrush to paint
            // the rectangle's fill.
            LinearGradientBrush gradientBrush = new LinearGradientBrush();

            // Create gradient stops for the brush.
            GradientStop stop1 = new GradientStop(Colors.MediumBlue, 0.0);
            GradientStop stop2 = new GradientStop(Colors.Purple, 0.5);
            GradientStop stop3 = new GradientStop(Colors.Red, 1.0);

            // Register a name for each gradient stop with the
            // page so that they can be animated by a storyboard.
            this.RegisterName("GradientStop1", stop1);
            this.RegisterName("GradientStop2", stop2);
            this.RegisterName("GradientStop3", stop3);

            // Add the stops to the brush.
            gradientBrush.GradientStops.Add(stop1);
            gradientBrush.GradientStops.Add(stop2);
            gradientBrush.GradientStops.Add(stop3);

            // Apply the brush to the rectangle.
            aRectangle.Fill = gradientBrush;

            //
            // Animate the first gradient stop's offset from
            // 0.0 to 1.0 and then back to 0.0.
            //
            DoubleAnimation offsetAnimation = new DoubleAnimation();
            offsetAnimation.From = 0.0;
            offsetAnimation.To = 1.0;
            offsetAnimation.Duration = TimeSpan.FromSeconds(1.5);
            offsetAnimation.AutoReverse = true;
            Storyboard.SetTargetName(offsetAnimation, "GradientStop1");
            Storyboard.SetTargetProperty(offsetAnimation, 
                new PropertyPath(GradientStop.OffsetProperty));

            //
            // Animate the second gradient stop's color from
            // Purple to Yellow and then back to Purple.
            //
            ColorAnimation gradientStopColorAnimation = new ColorAnimation();
            gradientStopColorAnimation.From = Colors.Purple;
            gradientStopColorAnimation.To = Colors.Yellow;
            gradientStopColorAnimation.Duration = TimeSpan.FromSeconds(1.5);
            gradientStopColorAnimation.AutoReverse = true;
            Storyboard.SetTargetName(gradientStopColorAnimation, "GradientStop2");
            Storyboard.SetTargetProperty(gradientStopColorAnimation,
                new PropertyPath(GradientStop.ColorProperty));

            // Set the animation to begin after the first animation
            // ends.
            gradientStopColorAnimation.BeginTime = TimeSpan.FromSeconds(3);

            //
            // Animate the third gradient stop's color so
            // that it becomes transparent.
            //
            ColorAnimation opacityAnimation = new ColorAnimation();

            // Reduces the target color's alpha value by 1, 
            // making the color transparent.
            opacityAnimation.By = Color.FromScRgb(-1.0F, 0F, 0F, 0F);
            opacityAnimation.Duration = TimeSpan.FromSeconds(1.5);
            opacityAnimation.AutoReverse = true;
            Storyboard.SetTargetName(opacityAnimation, "GradientStop3");
            Storyboard.SetTargetProperty(opacityAnimation,
                new PropertyPath(GradientStop.ColorProperty));

            // Set the animation to begin after the first two
            // animations have ended. 
            opacityAnimation.BeginTime = TimeSpan.FromSeconds(6);

            // Create a Storyboard to apply the animations.
            Storyboard gradientStopAnimationStoryboard = new Storyboard();
            gradientStopAnimationStoryboard.Children.Add(offsetAnimation);
            gradientStopAnimationStoryboard.Children.Add(gradientStopColorAnimation);
            gradientStopAnimationStoryboard.Children.Add(opacityAnimation);

            // Begin the storyboard when the left mouse button is
            // pressed over the rectangle.
            aRectangle.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
            {
                gradientStopAnimationStoryboard.Begin(this);
            };

            StackPanel mainPanel = new StackPanel();
            mainPanel.Margin = new Thickness(10);
            mainPanel.Children.Add(aRectangle);
            Content = mainPanel;
        }
    }
}
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="GradientStop Animation Example"
  Background="White">
  <StackPanel Margin="10">

    <Rectangle
      Width="200" 
      Height="100" 
      Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>
        <LinearGradientBrush>
          <GradientStop x:Name="GradientStop1" Color="MediumBlue" Offset="0.0" />
          <GradientStop x:Name="GradientStop2" Color="Purple" Offset="0.5" />
          <GradientStop x:Name="GradientStop3" Color="Red" Offset="1.0" />
        </LinearGradientBrush>
      </Rectangle.Fill>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetName="GradientStop1"
                Storyboard.TargetProperty="Offset"
                From="0.0" To="1.0" Duration="0:0:1.5"
                AutoReverse="True" />
              <ColorAnimation 
                Storyboard.TargetName="GradientStop2"
                Storyboard.TargetProperty="Color"
                From="Purple" To="Yellow" 
                Duration="0:0:1.5"
                AutoReverse="True"
                BeginTime="0:0:3" />
              <ColorAnimation 
                Storyboard.TargetName="GradientStop3"
                Storyboard.TargetProperty="Color" 
                Duration="0:0:1.5" 
                AutoReverse="True"
                BeginTime="0:0:6">
                <ColorAnimation.By>
                  <Color ScA="-1" ScR="0" ScB="0" ScG="0" />
                </ColorAnimation.By>
              </ColorAnimation>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>

  </StackPanel>
</Page>

Although this example uses a LinearGradientBrush, the process is the same for animating GradientStop objects inside a RadialGradientBrush.

For additional examples, see the Brushes Sample.




Create a Reflection


This example shows how to use a VisualBrush to create a reflection. Because a VisualBrush can display an existing visual, you can use this capability to produce interesting visual effects, such as reflections and magnification.

Example

The following example uses a VisualBrush to create a reflection of a Border that contains several elements. The following illustration shows the output that this example produces.

A reflected Visual object

A reflected Visual object

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
namespace SDKSample
{
    public partial class ReflectionExample : Page
    {
        public ReflectionExample()
        {
            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());

            this.Background = Brushes.Black;
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(50);

            Border myReflectedBorder = new Border();
            this.RegisterName("ReflectedVisual", myReflectedBorder);

            // Create a gradient background for the border.
            GradientStop firstStop = new GradientStop();
            firstStop.Offset = 0.0;
            Color firstStopColor = new Color();
            firstStopColor.R = 204;
            firstStopColor.G = 204;
            firstStopColor.B = 255;
            firstStopColor.A = 255;
            firstStop.Color = firstStopColor;
            GradientStop secondStop = new GradientStop();
            secondStop.Offset = 1.0;
            secondStop.Color = Colors.White;

            GradientStopCollection myGradientStopCollection = new GradientStopCollection();
            myGradientStopCollection.Add(firstStop);
            myGradientStopCollection.Add(secondStop);

            LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
            myLinearGradientBrush.StartPoint = new Point(0, 0.5);
            myLinearGradientBrush.EndPoint = new Point(1, 0.5);
            myLinearGradientBrush.GradientStops = myGradientStopCollection;

            myReflectedBorder.Background = myLinearGradientBrush;

            // Add contents to the border.
            StackPanel borderStackPanel = new StackPanel();
            borderStackPanel.Orientation = Orientation.Horizontal;
            borderStackPanel.Margin = new Thickness(10);

            TextBlock myTextBlock = new TextBlock();
            myTextBlock.TextWrapping = TextWrapping.Wrap;
            myTextBlock.Width = 200;
            myTextBlock.Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit." +
                               " Suspendisse vel ante. Donec luctus tortor sit amet est." +
                               " Nullam pulvinar odio et wisi." +
                               " Pellentesque quis magna. Sed pellentesque." +
                               " Nulla euismod." +
                               "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.";

            borderStackPanel.Children.Add(myTextBlock);

            StackPanel ellipseStackPanel = new StackPanel();

            Ellipse ellipse1 = new Ellipse();
            ellipse1.Margin = new Thickness(10);
            ellipse1.Height = 50;
            ellipse1.Width = 50;
            ellipse1.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse1);
            Ellipse ellipse2 = new Ellipse();
            ellipse2.Margin = new Thickness(10);
            ellipse2.Height = 50;
            ellipse2.Width = 50;
            ellipse2.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse2);
            Ellipse ellipse3 = new Ellipse();
            ellipse3.Margin = new Thickness(10);
            ellipse3.Height = 50;
            ellipse3.Width = 50;
            ellipse3.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse3);
            borderStackPanel.Children.Add(ellipseStackPanel);

            myReflectedBorder.Child = borderStackPanel;

            // Create divider rectangle
            Rectangle dividerRectangle = new Rectangle();
            dividerRectangle.Height = 1;
            dividerRectangle.Fill = Brushes.Gray;
            dividerRectangle.HorizontalAlignment = HorizontalAlignment.Stretch;

            // Create the object to contain the reflection.
            Rectangle reflectionRectangle = new Rectangle();

            // Bind the height of the rectangle to the border height.
            Binding heightBinding = new Binding();
            heightBinding.ElementName = "ReflectedVisual";
            heightBinding.Path = new PropertyPath(Rectangle.HeightProperty);
            BindingOperations.SetBinding(reflectionRectangle, Rectangle.HeightProperty, heightBinding);

            // Bind the width of the rectangle to the border width.
            Binding widthBinding = new Binding();
            widthBinding.ElementName = "ReflectedVisual";
            widthBinding.Path = new PropertyPath(Rectangle.WidthProperty);
            BindingOperations.SetBinding(reflectionRectangle, Rectangle.WidthProperty, widthBinding);

            // Creates the reflection.
            VisualBrush myVisualBrush = new VisualBrush();
            myVisualBrush.Opacity = 0.75;
            myVisualBrush.Stretch = Stretch.None;
            Binding reflectionBinding = new Binding();
            reflectionBinding.ElementName = "ReflectedVisual";
            BindingOperations.SetBinding(myVisualBrush, VisualBrush.VisualProperty, reflectionBinding);

            ScaleTransform myScaleTransform = new ScaleTransform();
            myScaleTransform.ScaleX = 1;
            myScaleTransform.ScaleY = -1;
            TranslateTransform myTranslateTransform = new TranslateTransform();
            myTranslateTransform.Y = 1;

            TransformGroup myTransformGroup = new TransformGroup();
            myTransformGroup.Children.Add(myScaleTransform);
            myTransformGroup.Children.Add(myTranslateTransform);

            myVisualBrush.RelativeTransform = myTransformGroup;

            reflectionRectangle.Fill = myVisualBrush;

            // Create a gradient background for the border.
            GradientStop firstStop2 = new GradientStop();
            firstStop2.Offset = 0.0;
            Color c1 = new Color();
            c1.R = 0;
            c1.G = 0;
            c1.B = 0;
            c1.A = 255;
            firstStop2.Color = c1;
            GradientStop secondStop2 = new GradientStop();
            secondStop2.Offset = 0.5;
            Color c2 = new Color();
            c2.R = 0;
            c2.G = 0;
            c2.B = 0;
            c2.A = 51;
            firstStop2.Color = c2;
            GradientStop thirdStop = new GradientStop();
            thirdStop.Offset = 0.75;
            Color c3 = new Color();
            c3.R = 0;
            c3.G = 0;
            c3.B = 0;
            c3.A = 0;
            thirdStop.Color = c3;

            GradientStopCollection myGradientStopCollection2 = new GradientStopCollection();
            myGradientStopCollection2.Add(firstStop2);
            myGradientStopCollection2.Add(secondStop2);
            myGradientStopCollection2.Add(thirdStop);

            LinearGradientBrush myLinearGradientBrush2 = new LinearGradientBrush();
            myLinearGradientBrush2.StartPoint = new Point(0.5, 0);
            myLinearGradientBrush2.EndPoint = new Point(0.5, 1);
            myLinearGradientBrush2.GradientStops = myGradientStopCollection2;

            reflectionRectangle.OpacityMask = myLinearGradientBrush2;

            BlurBitmapEffect myBlurBitmapEffect = new BlurBitmapEffect();
            myBlurBitmapEffect.Radius = 1.5;

            reflectionRectangle.BitmapEffect = myBlurBitmapEffect;

            myStackPanel.Children.Add(myReflectedBorder);
            myStackPanel.Children.Add(dividerRectangle);
            myStackPanel.Children.Add(reflectionRectangle);
            this.Content = myStackPanel;

        }
        /*
    <Rectangle 
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">

      <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <GradientStop Color="#FF000000" Offset="0.0" />
          <GradientStop Color="#33000000" Offset="0.5" />
          <GradientStop Color="#00000000" Offset="0.75" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

*/

    }
}
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  Background="Black">


  <StackPanel Margin="50">

    <!-- The object to reflect. -->
    <Border Name="ReflectedVisual" Width="400">
      <Border.Background>
        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
          <GradientStop Offset="0.0" Color="#CCCCFF" />
          <GradientStop Offset="1.0" Color="White" />
        </LinearGradientBrush>
      </Border.Background>
      <StackPanel Orientation="Horizontal" Margin="10">        
        <TextBlock TextWrapping="Wrap" Width="200" Margin="10">
          Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
          Suspendisse vel ante. Donec luctus tortor sit amet est.
          Nullam pulvinar odio et wisi.
          Pellentesque quis magna. Sed pellentesque.
          Nulla euismod.
          Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
        </TextBlock>
        <StackPanel>
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
        </StackPanel>
      </StackPanel>
    </Border>

    <Rectangle Height="1" Fill="Gray" HorizontalAlignment="Stretch" />

    <!-- The object to contain the reflection.-->
    <Rectangle 
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">
      <Rectangle.Fill>

        <!-- Creates the reflection. -->
        <VisualBrush 
          Opacity="0.75" Stretch="None"
          Visual="{Binding ElementName=ReflectedVisual}">
          <VisualBrush.RelativeTransform>

            <!-- Flip the reflection. -->
            <TransformGroup>
              <ScaleTransform ScaleX="1" ScaleY="-1" />
              <TranslateTransform  Y="1" />
            </TransformGroup>
          </VisualBrush.RelativeTransform>
        </VisualBrush>
      </Rectangle.Fill>

      <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <GradientStop Color="#FF000000" Offset="0.0" />
          <GradientStop Color="#33000000" Offset="0.5" />
          <GradientStop Color="#00000000" Offset="0.75" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

For the complete sample, which includes examples that show how to magnify parts of the screen and how to create reflections, see VisualBrush Sample.




Create Different Tile Patterns with a TileBrush


This example shows how to use the TileMode property of a TileBrush to create a pattern.

The TileMode property enables you to specify how the content of a TileBrush is repeated, that is, tiled to fill an output area. To create a pattern, you set the TileMode to TileFlipXFlipY, or FlipXY. You must also set the Viewport of the TileBrush so that it is smaller than the area that you are painting; otherwise, only a single tile is produced, regardless which TileMode setting you use.

Example

The following example creates five DrawingBrush objects, gives them each a different TileMode setting, and uses them to paint five rectangles. Although this example uses the DrawingBrush class to demonstrate TileMode behavior, the TileMode property works identically for all the TileBrush objects, that is, for ImageBrushVisualBrush, and DrawingBrush.

The following illustration shows the output that this example produces.

TileBrush tiling example output

Tile patterns created with the TileMode property

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace BrushesIntroduction
{
    public class TileModeExample : Page
    {

        public TileModeExample()
        {
            Background = Brushes.White;
            Margin = new Thickness(20);
            StackPanel mainPanel = new StackPanel();
            mainPanel.HorizontalAlignment = HorizontalAlignment.Left;

            //
            // Create a Drawing. This will be the DrawingBrushes' content.
            //
            PolyLineSegment triangleLinesSegment = new PolyLineSegment();
            triangleLinesSegment.Points.Add(new Point(50, 0));
            triangleLinesSegment.Points.Add(new Point(0, 50));
            PathFigure triangleFigure = new PathFigure();
            triangleFigure.IsClosed = true;
            triangleFigure.StartPoint = new Point(0, 0);
            triangleFigure.Segments.Add(triangleLinesSegment);
            PathGeometry triangleGeometry = new PathGeometry();
            triangleGeometry.Figures.Add(triangleFigure);

            GeometryDrawing triangleDrawing = new GeometryDrawing();
            triangleDrawing.Geometry = triangleGeometry;
            triangleDrawing.Brush = new SolidColorBrush(Color.FromArgb(255, 204, 204, 255));
            Pen trianglePen = new Pen(Brushes.Black, 2);
            triangleDrawing.Pen = trianglePen;
            trianglePen.MiterLimit = 0;
            triangleDrawing.Freeze();

            //
            // Create the first TileBrush. Its content is not tiled.
            //
            DrawingBrush tileBrushWithoutTiling = new DrawingBrush();
            tileBrushWithoutTiling.Drawing = triangleDrawing;
            tileBrushWithoutTiling.TileMode = TileMode.None;

            // Create a rectangle and paint it with the DrawingBrush.
            Rectangle noTileExampleRectangle = createExampleRectangle();
            noTileExampleRectangle.Fill = tileBrushWithoutTiling;

            // Add a header and the rectangle to the main panel.
            mainPanel.Children.Add(createExampleHeader("None"));
            mainPanel.Children.Add(noTileExampleRectangle);

            //
            // Create another TileBrush, this time with tiling.
            //
            DrawingBrush tileBrushWithTiling = new DrawingBrush();
            tileBrushWithTiling.Drawing = triangleDrawing;
            tileBrushWithTiling.TileMode = TileMode.Tile;

            // Specify the brush's Viewport. Otherwise,
            // a single tile will be produced that fills
            // the entire output area and its TileMode will
            // have no effect.
            // This setting uses realtive values to
            // creates four tiles. 
            tileBrushWithTiling.Viewport = new Rect(0, 0, 0.5, 0.5);

            // Create a rectangle and paint it with the DrawingBrush.
            Rectangle tilingExampleRectangle = createExampleRectangle();
            tilingExampleRectangle.Fill = tileBrushWithTiling;
            mainPanel.Children.Add(createExampleHeader("Tile"));
            mainPanel.Children.Add(tilingExampleRectangle);

            //
            // Create a TileBrush with FlipX tiling.
            // The brush's content is flipped horizontally as it is
            // tiled in this example
            //
            DrawingBrush tileBrushWithFlipXTiling = new DrawingBrush();
            tileBrushWithFlipXTiling.Drawing = triangleDrawing;
            tileBrushWithFlipXTiling.TileMode = TileMode.FlipX;

            // Specify the brush's Viewport.
            tileBrushWithFlipXTiling.Viewport = new Rect(0, 0, 0.5, 0.5);

            // Create a rectangle and paint it with the DrawingBrush.
            Rectangle flipXTilingExampleRectangle = createExampleRectangle();
            flipXTilingExampleRectangle.Fill = tileBrushWithFlipXTiling;
            mainPanel.Children.Add(createExampleHeader("FlipX"));
            mainPanel.Children.Add(flipXTilingExampleRectangle);

            //
            // Create a TileBrush with FlipY tiling.
            // The brush's content is flipped vertically as it is
            // tiled in this example
            //
            DrawingBrush tileBrushWithFlipYTiling = new DrawingBrush();
            tileBrushWithFlipYTiling.Drawing = triangleDrawing;
            tileBrushWithFlipYTiling.TileMode = TileMode.FlipX;

            // Specify the brush's Viewport.
            tileBrushWithFlipYTiling.Viewport = new Rect(0, 0, 0.5, 0.5);

            // Create a rectangle and paint it with the DrawingBrush.
            Rectangle flipYTilingExampleRectangle = createExampleRectangle();
            flipYTilingExampleRectangle.Fill = tileBrushWithFlipYTiling;
            mainPanel.Children.Add(createExampleHeader("FlipY"));
            mainPanel.Children.Add(flipYTilingExampleRectangle);

            //
            // Create a TileBrush with FlipXY tiling.
            // The brush's content is flipped vertically as it is
            // tiled in this example
            //
            DrawingBrush tileBrushWithFlipXYTiling = new DrawingBrush();
            tileBrushWithFlipXYTiling.Drawing = triangleDrawing;
            tileBrushWithFlipXYTiling.TileMode = TileMode.FlipXY;

            // Specify the brush's Viewport.
            tileBrushWithFlipXYTiling.Viewport = new Rect(0, 0, 0.5, 0.5);

            // Create a rectangle and paint it with the DrawingBrush.
            Rectangle flipXYTilingExampleRectangle = createExampleRectangle();
            flipXYTilingExampleRectangle.Fill = tileBrushWithFlipXYTiling;
            mainPanel.Children.Add(createExampleHeader("FlipXY"));
            mainPanel.Children.Add(flipXYTilingExampleRectangle);

            Content = mainPanel;
        }

        //
        // Helper method that creates rectangle elements.
        //
        private static Rectangle createExampleRectangle()
        {
            Rectangle exampleRectangle = new Rectangle();
            exampleRectangle.Width = 50;
            exampleRectangle.Height = 50;
            exampleRectangle.Stroke = Brushes.Black;
            exampleRectangle.StrokeThickness = 1;
            return exampleRectangle;
        }

        //
        // Helper method that creates headers for the examples. 
        //
        private static TextBlock createExampleHeader(String text)
        {
            TextBlock header = new TextBlock();
            header.Margin = new Thickness(0, 10, 0, 0);
            header.Text = text;
            return header;
        }
    }
}
<!-- Demonstrates TileMode values. -->
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Background="White" Margin="20">
  <Page.Resources>

    <!-- Define a Drawing as a resource that it can be easily used
         as content for all the DrawingBrush objects in this example. -->
    <GeometryDrawing x:Key="TriangleDrawing"
      Geometry="M0,0 L50,0 0,50Z" Brush="#CCCCFF"
      PresentationOptions:Freeze="True" >
      <GeometryDrawing.Pen>
        <Pen Thickness="2" Brush="Black" MiterLimit="0" />
      </GeometryDrawing.Pen>
    </GeometryDrawing>
  </Page.Resources>

  <StackPanel HorizontalAlignment="Left">
    <TextBlock Margin="0,10,0,0">None</TextBlock>
    <Rectangle Width="50" Height="50" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>

        <!-- The DrawingBrush's content is not tiled in this example. -->
        <DrawingBrush TileMode="None" 
          Drawing="{StaticResource TriangleDrawing}" />
      </Rectangle.Fill>
    </Rectangle>

    <TextBlock Margin="0,10,0,0">Tile</TextBlock>
    <Rectangle Width="50" Height="50" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>

        <!-- The DrawingBrush's content is tiled in this example. 
             The Viewport property is set to create four tiles. -->
        <DrawingBrush TileMode="Tile" Viewport="0,0,0.5,0.5" 
          Drawing="{StaticResource TriangleDrawing}"/>
      </Rectangle.Fill>
    </Rectangle>

    <TextBlock Margin="0,10,0,0">FlipX</TextBlock>
    <Rectangle Width="50" Height="50" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>

        <!-- The DrawingBrush's content is flipped horizontally as it is
             tiled in this example. -->
        <DrawingBrush 
          TileMode="FlipX" Viewport="0,0,0.5,0.5"
          Drawing="{StaticResource TriangleDrawing}" />
      </Rectangle.Fill>
    </Rectangle>

    <TextBlock Margin="0,10,0,0">FlipY</TextBlock>
    <Rectangle Width="50" Height="50" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>

        <!-- The DrawingBrush's content is flipped vertically as it is
             tiled in this example. -->
        <DrawingBrush TileMode="FlipY" Viewport="0,0,0.5,0.5" 
          Drawing="{StaticResource TriangleDrawing}" />
      </Rectangle.Fill>
    </Rectangle>

    <TextBlock Margin="0,10,0,0">FlipXY</TextBlock>
    <Rectangle Width="50" Height="50" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>

        <!-- The DrawingBrush's content is flipped horizontally
             and vertically as it is tiled in this example. -->
        <DrawingBrush TileMode="FlipXY" Viewport="0,0,0.5,0.5" 
          Drawing="{StaticResource TriangleDrawing}" />
      </Rectangle.Fill>
    </Rectangle>

  </StackPanel>
</Page>




Define a Pen


This example shows how use a Pen to outline a shape. To create a simple Pen, you need only specify its Thickness and Brush. You can create more complex pen's by specifying a DashStyleDashCapLineJoinStartLineCap, and EndLineCap.

Example

The following example uses a Pen to outline a shape defined by a GeometryDrawing.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace SDKSample
{
    public partial class PenExample : Page
    {
        public PenExample()
        {
            // Create several geometries.
            RectangleGeometry myRectangleGeometry = new RectangleGeometry();
            myRectangleGeometry.Rect = new Rect(0, 0, 50, 50);
            EllipseGeometry myEllipseGeometry = new EllipseGeometry();
            myEllipseGeometry.Center = new Point(75, 75);
            myEllipseGeometry.RadiusX = 50;
            myEllipseGeometry.RadiusY = 50;
            LineGeometry myLineGeometry = new LineGeometry();
            myLineGeometry.StartPoint = new Point(75, 75);
            myLineGeometry.EndPoint = new Point(75, 0);

            // Create a GeometryGroup and add the geometries to it.
            GeometryGroup myGeometryGroup = new GeometryGroup();
            myGeometryGroup.Children.Add(myRectangleGeometry);
            myGeometryGroup.Children.Add(myEllipseGeometry);
            myGeometryGroup.Children.Add(myLineGeometry);

            // Create a GeometryDrawing and use the GeometryGroup to specify
            // its geometry.
            GeometryDrawing myGeometryDrawing = new GeometryDrawing();
            myGeometryDrawing.Geometry = myGeometryGroup;

            // Add the GeometryDrawing to a DrawingGroup.
            DrawingGroup myDrawingGroup = new DrawingGroup();
            myDrawingGroup.Children.Add(myGeometryDrawing);

            // Create a Pen to add to the GeometryDrawing created above.
            Pen myPen = new Pen();
            myPen.Thickness = 10;
            myPen.LineJoin = PenLineJoin.Round;
            myPen.EndLineCap = PenLineCap.Round;

            // Create a gradient to use as a value for the Pen's Brush property.
            GradientStop firstStop = new GradientStop();
            firstStop.Offset = 0.0;
            Color c1 = new Color();
            c1.A = 255;
            c1.R = 204;
            c1.G = 204;
            c1.B = 255;
            firstStop.Color = c1;
            GradientStop secondStop = new GradientStop();
            secondStop.Offset = 1.0;
            secondStop.Color = Colors.Purple;

            LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
            myLinearGradientBrush.GradientStops.Add(firstStop);
            myLinearGradientBrush.GradientStops.Add(secondStop);

            myPen.Brush = myLinearGradientBrush;
            myGeometryDrawing.Pen = myPen;

            // Create an Image and set its DrawingImage to the Geometry created above.
            Image myImage = new Image();
            myImage.Stretch = Stretch.None;
            myImage.Margin = new Thickness(10);

            DrawingImage myDrawingImage = new DrawingImage();
            myDrawingImage.Drawing = myDrawingGroup;
            myImage.Source = myDrawingImage;

            this.Content = myImage;

        }      
    }
}
Outlines produces by a Pen

A GeometryDrawing




Paint an Area with a Drawing


This example shows how to paint an area with a drawing. To paint an area with a drawing, you use a DrawingBrush and one or more Drawing objects. The following example uses a DrawingBrush to paint an object with a drawing of two ellipses.

Example

<!-- Demonstrates the use of DrawingBrush. -->
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Background="White">
  <StackPanel Margin="20">

    <Rectangle Width="150" Height="150" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>
        <DrawingBrush>
          <DrawingBrush.Drawing>
            <GeometryDrawing Brush="MediumBlue">
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
                  <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Pen>
                <Pen Thickness="10">
                  <Pen.Brush>
                    <LinearGradientBrush>
                      <GradientStop Offset="0.0" Color="Black" />
                      <GradientStop Offset="1.0" Color="Gray" />
                    </LinearGradientBrush>
                  </Pen.Brush>
                </Pen>
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingBrush.Drawing>
        </DrawingBrush>
      </Rectangle.Fill>
    </Rectangle>
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;


namespace Microsoft.Samples.DrawingBrushExamples
{
    /// <summary>
    /// Paints a Rectangle element with a DrawingBrush.
    /// </summary>
    public class DrawingBrushExample : Page
    {
        public DrawingBrushExample()
        {
            Background = Brushes.White;
            StackPanel mainPanel = new StackPanel();

            // Create a drawing of two ellipses.
            GeometryDrawing aDrawing = new GeometryDrawing();

            // Use geometries to describe two overlapping ellipses.
            EllipseGeometry ellipse1 = new EllipseGeometry();
            ellipse1.RadiusX = 20;
            ellipse1.RadiusY = 45;
            ellipse1.Center = new Point(50, 50);
            EllipseGeometry ellipse2 = new EllipseGeometry();
            ellipse2.RadiusX = 45;
            ellipse2.RadiusY = 20;
            ellipse2.Center = new Point(50, 50);
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(ellipse1);
            ellipses.Children.Add(ellipse2);

            // Add the geometry to the drawing.
            aDrawing.Geometry = ellipses;

            // Specify the drawing's fill.
            aDrawing.Brush = Brushes.Blue;

            // Specify the drawing's stroke.
            Pen stroke = new Pen();
            stroke.Thickness = 10.0;
            stroke.Brush = new LinearGradientBrush(
                Colors.Black, Colors.Gray, new Point(0, 0), new Point(1, 1));
            aDrawing.Pen = stroke;

            // Create a DrawingBrush
            DrawingBrush myDrawingBrush = new DrawingBrush();
            myDrawingBrush.Drawing = aDrawing;

            // Create a Rectangle element.
            Rectangle aRectangle = new Rectangle();
            aRectangle.Width = 150;
            aRectangle.Height = 150;
            aRectangle.Stroke = Brushes.Black;
            aRectangle.StrokeThickness = 1.0;

            // Use the DrawingBrush to paint the rectangle's
            // background.
            aRectangle.Fill = myDrawingBrush;

            mainPanel.Children.Add(aRectangle);

            this.Content = mainPanel;

        }
    }
}

The following illustration shows the example's output.

Output from a DrawingBrush

(The center of the shape is white for reasons described in How to: Control the Fill of a Composite Shape.)

By setting a DrawingBrush object's Viewport and TileMode properties, you can create a repeating pattern. The following example paints an object with a pattern created from a drawing of two ellipses.

<!-- Demonstrates the use of DrawingBrush. -->
<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Background="White">
  <StackPanel Margin="20">

    <Rectangle Width="150" Height="150" Stroke="Black" StrokeThickness="1">
      <Rectangle.Fill>
        <DrawingBrush Viewport="0,0,0.25,0.25" TileMode="Tile">
          <DrawingBrush.Drawing>
            <GeometryDrawing Brush="MediumBlue">
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
                  <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Pen>
                <Pen Thickness="10">
                  <Pen.Brush>
                    <LinearGradientBrush>
                      <GradientStop Offset="0.0" Color="Black" />
                      <GradientStop Offset="1.0" Color="Gray" />
                    </LinearGradientBrush>
                  </Pen.Brush>
                </Pen>
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingBrush.Drawing>
        </DrawingBrush>
      </Rectangle.Fill>
    </Rectangle>
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;


namespace Microsoft.Samples.DrawingBrushExamples
{

    /// <summary>
    /// Paints a Rectangle element with a tiled DrawingBrush.
    /// </summary>
    public class TiledDrawingBrushExample : Page
    {

        public TiledDrawingBrushExample()
        {
            Background = Brushes.White;
            StackPanel mainPanel = new StackPanel();

            // Create a drawing of two ellipses.
            GeometryDrawing aDrawing = new GeometryDrawing();

            // Use geometries to describe two overlapping ellipses.
            EllipseGeometry ellipse1 = new EllipseGeometry();
            ellipse1.RadiusX = 20;
            ellipse1.RadiusY = 45;
            ellipse1.Center = new Point(50, 50);
            EllipseGeometry ellipse2 = new EllipseGeometry();
            ellipse2.RadiusX = 45;
            ellipse2.RadiusY = 20;
            ellipse2.Center = new Point(50, 50);
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(ellipse1);
            ellipses.Children.Add(ellipse2);

            // Add the geometry to the drawing.
            aDrawing.Geometry = ellipses;

            // Specify the drawing's fill.
            aDrawing.Brush = Brushes.Blue;

            // Specify the drawing's stroke.
            Pen stroke = new Pen();
            stroke.Thickness = 10.0;
            stroke.Brush = new LinearGradientBrush(
                Colors.Black, Colors.Gray, new Point(0, 0), new Point(1, 1));
            aDrawing.Pen = stroke;

            // Create a DrawingBrush
            DrawingBrush myDrawingBrush = new DrawingBrush();
            myDrawingBrush.Drawing = aDrawing;

            // Set the DrawingBrush's Viewport and TileMode
            // properties so that it generates a pattern.
            myDrawingBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
            myDrawingBrush.TileMode = TileMode.Tile;

            // Create a Rectangle element.
            Rectangle aRectangle = new Rectangle();
            aRectangle.Width = 150;
            aRectangle.Height = 150;
            aRectangle.Stroke = Brushes.Black;
            aRectangle.StrokeThickness = 1.0;

            // Use the DrawingBrush to paint the rectangle's
            // background.
            aRectangle.Fill = myDrawingBrush;

            mainPanel.Children.Add(aRectangle);

            this.Content = mainPanel;

        }

    }
}

The following illustration shows the tiled DrawingBrush output.

Tiled output from a DrawingBrush

For more information about drawing brushes, see Painting with Images, Drawings, and Visuals. For more information about Drawing objects, see theDrawing Objects Overview.




Paint an Area with an Image


This example shows how to use the ImageBrush class to paint an area with an image. An ImageBrush displays a single image, which is specified by itsImageSource property.

Example

The following example paints the Background of a button by using an ImageBrush.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace Microsoft.Samples.Graphics.UsingImageBrush
{

    public class PaintingWithImagesExample : Page
    {

        public PaintingWithImagesExample()
        {
            Background = Brushes.White;
            StackPanel mainPanel = new StackPanel();
            mainPanel.Margin = new Thickness(20.0);

            // Create a button.
            Button berriesButton = new Button();
            berriesButton.Foreground = Brushes.White;
            berriesButton.FontWeight = FontWeights.Bold;
            FontSizeConverter sizeConverter = new FontSizeConverter();
            berriesButton.FontSize = (Double)sizeConverter.ConvertFromString("16pt");
            berriesButton.FontFamily = new FontFamily("Verdana");
            berriesButton.Content = "Berries";
            berriesButton.Padding = new Thickness(20.0);
            berriesButton.HorizontalAlignment = HorizontalAlignment.Left;

            // Create an ImageBrush.
            ImageBrush berriesBrush = new ImageBrush();
            berriesBrush.ImageSource =
                new BitmapImage(
                    new Uri(@"sampleImages\berries.jpg", UriKind.Relative)
                );

            // Use the brush to paint the button's background.
            berriesButton.Background = berriesBrush;

            mainPanel.Children.Add(berriesButton);
            this.Content = mainPanel;
        }
    }
}

By default, an ImageBrush stretches its image to completely fill the area that you are painting. In the preceding example, the image is stretched to fill the button, possibly distorting the image. You can control this behavior by setting the Stretch property of TileBrush to Uniform or UniformToFill, which causes the brush to preserve the aspect ratio of the image.

If you set the Viewport and TileMode properties of an ImageBrush, you can create a repeating pattern. The following example paints a button by using a pattern that is created from an image.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace Microsoft.Samples.Graphics.UsingImageBrush
{

    public class TiledImageBrushExample : Page
    {

        public TiledImageBrushExample()
        {
            Background = Brushes.White;
            StackPanel mainPanel = new StackPanel();
            mainPanel.Margin = new Thickness(20.0);

            // Create a button.
            Button berriesButton = new Button();
            berriesButton.Foreground = Brushes.White;
            berriesButton.FontWeight = FontWeights.Bold;
            FontSizeConverter sizeConverter = new FontSizeConverter();
            berriesButton.FontSize = (Double)sizeConverter.ConvertFromString("16pt");
            berriesButton.FontFamily = new FontFamily("Verdana");
            berriesButton.Content = "Berries";
            berriesButton.Padding = new Thickness(20.0);
            berriesButton.HorizontalAlignment = HorizontalAlignment.Left;

            // Create an ImageBrush.
            ImageBrush berriesBrush = new ImageBrush();
            berriesBrush.ImageSource =
                new BitmapImage(
                    new Uri(@"sampleImages\berries.jpg", UriKind.Relative)
                );

            // Set the ImageBrush's Viewport and TileMode
            // so that it produces a pattern from
            // the image.
            berriesBrush.Viewport = new Rect(0,0,0.5,0.5);
            berriesBrush.TileMode = TileMode.FlipXY;

            // Use the brush to paint the button's background.
            berriesButton.Background = berriesBrush;

            mainPanel.Children.Add(berriesButton);
            this.Content = mainPanel;
        }
    }
}

For more information about the ImageBrush class, see Painting with Images, Drawings, and Visuals.

This code example is part of a larger example that is provided for the ImageBrush class. For the complete sample, see ImageBrush Sample.




Paint an Area with a Linear Gradient


This example shows how to use the LinearGradientBrush class to paint an area with a linear gradient. In the following example, the Fill of a Rectangle is painted with a diagonal linear gradient that transitions from yellow to red to blue to lime green.

Example

<!-- This rectangle is painted with a diagonal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle diagonalFillRectangle = new Rectangle();
diagonalFillRectangle.Width = 200;
diagonalFillRectangle.Height = 100;

// Create a diagonal linear gradient with four stops.   
LinearGradientBrush myLinearGradientBrush =
    new LinearGradientBrush();
myLinearGradientBrush.StartPoint = new Point(0,0);
myLinearGradientBrush.EndPoint = new Point(1,1);
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myLinearGradientBrush.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
diagonalFillRectangle.Fill = myLinearGradientBrush;

The following illustration shows the gradient created by the previous example.

Diagonal linear gradient

To create a horizontal linear gradient, change the StartPoint and EndPoint of the LinearGradientBrush to (0,0.5) and (1,0.5). In the following example, a Rectangle is painted with a horizontal linear gradient.

<!-- This rectangle is painted with a horizontal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle horizontalFillRectangle = new Rectangle();
horizontalFillRectangle.Width = 200;
horizontalFillRectangle.Height = 100;

// Create a horizontal linear gradient with four stops.   
LinearGradientBrush myHorizontalGradient =
    new LinearGradientBrush();
myHorizontalGradient.StartPoint = new Point(0,0.5);
myHorizontalGradient.EndPoint = new Point(1,0.5);
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myHorizontalGradient.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
horizontalFillRectangle.Fill = myHorizontalGradient; 

The following illustration shows the gradient created by the previous example.

A horizontal linear gradient

To create a vertical linear gradient, change the StartPoint and EndPoint of the LinearGradientBrush to (0.5,0) and (0.5,1). In the following example, a Rectangle is painted with a vertical linear gradient.

<!-- This rectangle is painted with a vertical gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle verticalFillRectangle = new Rectangle();
verticalFillRectangle.Width = 200;
verticalFillRectangle.Height = 100;

// Create a vertical linear gradient with four stops.   
LinearGradientBrush myVerticalGradient =
    new LinearGradientBrush();
myVerticalGradient.StartPoint = new Point(0.5,0);
myVerticalGradient.EndPoint = new Point(0.5,1);
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Yellow, 0.0));
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Red, 0.25));                
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.Blue, 0.75));        
myVerticalGradient.GradientStops.Add(
    new GradientStop(Colors.LimeGreen, 1.0));

// Use the brush to paint the rectangle.
verticalFillRectangle.Fill = myVerticalGradient;  

The following illustration shows the gradient created by the previous example.

Vertical linear gradient
System_CAPS_noteNote

The examples in this topic use the default coordinate system for setting start points and end points. The default coordinate system is relative to a bounding box: 0 indicates 0 percent of the bounding box, and 1 indicates 100 percent of the bounding box. You can change this coordinate system by setting the MappingMode property to the value BrushMappingMode.Absolute. An absolute coordinate system is not relative to a bounding box. Values are interpreted directly in local space.

For additional examples, see Brushes Sample. For more information about gradients and other types of brushes, see Painting with Solid Colors and Gradients Overview.




Paint an Area with a Radial Gradient


This example shows how to use the RadialGradientBrush class to paint an area with a radial gradient.

Example

The following example uses a RadialGradientBrush to paint a rectangle with a radial gradient that transitions from yellow to red to blue to lime green.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace BrushesIntroduction
{
    public class RadialGradientBrushSnippet : Page
    {
        public RadialGradientBrushSnippet()
        {
            Title = "RadialGradientBrush Example";
            Background = Brushes.White;
            Margin = new Thickness(20);

            //
            // Create a RadialGradientBrush with four gradient stops.
            //
            RadialGradientBrush radialGradient = new RadialGradientBrush();

            // Set the GradientOrigin to the center of the area being painted.
            radialGradient.GradientOrigin = new Point(0.5, 0.5);

            // Set the gradient center to the center of the area being painted.
            radialGradient.Center = new Point(0.5, 0.5);

            // Set the radius of the gradient circle so that it extends to
            // the edges of the area being painted.
            radialGradient.RadiusX = 0.5; 
            radialGradient.RadiusY = 0.5;

            // Create four gradient stops.
            radialGradient.GradientStops.Add(new GradientStop(Colors.Yellow, 0.0));
            radialGradient.GradientStops.Add(new GradientStop(Colors.Red, 0.25));
            radialGradient.GradientStops.Add(new GradientStop(Colors.Blue, 0.75));
            radialGradient.GradientStops.Add(new GradientStop(Colors.LimeGreen, 1.0));

            // Freeze the brush (make it unmodifiable) for performance benefits.
            radialGradient.Freeze();

            // Create a rectangle and paint it with the 
            // RadialGradientBrush.
            Rectangle aRectangle = new Rectangle();
            aRectangle.Width = 200;
            aRectangle.Height = 100;
            aRectangle.Fill = radialGradient;

            StackPanel mainPanel = new StackPanel();
            mainPanel.Children.Add(aRectangle);
            Content = mainPanel;

        }

    }
}


<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="RadialGradientBrush Example"
  Background="White" Margin="20">
  <StackPanel>

    <!-- This rectangle is painted with a radial gradient. -->
    <Rectangle Width="200" Height="100">
      <Rectangle.Fill>
        <RadialGradientBrush 
          GradientOrigin="0.5,0.5" 
          Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
          <RadialGradientBrush.GradientStops>
            <GradientStop Color="Yellow" Offset="0" />
            <GradientStop Color="Red" Offset="0.25" />
            <GradientStop Color="Blue" Offset="0.75" />
            <GradientStop Color="LimeGreen" Offset="1" />
          </RadialGradientBrush.GradientStops>
        </RadialGradientBrush>
      </Rectangle.Fill>
    </Rectangle>
  </StackPanel>
</Page>

The following illustration shows the gradient from the preceding example. The gradient's stops have been highlighted.

Gradient stops in a radial gradient
System_CAPS_noteNote

The examples in this topic use the default coordinate system for setting control points. The default coordinate system is relative to a bounding box: 0 indicates 0 percent of the bounding box, and 1 indicates 100 percent of the bounding box. You can change this coordinate system by setting the MappingMode property to the value Absolute. An absolute coordinate system is not relative to a bounding box. Values are interpreted directly in local space.

For additional RadialGradientBrush examples, see the Brushes Sample. For more information about gradients and other types of brushes, see Painting with Solid Colors and Gradients Overview.




Paint an Area with a Solid Color


To paint an area with a solid color, you can use a predefined system brush, such as Red or Blue, or you can create a new SolidColorBrush and describe its Color using alpha, red, green, and blue values. In XAML, you may also paint an area with a solid color by using hexidecimal notation.

The following examples uses each of these techniques to paint a Rectangle blue.

Example

Using a Predefined Brush

In the following example uses the predefined brush Blue to paint a rectangle blue.

<Rectangle Width="50" Height="50" Fill="Blue" />
// Create a rectangle and paint it with
// a predefined brush.
Rectangle myPredefinedBrushRectangle = new Rectangle();
myPredefinedBrushRectangle.Width = 50;
myPredefinedBrushRectangle.Height = 50;
myPredefinedBrushRectangle.Fill = Brushes.Blue;

Using Hexadecimal Notation

The next example uses 8-digit hexadecimal notation to paint a rectangle blue.

<!-- Note that the first two characters "FF" of the 8-digit
     value is the alpha which controls the transparency of 
     the color. Therefore, to make a completely transparent
     color (invisible), use "00" for those digits (e.g. #000000FF). -->
<Rectangle Width="50" Height="50" Fill="#FF0000FF" />

Using ARGB Values

The next example creates a SolidColorBrush and describes its Color using the ARGB values for the color blue.

<Rectangle Width="50" Height="50">
  <Rectangle.Fill>
    <SolidColorBrush>
     <SolidColorBrush.Color>

        <!-- Describes the brush's color using
             RGB values. Each value has a range of 0-255.  
             R is for red, G is for green, and B is for blue.
             A is for alpha which controls transparency of the
             color. Therefore, to make a completely transparent
             color (invisible), use a value of 0 for Alpha. -->
        <Color A="255" R="0" G="0" B="255" />
     </SolidColorBrush.Color>
    </SolidColorBrush>
  </Rectangle.Fill>
</Rectangle>
Rectangle myRgbRectangle = new Rectangle();
myRgbRectangle.Width = 50;
myRgbRectangle.Height = 50;
SolidColorBrush mySolidColorBrush = new SolidColorBrush();

// Describes the brush's color using RGB values. 
// Each value has a range of 0-255.
mySolidColorBrush.Color = Color.FromArgb(255, 0, 0, 255);
myRgbRectangle.Fill = mySolidColorBrush;           

For other ways of describing color, see the Color structure.

Related Topics

For more information about SolidColorBrush and additional examples, see the Painting with Solid Colors and Gradients Overview overview.

This code example is part of a larger example provided for the SolidColorBrush class. For the complete sample, see the Brushes Sample.




Paint an Area with a System Brush


The SystemColors class provides access to system brushes and colors, such as ControlBrushControlBrushKey, and DesktopBrush. A system brush is aSolidColorBrush object that paints an area with the specified system color. A system brush always produces a solid fill; it can't be used to create a gradient.

You can use system brushes as either a static or a dynamic resource. Use a dynamic resource if you want the brush to update automatically if the user changes the system brush as the application is running; otherwise, use a static resource. The SystemColors class contains a variety of static properties that follow a strict naming convention:

  • <SystemColor>Brush

    Gets a static reference to a SolidColorBrush of the specified system color.

  • <SystemColor>BrushKey

    Gets a dynamic reference to a SolidColorBrush of the specified system color.

  • <SystemColor>Color

    Gets a static reference to a Color structure of the specified system color.

  • <SystemColor>ColorKey

    Gets a dynamic reference to the Color structure of the specified system color.

A system color is a Color structure that can be used to configure a brush. For example, you can create a gradient using system colors by setting theColor properties of a LinearGradientBrush object's gradient stops with system colors. For an example, see How to: Use System Colors in a Gradient.

Example

The following example uses a dynamic system brush reference to set the Background of a button.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  WindowTitle="SystemColors Example" Background="White">  
  <StackPanel Margin="20">

    <!-- Uses a dynamic resource to set the 
         background of a button. 
         If the desktop brush changes while this application
         is running, this button will be updated. -->
    <Button 
      Background="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}" 
      Content="Hello, World!" />

  </StackPanel>
</Page>

The next example uses a static system brush reference to set the Background of a button.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  WindowTitle="SystemColors Example" Background="White">  
  <StackPanel Margin="20">

    <!-- Uses a static brush to set the
         background of a button. 
         If the desktop brush changes while this application
         is running, this button will not be updated until
         the page is loaded again. -->
    <Button 
      Background="{x:Static SystemColors.DesktopBrush}" 
      Content="Hello, World!"  /> 

  </StackPanel>
</Page>

For an example showing how to use a system color in a gradient, see How to: Use System Colors in a Gradient.




Paint an Area with a Video


This example shows how to paint an area with media. One way to paint an area with media is to use a MediaElement together with a VisualBrush. Use the MediaElement to load and play the media, and then use it to set the Visual property of the VisualBrush. You can then use the VisualBrush to paint an area with the loaded media.

Example

The following example uses a MediaElement and a VisualBrush to paint the Foreground of a TextBlock control with video. This example sets the IsMuted property of the MediaElement to true so that it produces no sound.

MediaElement myMediaElement = new MediaElement();
myMediaElement.Source = new Uri("sampleMedia\\xbox.wmv", UriKind.Relative);
myMediaElement.IsMuted = true;

VisualBrush myVisualBrush = new VisualBrush();
myVisualBrush.Visual = myMediaElement;

TextBlock myTextBlock = new TextBlock();
myTextBlock.FontSize = 150;
myTextBlock.Text = "Some Text";
myTextBlock.FontWeight = FontWeights.Bold;

myTextBlock.Foreground = myVisualBrush;
<TextBlock FontSize="100pt" Text="Some Text" FontWeight="Bold">
  <TextBlock.Foreground>
    <VisualBrush>
      <VisualBrush.Visual>
        <MediaElement Source="sampleMedia\xbox.wmv" IsMuted="True" />
      </VisualBrush.Visual>
    </VisualBrush>
  </TextBlock.Foreground>
</TextBlock>

Example

Because VisualBrush inherits from the TileBrush class, it provides several tiling modes. By setting the TileMode property of a VisualBrush to Tile and by setting its Viewport property to a value smaller than the area that you are painting, you can create a tiled pattern.

The following example is identical to the previous example, except that the VisualBrush generates a pattern from the video.

MediaElement myMediaElement = new MediaElement();
myMediaElement.Source = new Uri("sampleMedia\\xbox.wmv", UriKind.Relative);
myMediaElement.IsMuted = true;

VisualBrush myVisualBrush = new VisualBrush();
myVisualBrush.Viewport = new Rect(0, 0, 0.5, 0.5);
myVisualBrush.TileMode = TileMode.Tile;
myVisualBrush.Visual = myMediaElement;

TextBlock myTextBlock = new TextBlock();
myTextBlock.FontSize = 150;
myTextBlock.Text = "Some Text";
myTextBlock.FontWeight = FontWeights.Bold;

myTextBlock.Foreground = myVisualBrush;
<TextBlock FontSize="100pt" Text="Some Text" FontWeight="Bold">
  <TextBlock.Foreground>
    <VisualBrush Viewport="0,0,0.5,0.5" TileMode="Tile">
      <VisualBrush.Visual>

        <MediaElement Source="sampleMedia\xbox.wmv" IsMuted="True" /> 
      </VisualBrush.Visual>
    </VisualBrush>
  </TextBlock.Foreground>
</TextBlock>

For information about how to add a content file, such as a media file, to your application, see WPF Application Resource, Content, and Data Files. When you add a media file, you must add it as a content file, not as a resource file.




Paint an Area with a Visual


This example shows how to use the VisualBrush class to paint an area with a Visual.

In the following example, several controls and a panel are used as the background of a rectangle.

Example

<Rectangle Width="150" Height="150" Stroke="Black" Margin="5,0,5,0">
  <Rectangle.Fill>
    <VisualBrush>
      <VisualBrush.Visual>
        <StackPanel Background="White">
          <Rectangle Width="25" Height="25" Fill="Red" Margin="2" />
          <TextBlock FontSize="10pt" Margin="2">Hello, World!</TextBlock>
          <Button Margin="2">A Button</Button>
        </StackPanel>
      </VisualBrush.Visual>
    </VisualBrush>
  </Rectangle.Fill>
</Rectangle>
VisualBrush myVisualBrush = new VisualBrush();

// Create the visual brush's contents.
StackPanel myStackPanel = new StackPanel();
myStackPanel.Background = Brushes.White;

Rectangle redRectangle = new Rectangle();
redRectangle.Width = 25;
redRectangle.Height =25; 
redRectangle.Fill = Brushes.Red;
redRectangle.Margin = new Thickness(2);
myStackPanel.Children.Add(redRectangle);

TextBlock someText = new TextBlock();
FontSizeConverter myFontSizeConverter = new FontSizeConverter();
someText.FontSize = (double)myFontSizeConverter.ConvertFrom("10pt");
someText.Text = "Hello, World!";
someText.Margin = new Thickness(2);
myStackPanel.Children.Add(someText);

Button aButton = new Button();
aButton.Content = "A Button";
aButton.Margin = new Thickness(2);
myStackPanel.Children.Add(aButton);

// Use myStackPanel as myVisualBrush's content.
myVisualBrush.Visual = myStackPanel;

// Create a rectangle to paint.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 150;
myRectangle.Height = 150;
myRectangle.Stroke = Brushes.Black;
myRectangle.Margin = new Thickness(5,0,5,0);

// Use myVisualBrush to paint myRectangle.
myRectangle.Fill = myVisualBrush;

For more information about VisualBrush and additional examples, see the Painting with Images, Drawings, and Visuals overview.

This code example is part of a larger example provided for the VisualBrush class. For the complete sample, see the VisualBrush Sample.




Preserve the Aspect Ratio of an Image Used as a Background


This example shows how to use the Stretch property of an ImageBrush in order to preserve the aspect ratio of the image.

By default, when you use an ImageBrush to paint an area, its content stretches to completely fill the output area. When the output area and the image have different aspect ratios, the image is distorted by this stretching.

To make an ImageBrush preserve the aspect ratio of its image, set the Stretch property to Uniform or UniformToFill.

Example

The following example uses two ImageBrush objects to paint two rectangles. Each rectangle is 300 by 150 pixels and each contains a 300 by 300 pixel image. The Stretch property of the first brush is set to Uniform, and the Stretch property of the second brush is set to UniformToFill.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Microsoft.Samples.Graphics.UsingImageBrush
{
    /// <summary>
    /// Demonstrates different ImageBrush Stretch settings.
    /// </summary>
    public class StretchModes : Page
    {
        public StretchModes()
        {

            // Create an ImageBrush with its Stretch
            // property set to Uniform. The image it
            // contains will be expanded as much as possible
            // to fill the output area while still
            // preserving its aspect ratio.
            ImageBrush uniformBrush = new ImageBrush();
            uniformBrush.ImageSource = 
                new BitmapImage(new Uri("sampleImages\\square.jpg", UriKind.Relative));
            uniformBrush.Stretch = Stretch.Uniform;

            // Freeze the brush (make it unmodifiable) for performance benefits.
            uniformBrush.Freeze();

            // Create a rectangle and paint it with the ImageBrush.
            Rectangle rectangle1 = new Rectangle();
            rectangle1.Width = 300;
            rectangle1.Height = 150;
            rectangle1.Stroke = Brushes.MediumBlue;
            rectangle1.StrokeThickness = 1.0;
            rectangle1.Fill = uniformBrush;

            // Create an ImageBrush with its Stretch
            // property set to UniformToFill. The image it
            // contains will be expanded to completely fill
            // the rectangle, but its aspect ratio is preserved.
            ImageBrush uniformToFillBrush = new ImageBrush();
            uniformToFillBrush.ImageSource =
                new BitmapImage(new Uri("sampleImages\\square.jpg", UriKind.Relative));
            uniformToFillBrush.Stretch = Stretch.UniformToFill;

            // Freeze the brush (make it unmodifiable) for performance benefits.
            uniformToFillBrush.Freeze();

            // Create a rectangle and paint it with the ImageBrush.
            Rectangle rectangle2 = new Rectangle();
            rectangle2.Width = 300;
            rectangle2.Height = 150;
            rectangle2.Stroke = Brushes.MediumBlue;
            rectangle2.StrokeThickness = 1.0;
            rectangle2.Margin = new Thickness(0, 10, 0, 0);
            rectangle2.Fill = uniformToFillBrush;

            StackPanel mainPanel = new StackPanel();
            mainPanel.Children.Add(rectangle1);
            mainPanel.Children.Add(rectangle2);

            Content = mainPanel;
            Background = Brushes.White;
            Margin = new Thickness(20);
            Title = "ImageBrush Stretch Modes";


        }
    }
}

The following illustration shows the output of the first brush, which has a Stretch setting of Uniform.

ImageBrush with Uniform stretching

The next illustration shows the output of the second brush, which has a Stretch setting of UniformToFill.

ImageBrush with UniformToFill stretching

Note that the Stretch property behaves identically for the other TileBrush objects, that is, for DrawingBrush and VisualBrush. For more information about ImageBrush and the other TileBrush objects, see Painting with Images, Drawings, and Visuals.

Note also that, although the Stretch property appears to specify how the TileBrush content stretches to fit its output area, it actually specifies how theTileBrush content stretches to fill its base tile. For more information, see TileBrush.

This code example is part of a larger example that is provided for the ImageBrush class. For the complete sample, see ImageBrush Sample.




Set the Horizontal and Vertical Alignment of a TileBrush


This example shows how to control the horizontal and vertical alignment of content in a tile. To control the horizontal and vertical alignment of a TileBrush, use its AlignmentX and AlignmentY properties.

The AlignmentX and AlignmentY properties of a TileBrush are used when either of the following conditions is true:

Example

The following example aligns the content of a DrawingBrush, which is a type of TileBrush, to the upper-left corner of its tile. To align the content, the example sets the AlignmentX property of the DrawingBrush to Left and the AlignmentY property to Top. This example produces the following output.

A TileBrush with top-left alignment

TileBrush with content aligned to the upper-left corner

//
// Create a TileBrush and align its
// content to the top-left of its tile.
//
DrawingBrush topLeftAlignedTileBrush = new DrawingBrush();
topLeftAlignedTileBrush.AlignmentX = AlignmentX.Left;
topLeftAlignedTileBrush.AlignmentY = AlignmentY.Top;

// Set Stretch to None so that the brush's
// content doesn't automatically expand to
// fill the entire tile. 
topLeftAlignedTileBrush.Stretch = Stretch.None;

// Define the brush's content.
GeometryGroup ellipses = new GeometryGroup();
ellipses.Children.Add(new EllipseGeometry(new Point(50, 50), 20, 45));
ellipses.Children.Add(new EllipseGeometry(new Point(50, 50), 45, 20));
Pen drawingPen = new Pen(Brushes.Gray, 10);
GeometryDrawing ellipseDrawing = new GeometryDrawing(Brushes.Blue, drawingPen, ellipses);
topLeftAlignedTileBrush.Drawing = ellipseDrawing;

// Use the brush to paint a rectangle.
Rectangle rectangle1 = new Rectangle();
rectangle1.Width = 150;
rectangle1.Height = 150;
rectangle1.Stroke = Brushes.Red;
rectangle1.StrokeThickness = 2;
rectangle1.Margin = new Thickness(20);
rectangle1.Fill = topLeftAlignedTileBrush;

<Rectangle
  Width="150" Height="150"
  Stroke="Red" StrokeThickness="2"
  Margin="20">
  <Rectangle.Fill>

    <!-- This brush's content is aligned to the top-left
         of its tile. -->
    <DrawingBrush  
      Stretch="None"
      AlignmentX="Left"
      AlignmentY="Top">
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="MediumBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
              <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Brush="Gray" Thickness="10" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Rectangle.Fill>
</Rectangle>

Example

The next example aligns the content of a DrawingBrush to the lower-right corner of its tile by setting the AlignmentX property to Right and the AlignmentY property to Bottom. The example produces the following output.

A TileBrush with bottom-right alignment

TileBrush with content aligned to the lower-right corner

//
// Create a TileBrush and align its
// content to the bottom-right of its tile.
//
DrawingBrush bottomRightAlignedTileBrush = new DrawingBrush();
bottomRightAlignedTileBrush.AlignmentX = AlignmentX.Right;
bottomRightAlignedTileBrush.AlignmentY = AlignmentY.Bottom;
bottomRightAlignedTileBrush.Stretch = Stretch.None;

// Define the brush's content.
bottomRightAlignedTileBrush.Drawing = ellipseDrawing;

// Use the brush to paint a rectangle.
Rectangle rectangle2 = new Rectangle();
rectangle2.Width = 150;
rectangle2.Height = 150;
rectangle2.Stroke = Brushes.Red;
rectangle2.StrokeThickness = 2;
rectangle2.Margin = new Thickness(20);
rectangle2.Fill = bottomRightAlignedTileBrush;

<Rectangle
  Width="150" Height="150"
  Stroke="Red" StrokeThickness="2"
  Margin="20">
  <Rectangle.Fill>

    <!-- This brush's content is aligned to the bottom right
         of its tile. -->
    <DrawingBrush 
      Stretch="None"
      AlignmentX="Right"
      AlignmentY="Bottom">
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="MediumBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
              <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Brush="Gray" Thickness="10" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Rectangle.Fill>
</Rectangle>

Example

The next example aligns the content of a DrawingBrush to the upper-left corner of its tile by setting the AlignmentX property to Left and the AlignmentY property to Top. It also sets the Viewport and TileMode of the DrawingBrush to produce a tile pattern. The example produces the following output.

A tiled TileBrush with top-left alignment

Tile pattern with content aligned to upper-left in base tile

The illustration highlights a base tile so that you can see how its content is aligned. Notice that the AlignmentX setting has no effect because the content of the DrawingBrush completely fills the base tile horizontally.

//
// Create a TileBrush that generates a 
// tiled pattern and align its
// content to the top-left of its tile.
//
DrawingBrush tiledTopLeftAlignedTileBrush = new DrawingBrush();
tiledTopLeftAlignedTileBrush.AlignmentX = AlignmentX.Left;
tiledTopLeftAlignedTileBrush.AlignmentY = AlignmentY.Top;
tiledTopLeftAlignedTileBrush.Stretch = Stretch.Uniform;

// Set the brush's Viewport and TileMode to produce a 
// tiled pattern.
tiledTopLeftAlignedTileBrush.Viewport = new Rect(0, 0, 0.25, 0.5);
tiledTopLeftAlignedTileBrush.TileMode = TileMode.Tile;

// Define the brush's content.
tiledTopLeftAlignedTileBrush.Drawing = ellipseDrawing;

// Use the brush to paint a rectangle.
Rectangle rectangle3 = new Rectangle();
rectangle3.Width = 150;
rectangle3.Height = 150;
rectangle3.Stroke = Brushes.Black;
rectangle3.StrokeThickness = 2;
rectangle3.Margin = new Thickness(20);
rectangle3.Fill = tiledTopLeftAlignedTileBrush;

<Rectangle
 Width="150" Height="150"
 Stroke="Black" StrokeThickness="2"
 Margin="20">
  <Rectangle.Fill>

    <!-- This brush's content is aligned to the top left
         of its tile.  -->
    <DrawingBrush 
      Stretch="Uniform"
      Viewport="0,0,0.25,0.5"
      TileMode="Tile" 
      AlignmentX="Left"
      AlignmentY="Top">
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="MediumBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
              <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Brush="Gray" Thickness="10" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Rectangle.Fill>
</Rectangle>

Example

The final example aligns the content of a tiled DrawingBrush to the lower-right of its base tile by setting the AlignmentX property to Right and the AlignmentY property to Bottom. The example produces the following output.

A tiled TileBrush with bottom-right alignment

Tile pattern with content aligned to lower-right in base tile

Again, the AlignmentX setting has no effect because the content of the DrawingBrush completely fills the base tile horizontally.

//
// Create a TileBrush and align its
// content to the bottom-right of its tile.
//
DrawingBrush bottomRightAlignedTileBrush = new DrawingBrush();
bottomRightAlignedTileBrush.AlignmentX = AlignmentX.Right;
bottomRightAlignedTileBrush.AlignmentY = AlignmentY.Bottom;
bottomRightAlignedTileBrush.Stretch = Stretch.None;

// Define the brush's content.
bottomRightAlignedTileBrush.Drawing = ellipseDrawing;

// Use the brush to paint a rectangle.
Rectangle rectangle2 = new Rectangle();
rectangle2.Width = 150;
rectangle2.Height = 150;
rectangle2.Stroke = Brushes.Red;
rectangle2.StrokeThickness = 2;
rectangle2.Margin = new Thickness(20);
rectangle2.Fill = bottomRightAlignedTileBrush;

<Rectangle
  Width="150" Height="150"
  Stroke="Red" StrokeThickness="2"
  Margin="20">
  <Rectangle.Fill>

    <!-- This brush's content is aligned to the bottom right
         of its tile. -->
    <DrawingBrush 
      Stretch="None"
      AlignmentX="Right"
      AlignmentY="Bottom">
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="MediumBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
              <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Brush="Gray" Thickness="10" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Rectangle.Fill>
</Rectangle>

The examples use DrawingBrush objects to demonstrate how the AlignmentX and AlignmentY properties are used. These properties behave identically for all the tile brushes: DrawingBrushImageBrush, and VisualBrush. For more information about tile brushes, see Painting with Images, Drawings, and Visuals.




Set the Tile Size for a TileBrush


This example shows how to set the tile size for a TileBrush. By default, a TileBrush produces a single tile that completely fills the area that you are painting. You can override this behavior by setting the Viewport and ViewportUnits properties.

The Viewport property specifies the tile size for a TileBrush. By default, the value of the Viewport property is relative to the size of the area being painted. To make the Viewport property specify an absolute tile size, set the ViewportUnits property to Absolute.

Example

The following example uses an ImageBrush, a type of TileBrush, to paint a rectangle with tiles. The example sets each tile to 50 percent by 50 percent of the output area (the rectangle). As a result, the rectangle is painted with four projections of the image.

The following illustration shows the output that the example produces .

Example of tiling with an image brush

//
// Create an ImageBrush and set the size of each
// tile to 50% by 50% of the area being painted. 
// 
ImageBrush relativeTileSizeImageBrush = new ImageBrush();
relativeTileSizeImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\cherries_larger.jpg", UriKind.Relative));
relativeTileSizeImageBrush.TileMode = TileMode.Tile;

// Specify the size of the base tile. 
// By default, the size of the Viewport is
// relative to the area being painted,
// so a value of 0.5 indicates 50% of the output
// area.
relativeTileSizeImageBrush.Viewport = new Rect(0, 0, 0.5, 0.5);

// Create a rectangle and paint it with the ImageBrush.
Rectangle relativeTileSizeExampleRectangle = new Rectangle();
relativeTileSizeExampleRectangle.Width = 200;
relativeTileSizeExampleRectangle.Height = 150;
relativeTileSizeExampleRectangle.Stroke = Brushes.LimeGreen;
relativeTileSizeExampleRectangle.StrokeThickness = 1;
relativeTileSizeExampleRectangle.Fill = relativeTileSizeImageBrush;

The next example creates an ImageBrush, sets its Viewport to 0,0,25,25 and its ViewportUnits to Absolute, and uses it to paint another rectangle. As a result, the brush produces tiles that have a width of 25 pixels and a height of 25 pixels .

The following illustration shows the output that the example produces.

A tiled TileBrush with a Viewport of 0,0,0.25,0.25

//
// Create an ImageBrush and set the size of each
// tile to 25 by 25 pixels. 
// 
ImageBrush absoluteTileSizeImageBrush = new ImageBrush();
absoluteTileSizeImageBrush.ImageSource =
     new BitmapImage(new Uri(@"sampleImages\cherries_larger.jpg", UriKind.Relative));
absoluteTileSizeImageBrush.TileMode = TileMode.Tile;

// Specify that the Viewport is to be interpreted as
// an absolute value. 
absoluteTileSizeImageBrush.ViewportUnits = BrushMappingMode.Absolute;

// Set the size of the base tile. Had we left ViewportUnits set
// to RelativeToBoundingBox (the default value), 
// each tile would be 25 times the size of the area being
// painted. Because ViewportUnits is set to Absolute,
// the following line creates tiles that are 25 by 25 pixels.
absoluteTileSizeImageBrush.Viewport = new Rect(0, 0, 25, 25);

// Create a rectangle and paint it with the ImageBrush.
Rectangle absoluteTileSizeExampleRectangle = new Rectangle();
absoluteTileSizeExampleRectangle.Width = 200;
absoluteTileSizeExampleRectangle.Height = 150;
absoluteTileSizeExampleRectangle.Stroke = Brushes.LimeGreen;
absoluteTileSizeExampleRectangle.StrokeThickness = 1;
absoluteTileSizeExampleRectangle.Fill = absoluteTileSizeImageBrush;

The preceding examples are part of a larger sample. For the complete sample, see ImageBrush Sample.

Although this example uses the ImageBrush class, the Viewport and ViewportUnits properties behave identically for the other TileBrush objects, that is, for DrawingBrush and VisualBrush. For more information about ImageBrush and the other TileBrush objects, see Painting with Images, Drawings, and Visuals.




Transform a Brush


This example shows how to transform Brush objects by using their two transformation properties: RelativeTransform and Transform.

The following examples use a RotateTransform to rotate the content of an ImageBrush by 45 degrees.

The following illustration shows the ImageBrush without a RotateTransform, with the RotateTransform applied to the RelativeTransform property, and with the RotateTransform applied to the Transform property.

Brush RelativeTransform and Transform settings

Example

The first example applies a RotateTransform to the RelativeTransform property of an ImageBrush. The CenterX and CenterY properties of a RotateTransform object are both set to 0.5, which is the relative coordinate of the center point of this content. As a result, the ImageBrush content rotates about its center.

//
// Create an ImageBrush with a relative transform and
// use it to paint a rectangle.
//
ImageBrush relativeTransformImageBrush = new ImageBrush();
relativeTransformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's RelativeTransform property.
RotateTransform aRotateTransform = new RotateTransform();
aRotateTransform.CenterX = 0.5; 
aRotateTransform.CenterY = 0.5;
aRotateTransform.Angle = 45;
relativeTransformImageBrush.RelativeTransform = aRotateTransform;

// Use the brush to paint a rectangle.
Rectangle relativeTransformImageBrushRectangle = new Rectangle();
relativeTransformImageBrushRectangle.Width = 175;
relativeTransformImageBrushRectangle.Height = 90;
relativeTransformImageBrushRectangle.Stroke = Brushes.Black;
relativeTransformImageBrushRectangle.Fill = relativeTransformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.RelativeTransform>
        <RotateTransform CenterX="0.5" CenterY="0.5" Angle="45" />
      </ImageBrush.RelativeTransform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

The second example also applies a RotateTransform to an ImageBrush; however, this example uses the Transform property instead of the RelativeTransform property.

To rotate the brush about its center, the example sets the CenterX and CenterY properties of the RotateTransform object to absolute coordinates. Because the brush paints a rectangle that is 175 by 90 pixels, the center point of the rectangle is (87.5, 45).

//
// Create an ImageBrush with a transform and
// use it to paint a rectangle.
//
ImageBrush transformImageBrush = new ImageBrush();
transformImageBrush.ImageSource =
    new BitmapImage(new Uri(@"sampleImages\pinkcherries.jpg", UriKind.Relative));

// Create a 45 rotate transform about the brush's center
// and apply it to the brush's Transform property.
RotateTransform anotherRotateTransform = new RotateTransform();
anotherRotateTransform.CenterX = 87.5;
anotherRotateTransform.CenterY = 45;
anotherRotateTransform.Angle = 45;
transformImageBrush.Transform = anotherRotateTransform;

// Use the brush to paint a rectangle.
Rectangle transformImageBrushRectangle = new Rectangle();
transformImageBrushRectangle.Width = 175;
transformImageBrushRectangle.Height = 90;
transformImageBrushRectangle.Stroke = Brushes.Black;
transformImageBrushRectangle.Fill = transformImageBrush;

<Rectangle Width="175" Height="90" Stroke="Black">
  <Rectangle.Fill>
    <ImageBrush ImageSource="sampleImages\pinkcherries.jpg">
      <ImageBrush.Transform>
        <RotateTransform CenterX="87.5" CenterY="45" Angle="45" />
      </ImageBrush.Transform>
    </ImageBrush>
  </Rectangle.Fill>
</Rectangle>

For a description of how the RelativeTransform and Transform properties work, see the Brush Transformation Overview.

For the complete sample, see Brushes Sample. For more information about brushes, see Painting with Solid Colors and Gradients Overview.




Use System Colors in a Gradient


To use a system color in a gradient, you use the <SystemColor>Color and <SystemColor>ColorKey static properties of the SystemColors class to obtain a reference to the color, where <SystemColor> is the name of the desired system color. Use the <SystemColor>ColorKey properties when you want to create a dynamic reference that updates automatically as the system theme changes. Otherwise, use the <SystemColor>Color properties.

Example

The following example uses dynamic system color resources to create a gradient.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  WindowTitle="Dynamic System Colors Example" Background="White">  
  <StackPanel Margin="20">

    <!-- Uses dynamic references to system colors to set
         the colors of gradient stops. 
         If these system colors change while this application
         is running, the gradient will be updated
         automatically.  -->
    <Button Content="Hello, World!">
      <Button.Background>
        <LinearGradientBrush>
          <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.0" 
              Color="{DynamicResource {x:Static SystemColors.DesktopColorKey}}" />
            <GradientStop Offset="1.0" 
              Color="{DynamicResource {x:Static SystemColors.ControlLightLightColorKey}}" />
          </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
      </Button.Background>
    </Button>

  </StackPanel>
</Page>

The next example uses static system color resources to create a gradient.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  WindowTitle="Static System Colors Example" Background="White">  
  <StackPanel Margin="20">

    <!-- Uses static references to system colors to set
         the colors of gradient stops. 
         If these system colors change while this application
         is running, this button will not be updated until
         the page is loaded again. -->
    <Button Content="Hello, World!">
      <Button.Background>
        <LinearGradientBrush>
          <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.0" 
              Color="{x:Static SystemColors.DesktopColor}" />
            <GradientStop Offset="1.0" 
              Color="{x:Static SystemColors.ControlLightLightColor}" />
          </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
      </Button.Background>
    </Button>

  </StackPanel>
</Page>






Drawings


Drawing Objects Overview


This topic introduces Drawing objects and describes how to use them to efficiently draw shapes, bitmaps, text, and media. Use Drawing objects when you create clip art, paint with a DrawingBrush, or use Visual objects.

What Is a Drawing Object?

Drawing object describes visible content, such as a shape, bitmap, video, or a line of text. Different types of drawings describe different types of content. The following is a list of the different types of drawing objects.

Drawing objects are versatile; there are many ways you can use a Drawing object.

WPF provides other types of objects that are capable of drawing shapes, bitmaps, text, and media. For example, you can also use Shape objects to draw shapes, and the MediaElement control provides another way to add video to your application. So when should you use Drawing objects? When you can sacrifice framework level features to gain performance benefits or when you need Freezable features. Because Drawing objects lack support for Layout, input, and focus, they provide performance benefits that make them ideal for describing backgrounds, clip art, and for low-level drawing with Visual objects.

Because they are a type Freezable object, Drawing objects gain several special features, which include the following: they can be declared as resources, shared among multiple objects, made read-only to improve performance, cloned, and made thread-safe. For more information about the different features provided by Freezable objects, see the Freezable Objects Overview.

Draw a Shape

To draw a shape, you use a GeometryDrawing. A geometry drawing's Geometry property describes the shape to draw, its Brush property describes how the interior of the shape should be painted, and its Pen property describes how its outline should be drawn.

The following example uses a GeometryDrawing to draw a shape. The shape is described by a GeometryGroup and two EllipseGeometry objects. The shape's interior is painted with a LinearGradientBrush and its outline is drawn with a Black Pen.

This example creates the following GeometryDrawing.

A GeometryDrawing of two ellipses

A GeometryDrawing

//
// Create the Geometry to draw.
//
GeometryGroup ellipses = new GeometryGroup();
ellipses.Children.Add(
    new EllipseGeometry(new Point(50,50), 45, 20)
    );
ellipses.Children.Add(
    new EllipseGeometry(new Point(50, 50), 20, 45)
    );


//
// Create a GeometryDrawing.
//
GeometryDrawing aGeometryDrawing = new GeometryDrawing();
aGeometryDrawing.Geometry = ellipses;

// Paint the drawing with a gradient.
aGeometryDrawing.Brush = 
    new LinearGradientBrush(
        Colors.Blue, 
        Color.FromRgb(204,204,255), 
        new Point(0,0), 
        new Point(1,1));

// Outline the drawing with a solid color.
aGeometryDrawing.Pen = new Pen(Brushes.Black, 10);
<GeometryDrawing>
  <GeometryDrawing.Geometry>

    <!-- Create a composite shape. -->
    <GeometryGroup>
      <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
      <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
    </GeometryGroup>
  </GeometryDrawing.Geometry>
  <GeometryDrawing.Brush>

    <!-- Paint the drawing with a gradient. -->
    <LinearGradientBrush>
      <GradientStop Offset="0.0" Color="Blue" />
      <GradientStop Offset="1.0" Color="#CCCCFF" />
    </LinearGradientBrush>
  </GeometryDrawing.Brush>
  <GeometryDrawing.Pen>

    <!-- Outline the drawing with a solid color. -->
    <Pen Thickness="10" Brush="Black" />
  </GeometryDrawing.Pen>
</GeometryDrawing>

For the complete example, see How to: Create a GeometryDrawing.

Other Geometry classes, such as PathGeometry enable you to create more complex shapes by creating curves and arcs. For more information about Geometry objects, see the Geometry Overview.

For more information about other ways to draw shapes that don't use Drawing objects, see Shapes and Basic Drawing in WPF Overview.

Draw an Image

To draw an image, you use an ImageDrawing. An ImageDrawing object's ImageSource property describes the image to draw, and its Rect property defines the region where the image is drawn.

The following example draws an image into a rectangle located at (75,75) that is 100 by 100 pixel. The following illustration shows the ImageDrawing created by the example. A gray border was added to show the bounds of the ImageDrawing.

A 100 by 100 ImageDrawing drawn at (75,75)

A 100 by 100 ImageDrawing

// Create a 100 by 100 image with an upper-left point of (75,75). 
ImageDrawing bigKiwi = new ImageDrawing();
bigKiwi.Rect = new Rect(75, 75, 100, 100);
bigKiwi.ImageSource = new BitmapImage(
    new Uri(@"sampleImages\kiwi.png", UriKind.Relative));
<!-- The Rect property specifies that the image only fill a 100 by 100
     rectangular area. -->
<ImageDrawing Rect="75,75,100,100" ImageSource="sampleImages\kiwi.png"/>

For more information about images, see the Imaging Overview.

Play Media (Code Only)

System_CAPS_noteNote

Although you can declare a VideoDrawing in Extensible Application Markup Language (XAML), you can only load and play its media using code. To play video in Extensible Application Markup Language (XAML), use a MediaElement instead.

To play an audio or video file, you use a VideoDrawing and a MediaPlayer. There are two ways to load and play media. The first is to use a MediaPlayer and a VideoDrawing by themselves, and the second way is to create your own MediaTimeline to use with the MediaPlayer and VideoDrawing.

System_CAPS_noteNote

When distributing media with your application, you cannot use a media file as a project resource, like you would an image. In your project file, you must instead set the media type to Content and set CopyToOutputDirectory to PreserveNewest or Always.

To play media without creating your own MediaTimeline, you perform the following steps.

  1. Create a MediaPlayer object.

    MediaPlayer player = new MediaPlayer();
    
  2. Use the Open method to load the media file.

    player.Open(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative));
    
  3. Create a VideoDrawing.

    VideoDrawing aVideoDrawing = new VideoDrawing();
    
  4. Specify the size and location to draw the media by setting the Rect property of the VideoDrawing.

    aVideoDrawing.Rect = new Rect(0, 0, 100, 100);
    
  5. Set the Player property of the VideoDrawing with the MediaPlayer you created.

    aVideoDrawing.Player = player;
    
  6. Use the Play method of the MediaPlayer to start playing the media.

    // Play the video once.
    player.Play();        
    

The following example uses a VideoDrawing and a MediaPlayer to play a video file once.

//
// Create a VideoDrawing.
//      
MediaPlayer player = new MediaPlayer();

player.Open(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative));

VideoDrawing aVideoDrawing = new VideoDrawing();

aVideoDrawing.Rect = new Rect(0, 0, 100, 100);

aVideoDrawing.Player = player;

// Play the video once.
player.Play();        

To gain additional timing control over the media, use a MediaTimeline with the MediaPlayer and VideoDrawing objects. The MediaTimeline enables you to specify whether the video should repeat. To use a MediaTimeline with a VideoDrawing, you perform the following steps:

  1. Declare the MediaTimeline and set its timing behaviors.

    // Create a MediaTimeline.
    MediaTimeline mTimeline = 
        new MediaTimeline(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative)); 
    
    // Set the timeline to repeat.
    mTimeline.RepeatBehavior = RepeatBehavior.Forever;
    
  2. Create a MediaClock from the MediaTimeline.

    // Create a clock from the MediaTimeline.
    MediaClock mClock = mTimeline.CreateClock();
    
  3. Create a MediaPlayer and use the MediaClock to set its Clock property.

    MediaPlayer repeatingVideoDrawingPlayer = new MediaPlayer();
    repeatingVideoDrawingPlayer.Clock = mClock;
    
  4. Create a VideoDrawing and assign the MediaPlayer to the Player property of the VideoDrawing.

    VideoDrawing repeatingVideoDrawing = new VideoDrawing();
    repeatingVideoDrawing.Rect = new Rect(150, 0, 100, 100);
    repeatingVideoDrawing.Player = repeatingVideoDrawingPlayer;  
    

The following example uses a MediaTimeline with a MediaPlayer and a VideoDrawing to play a video repeatedly.

//
// Create a VideoDrawing that repeats.
//

// Create a MediaTimeline.
MediaTimeline mTimeline = 
    new MediaTimeline(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative)); 

// Set the timeline to repeat.
mTimeline.RepeatBehavior = RepeatBehavior.Forever;

// Create a clock from the MediaTimeline.
MediaClock mClock = mTimeline.CreateClock();

MediaPlayer repeatingVideoDrawingPlayer = new MediaPlayer();
repeatingVideoDrawingPlayer.Clock = mClock;

VideoDrawing repeatingVideoDrawing = new VideoDrawing();
repeatingVideoDrawing.Rect = new Rect(150, 0, 100, 100);
repeatingVideoDrawing.Player = repeatingVideoDrawingPlayer;  

Note that, when you use a MediaTimeline, you use the interactive ClockController returned from the Controller property of the MediaClock to control media playback instead of the interactive methods of MediaPlayer.

Draw Text

To draw text, you use a GlyphRunDrawing and a GlyphRun. The following example uses a GlyphRunDrawing to draw the text "Hello World".

GlyphRun theGlyphRun = new GlyphRun(
    new GlyphTypeface(new Uri(@"C:\WINDOWS\Fonts\TIMES.TTF")),
    0,
    false,
    13.333333333333334,
    new ushort[]{43, 72, 79, 79, 82, 3, 58, 82, 85, 79, 71},
    new Point(0, 12.29),
    new double[]{
        9.62666666666667, 7.41333333333333, 2.96, 
        2.96, 7.41333333333333, 3.70666666666667, 
        12.5866666666667, 7.41333333333333, 
        4.44, 2.96, 7.41333333333333},
    null,
    null,
    null,
    null,
    null,
    null


    );

GlyphRunDrawing gDrawing = new GlyphRunDrawing(Brushes.Black, theGlyphRun);
<GlyphRunDrawing ForegroundBrush="Black">
  <GlyphRunDrawing.GlyphRun>
    <GlyphRun 
      CaretStops="{x:Null}" 
      ClusterMap="{x:Null}" 
      IsSideways="False" 
      GlyphOffsets="{x:Null}" 
      GlyphIndices="43 72 79 79 82 3 58 82 85 79 71" 
      BaselineOrigin="0,12.29"  
      FontRenderingEmSize="13.333333333333334" 
      DeviceFontName="{x:Null}" 
      AdvanceWidths="9.62666666666667 7.41333333333333 2.96 2.96 7.41333333333333 3.70666666666667 12.5866666666667 7.41333333333333 4.44 2.96 7.41333333333333" 
      BidiLevel="0">
      <GlyphRun.GlyphTypeface>
        <GlyphTypeface FontUri="C:\WINDOWS\Fonts\TIMES.TTF" />
      </GlyphRun.GlyphTypeface>
    </GlyphRun>
  </GlyphRunDrawing.GlyphRun>
</GlyphRunDrawing>

GlyphRun is a low-level object intended for use with fixed-format document presentation and print scenarios. A simpler way to draw text to the screen is to use a Label or a TextBlock. For more information about GlyphRun, see the Introduction to the GlyphRun Object and Glyphs Element overview.

Composite Drawings

DrawingGroup enables you to combine multiple drawings into a single composite drawing. By using a DrawingGroup, you can combine shapes, images, and text into a single Drawing object.

The following example uses a DrawingGroup to combine two GeometryDrawing objects and an ImageDrawing object. This example produces the following output.

A DrawingGroup with multiple drawings

A composite drawing

//
// Create three drawings.
//
GeometryDrawing ellipseDrawing =
    new GeometryDrawing(
        new SolidColorBrush(Color.FromArgb(102, 181, 243, 20)),
        new Pen(Brushes.Black, 4),
        new EllipseGeometry(new Point(50,50), 50, 50)
    );

ImageDrawing kiwiPictureDrawing = 
    new ImageDrawing(
        new BitmapImage(new Uri(@"sampleImages\kiwi.png", UriKind.Relative)), 
        new Rect(50,50,100,100));

GeometryDrawing ellipseDrawing2 =
    new GeometryDrawing(
        new SolidColorBrush(Color.FromArgb(102,181,243,20)),
        new Pen(Brushes.Black, 4),
        new EllipseGeometry(new Point(150, 150), 50, 50)
    );

// Create a DrawingGroup to contain the drawings.
DrawingGroup aDrawingGroup = new DrawingGroup();
aDrawingGroup.Children.Add(ellipseDrawing);
aDrawingGroup.Children.Add(kiwiPictureDrawing);
aDrawingGroup.Children.Add(ellipseDrawing2);

<DrawingGroup>

  <GeometryDrawing Brush="#66B5F314">
    <GeometryDrawing.Geometry>
      <EllipseGeometry Center="50,50" RadiusX="50"  RadiusY="50"/>
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Pen>
      <Pen Brush="Black" Thickness="4" />
    </GeometryDrawing.Pen>
  </GeometryDrawing>
  <ImageDrawing ImageSource="sampleImages\kiwi.png" Rect="50,50,100,100"/>
  <GeometryDrawing Brush="#66B5F314">
    <GeometryDrawing.Geometry>
      <EllipseGeometry Center="150,150" RadiusX="50"  RadiusY="50"/>
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Pen>
      <Pen Brush="Black" Thickness="4" />
    </GeometryDrawing.Pen>
  </GeometryDrawing>
</DrawingGroup>

DrawingGroup also enables you to apply opacity masks, transforms, bitmap effects, and other operations to its contents. DrawingGroup operations are applied in the following order: OpacityMaskOpacityBitmapEffectClipGeometryGuidelineSet, and then Transform.

The following illustration shows the order in which DrawingGroup operations are applied.

DrawingGroup order of operations

Order of DrawingGroup operations

The following table describes the properties you can use to manipulate a DrawingGroup object's contents.

Property

Description

Illustration

OpacityMask

Alters the opacity of selected portions of the DrawingGroup contents. For an example, see How to: Control the Opacity of a Drawing.

A DrawingGroup with an opacity mask

Opacity

Uniformly changes the opacity of the DrawingGroup contents. Use this property to make a Drawing transparent or partially transparent. For an example, see How to: Apply an Opacity Mask to a Drawing.

DrawingGroups with different opacity settings

BitmapEffect

Applies a BitmapEffect to the DrawingGroup contents. For an example, see How to: Apply a BitmapEffect to a Drawing.

DrawingGroup with a BlurBitmapEffect

ClipGeometry

Clips the DrawingGroup contents to a region you describe using a Geometry. For an example, see How to: Clip a Drawing .

DrawingGroup with a defined clip region

GuidelineSet

Snaps device independent pixels to device pixels along the specified guidelines. This property is useful for ensuring that finely detailed graphics render sharply on low-DPI displays. For an example, see How to: Apply a GuidelineSet to a Drawing.

A DrawingGroup with and without a GuidelineSet

Transform

Transforms the DrawingGroup contents. For an example, see How to: Apply a Transform to a Drawing.

A rotated DrawingGroup

Display a Drawing as an Image

To display a Drawing with an Image control, use a DrawingImage as the Image control's Source and set the DrawingImage object's DrawingImage.Drawing property to the drawing you want to display.

The following example uses a DrawingImage and an Image control to display a GeometryDrawing. This example produces the following output.

A GeometryDrawing of two ellipses

A DrawingImage

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SDKSample
{
    public class DrawingImageExample : Page
    {

        public DrawingImageExample()
        {

            //
            // Create the Geometry to draw.
            //
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50,50), 45, 20)
                );
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50, 50), 20, 45)
                );

            //
            // Create a GeometryDrawing.
            //
            GeometryDrawing aGeometryDrawing = new GeometryDrawing();
            aGeometryDrawing.Geometry = ellipses;

            // Paint the drawing with a gradient.
            aGeometryDrawing.Brush = 
                new LinearGradientBrush(
                    Colors.Blue, 
                    Color.FromRgb(204,204,255), 
                    new Point(0,0), 
                    new Point(1,1));

            // Outline the drawing with a solid color.
            aGeometryDrawing.Pen = new Pen(Brushes.Black, 10);

            //
            // Use a DrawingImage and an Image control
            // to display the drawing.
            //
            DrawingImage geometryImage = new DrawingImage(aGeometryDrawing);

            // Freeze the DrawingImage for performance benefits.
            geometryImage.Freeze();

            Image anImage = new Image();
            anImage.Source = geometryImage;
            anImage.HorizontalAlignment = HorizontalAlignment.Left;

            //
            // Place the image inside a border and
            // add it to the page.
            //
            Border exampleBorder = new Border();
            exampleBorder.Child = anImage;
            exampleBorder.BorderBrush = Brushes.Gray;
            exampleBorder.BorderThickness = new Thickness(1);
            exampleBorder.HorizontalAlignment = HorizontalAlignment.Left;
            exampleBorder.VerticalAlignment = VerticalAlignment.Top;
            exampleBorder.Margin = new Thickness(10);

            this.Margin = new Thickness(20);
            this.Background = Brushes.White;
            this.Content = exampleBorder;
        }

    }
}
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Background="White" Margin="20">

  <Border BorderBrush="Gray" BorderThickness="1" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="10">

    <!-- This image uses a Drawing object for its source. -->
    <Image>
      <Image.Source>
        <DrawingImage PresentationOptions:Freeze="True">
          <DrawingImage.Drawing>
            <GeometryDrawing>
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                  <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Brush>
                <LinearGradientBrush>
                  <GradientStop Offset="0.0" Color="Blue" />
                  <GradientStop Offset="1.0" Color="#CCCCFF" />
                </LinearGradientBrush>
              </GeometryDrawing.Brush>
              <GeometryDrawing.Pen>
                <Pen Thickness="10" Brush="Black" />
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingImage.Drawing>
        </DrawingImage>
      </Image.Source>
    </Image>
  </Border>

</Page>

Paint an Object with a Drawing

DrawingBrush is a type of brush that paints an area with a drawing object. You can use it to paint just about any graphical object with a drawing. The Drawing property of a DrawingBrush describes its Drawing. To render a Drawing with a DrawingBrush, add it to the brush using the brush's Drawing property and use the brush to paint a graphical object, such as a control or panel.

The following examples uses a DrawingBrush to paint the Fill of a Rectangle with a pattern created from a GeometryDrawing. This example produces the following output.

A tiled DrawingBrush

A GeometryDrawing used with a DrawingBrush

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SDKSample
{
    public class DrawingBrushExample : Page
    {

        public DrawingBrushExample()
        {

            //
            // Create the Geometry to draw.
            //
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50,50), 45, 20)
                );
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50, 50), 20, 45)
                );

            //
            // Create a GeometryDrawing.
            //
            GeometryDrawing aGeometryDrawing = new GeometryDrawing();
            aGeometryDrawing.Geometry = ellipses;

            // Paint the drawing with a gradient.
            aGeometryDrawing.Brush = 
                new LinearGradientBrush(
                    Colors.Blue, 
                    Color.FromRgb(204,204,255), 
                    new Point(0,0), 
                    new Point(1,1));

            // Outline the drawing with a solid color.
            aGeometryDrawing.Pen = new Pen(Brushes.Black, 10);

            DrawingBrush patternBrush = new DrawingBrush(aGeometryDrawing);
            patternBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
            patternBrush.TileMode = TileMode.Tile;
            patternBrush.Freeze();

            //
            // Create an object to paint.
            //
            Rectangle paintedRectangle = new Rectangle();
            paintedRectangle.Width = 100;
            paintedRectangle.Height = 100;
            paintedRectangle.Fill = patternBrush;

            //
            // Place the image inside a border and
            // add it to the page.
            //
            Border exampleBorder = new Border();
            exampleBorder.Child = paintedRectangle;
            exampleBorder.BorderBrush = Brushes.Gray;
            exampleBorder.BorderThickness = new Thickness(1);
            exampleBorder.HorizontalAlignment = HorizontalAlignment.Left;
            exampleBorder.VerticalAlignment = VerticalAlignment.Top;
            exampleBorder.Margin = new Thickness(10);

            this.Margin = new Thickness(20);
            this.Background = Brushes.White;
            this.Content = exampleBorder;
        }
    }
}
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Margin="20" Background="White">

  <Border BorderBrush="Gray" BorderThickness="1" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="10">
    <Rectangle Width="100" Height="100">
      <Rectangle.Fill>
        <DrawingBrush PresentationOptions:Freeze="True"
                      Viewport="0,0,0.25,0.25" TileMode="Tile">
          <DrawingBrush.Drawing>
            <GeometryDrawing>
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                  <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Brush>
                <LinearGradientBrush>
                  <GradientStop Offset="0.0" Color="Blue" />
                  <GradientStop Offset="1.0" Color="#CCCCFF" />
                </LinearGradientBrush>
              </GeometryDrawing.Brush>
              <GeometryDrawing.Pen>
                <Pen Thickness="10" Brush="Black" />
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingBrush.Drawing>
        </DrawingBrush>
      </Rectangle.Fill>

    </Rectangle>
  </Border>


</Page>

The DrawingBrush class provides a variety of options for stretching and tiling its content. For more information about DrawingBrush, see the Painting with Images, Drawings, and Visuals overview.

Render a Drawing with a Visual

DrawingVisual is a type of visual object designed to render a drawing. Working directly at the visual layer is an option for developers who want to build a highly customized graphical environment, and is not described in this overview. For more information, see the Using DrawingVisual Objects overview.

DrawingContext Objects

The DrawingContext class enables you to populate a Visual or a Drawing with visual content. Many such lower-level graphics objects use a DrawingContext because it describes graphical content very efficiently.

Although the DrawingContext draw methods appear similar to the draw methods of the System.Drawing.Graphics type, they are actually very different. DrawingContext is used with a retained mode graphics system, while the System.Drawing.Graphics type is used with an immediate mode graphics system. When you use a DrawingContext object's draw commands, you are actually storing a set of rendering instructions (although the exact storage mechanism depends on the type of object that supplies the DrawingContext) that will later be used by the graphics system; you are not drawing to the screen in real-time. For more information about how the Windows Presentation Foundation (WPF) graphics system works, see the WPF Graphics Rendering Overview.

You never directly instantiate a DrawingContext; you can, however, acquire a drawing context from certain methods, such as DrawingGroup.Open and DrawingVisual.RenderOpen.

Enumerate the Contents of a Visual

In addition to their other uses, Drawing objects also provide an object model for enumerating the contents of a Visual.

The following example uses the GetDrawing method to retrieve the DrawingGroup value of a Visual and enumerate it.

public void RetrieveDrawing(Visual v)
{
    DrawingGroup dGroup = VisualTreeHelper.GetDrawing(v);
    EnumDrawingGroup(dGroup);

}

 // Enumerate the drawings in the DrawingGroup.
 public void EnumDrawingGroup(DrawingGroup drawingGroup)
 {
     DrawingCollection dc = drawingGroup.Children;

     // Enumerate the drawings in the DrawingCollection.
     foreach (Drawing drawing in dc)
     {
         // If the drawing is a DrawingGroup, call the function recursively.
         if (drawing.GetType() == typeof(DrawingGroup))
         {
             EnumDrawingGroup((DrawingGroup)drawing);
         }
         else if (drawing.GetType() == typeof(GeometryDrawing))
         {
             // Perform action based on drawing type.  
         }
         else if (drawing.GetType() == typeof(ImageDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(GlyphRunDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(VideoDrawing))
         {
             // Perform action based on drawing type.
         }
     }
 }





How-to Topics



Apply a GuidelineSet to a Drawing


This example shows how to apply a GuidelineSet to a DrawingGroup.

The DrawingGroup class is the only type of Drawing that has a GuidelineSet property. To apply a GuidelineSet to another type of Drawing, add it to a DrawingGroup and then apply the GuidelineSet to your DrawingGroup.

Example

The following example creates two DrawingGroup objects that are almost identical; the only difference is: the second DrawingGroup has a GuidelineSet and the first does not.

The following illustration shows the output from the example. Because the rendering difference between the two DrawingGroup objects is so subtle, portions of the drawings are enlarged.

A DrawingGroup with and without a GuidelineSet
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SDKSample
{
    /// <summary>
    /// This example shows how to apply a GuidelineSet to 
    /// a drawing.
    /// </summary>
	public class DrawingGroupGuidelineSetExample : Page
	{
        public DrawingGroupGuidelineSetExample()
        {

            //
            // Create a DrawingGroup
            // that has no guideline set
            //          
            GeometryDrawing drawing1 = new GeometryDrawing(
                    Brushes.Black, 
                    null,
                    new RectangleGeometry(new Rect(0,20,30,80))
                );

            GeometryGroup whiteRectangles = new GeometryGroup();
            whiteRectangles.Children.Add(new RectangleGeometry(new Rect(5.5, 25, 20, 20)));
            whiteRectangles.Children.Add(new RectangleGeometry(new Rect(5.5, 50, 20, 20)));
            whiteRectangles.Children.Add(new RectangleGeometry(new Rect(5.5, 75, 20, 20)));

            GeometryDrawing drawing2 = new GeometryDrawing(
                    Brushes.White,
                    null,
                    whiteRectangles
                );

            // Create a DrawingGroup
            DrawingGroup drawingGroupWithoutGuidelines = new DrawingGroup();
            drawingGroupWithoutGuidelines.Children.Add(drawing1);
            drawingGroupWithoutGuidelines.Children.Add(drawing2);

            // Use an Image control and a DrawingImage to
            // display the drawing.
            DrawingImage drawingImage01 = new DrawingImage(drawingGroupWithoutGuidelines);

            // Freeze the DrawingImage for performance benefits.
            drawingImage01.Freeze();

            Image image01 = new Image();
            image01.Source = drawingImage01;
            image01.Stretch = Stretch.None;
            image01.HorizontalAlignment = HorizontalAlignment.Left;
            image01.Margin = new Thickness(10);

            //
            // Create another DrawingGroup and apply 
            // a blur effect to it.
            //

            // Create a clone of the first DrawingGroup.
            DrawingGroup drawingGroupWithGuidelines =
                drawingGroupWithoutGuidelines.Clone();

            // Create a guideline set.
            GuidelineSet guidelines = new GuidelineSet();
            guidelines.GuidelinesX.Add(5.5);
            guidelines.GuidelinesX.Add(25.5);
            guidelines.GuidelinesY.Add(25);
            guidelines.GuidelinesY.Add(50);
            guidelines.GuidelinesY.Add(75);

            // Apply it to the drawing group.
            drawingGroupWithGuidelines.GuidelineSet = guidelines; 

            // Use another Image control and DrawingImage
            // to display the drawing.
            DrawingImage drawingImage02 = new DrawingImage(drawingGroupWithGuidelines);

            // Freeze the DrawingImage for performance benefits.
            drawingImage02.Freeze();

            Image image02 = new Image();
            image02.Source = drawingImage02;
            image02.Stretch = Stretch.None;
            image02.HorizontalAlignment = HorizontalAlignment.Left;
            image02.Margin = new Thickness(50, 10, 10, 10);

            StackPanel mainPanel = new StackPanel();
            mainPanel.Orientation = Orientation.Horizontal;
            mainPanel.HorizontalAlignment = HorizontalAlignment.Left;
            mainPanel.Margin = new Thickness(20);
            mainPanel.Children.Add(image01);
            mainPanel.Children.Add(image02);

            //
            // Use a DrawingBrush to create a grid background.
            //
            GeometryDrawing backgroundRectangleDrawing =
                new GeometryDrawing(
                    Brushes.White,
                    null,
                    new RectangleGeometry(new Rect(0,0,1,1))
                );
            PolyLineSegment backgroundLine1 = new PolyLineSegment();
            backgroundLine1.Points.Add(new Point(1, 0));
            backgroundLine1.Points.Add(new Point(1, 0.1));
            backgroundLine1.Points.Add(new Point(0, 0.1));
            PathFigure line1Figure = new PathFigure();
            line1Figure.Segments.Add(backgroundLine1);
            PathGeometry backgroundLine1Geometry = new PathGeometry();
            backgroundLine1Geometry.Figures.Add(line1Figure);
            GeometryDrawing backgroundLineDrawing1 = new GeometryDrawing(
                    new SolidColorBrush(Color.FromArgb(255,204,204,255)),
                    null,
                    backgroundLine1Geometry
                );
            PolyLineSegment backgroundLine2 = new PolyLineSegment();
            backgroundLine2.Points.Add(new Point(0, 1));
            backgroundLine2.Points.Add(new Point(0.1, 1));
            backgroundLine2.Points.Add(new Point(0.1, 0));
            PathFigure line2Figure = new PathFigure();
            line2Figure.Segments.Add(backgroundLine2);
            PathGeometry backgroundLine2Geometry = new PathGeometry();
            backgroundLine2Geometry.Figures.Add(line2Figure);
            GeometryDrawing backgroundLineDrawing2 = new GeometryDrawing(
                    new SolidColorBrush(Color.FromArgb(255, 204, 204, 255)),
                    null,
                    backgroundLine2Geometry
                );

            DrawingGroup backgroundGroup = new DrawingGroup();
            backgroundGroup.Children.Add(backgroundRectangleDrawing);
            backgroundGroup.Children.Add(backgroundLineDrawing1);
            backgroundGroup.Children.Add(backgroundLineDrawing2);

            DrawingBrush gridPatternBrush = new DrawingBrush(backgroundGroup);
            gridPatternBrush.Viewport = new Rect(0, 0, 10, 10);
            gridPatternBrush.ViewportUnits = BrushMappingMode.Absolute;
            gridPatternBrush.TileMode = TileMode.Tile;
            gridPatternBrush.Freeze();

            Border mainBorder = new Border();
            mainBorder.Background = gridPatternBrush;
            mainBorder.BorderThickness = new Thickness(1);
            mainBorder.BorderBrush = Brushes.Gray;
            mainBorder.HorizontalAlignment = HorizontalAlignment.Left;
            mainBorder.VerticalAlignment = VerticalAlignment.Top;
            mainBorder.Margin = new Thickness(20);
            mainBorder.Child = mainPanel;

            //
            // Add the items to the page.
            //
            this.Content = mainBorder;
            this.Background = Brushes.White;

        }


	}
}
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions">
  <Border BorderThickness="1" BorderBrush="Gray" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="20">
    <StackPanel Margin="20" Orientation="Horizontal">


        <Image Stretch="None" Margin="10">
          <Image.Source>
            <DrawingImage PresentationOptions:Freeze="True">
              <DrawingImage.Drawing>

                <!-- This DrawingGroup has no GuidelineSet. -->
                <DrawingGroup>
                  <GeometryDrawing Brush="Black">
                    <GeometryDrawing.Geometry>
                      <RectangleGeometry Rect="0,20,30,80" />
                    </GeometryDrawing.Geometry>
                  </GeometryDrawing>
                  <GeometryDrawing Brush="White">
                    <GeometryDrawing.Geometry>
                      <GeometryGroup>
                        <RectangleGeometry Rect="5.5,25, 20,20" />
                        <RectangleGeometry Rect="5.5,50, 20,20" />
                        <RectangleGeometry Rect="5.5,75, 20,20" />
                      </GeometryGroup>
                    </GeometryDrawing.Geometry>
                  </GeometryDrawing>
                </DrawingGroup>
              </DrawingImage.Drawing>
            </DrawingImage>
          </Image.Source>
        </Image>

        <Image Stretch="None" Margin="50,10,10,10">
          <Image.Source>
            <DrawingImage PresentationOptions:Freeze="True">
              <DrawingImage.Drawing>

                <!-- This DrawingGroup has a GuidelineSet. -->
                <DrawingGroup>
                  <GeometryDrawing Brush="Black">
                    <GeometryDrawing.Geometry>
                      <RectangleGeometry Rect="0,20,30,80" />
                    </GeometryDrawing.Geometry>
                  </GeometryDrawing>
                  <GeometryDrawing Brush="White">
                    <GeometryDrawing.Geometry>
                      <GeometryGroup>
                        <RectangleGeometry Rect="5.5,25, 20,20" />
                        <RectangleGeometry Rect="5.5,50, 20,20" />
                        <RectangleGeometry Rect="5.5,75, 20,20" />
                      </GeometryGroup>
                    </GeometryDrawing.Geometry>
                  </GeometryDrawing>
                  <DrawingGroup.GuidelineSet>

                    <!-- The GuidelineSet -->
                    <GuidelineSet
                      GuidelinesX="5.5,25.5" GuidelinesY="25,50,75" />
                  </DrawingGroup.GuidelineSet>
                </DrawingGroup>
              </DrawingImage.Drawing>
            </DrawingImage>
          </Image.Source>
        </Image>
    </StackPanel>

    <Border.Background>
      <DrawingBrush  Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile"
        PresentationOptions:Freeze="True">
        <DrawingBrush.Drawing>
          <DrawingGroup>
            <GeometryDrawing Brush="White">
              <GeometryDrawing.Geometry>
                <RectangleGeometry Rect="0,0,1,1" />
              </GeometryDrawing.Geometry>
            </GeometryDrawing>
            <GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
            <GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
          </DrawingGroup>
        </DrawingBrush.Drawing>
      </DrawingBrush>    
    </Border.Background>
  </Border>
</Page>





Create a Composite Drawing


This example shows how to use a DrawingGroup to create complex drawings by combining multiple Drawing objects into a single composite drawing.

Example

The following example uses a DrawingGroup to create a composite drawing from the GeometryDrawing and ImageDrawing objects. The following illustration shows the output that this example produces.

A DrawingGroup with multiple drawings

A composite drawing that is created by using DrawingGroup

Note the gray border, which shows the bounds of the drawing.

//
// Create three drawings.
//
GeometryDrawing ellipseDrawing =
    new GeometryDrawing(
        new SolidColorBrush(Color.FromArgb(102, 181, 243, 20)),
        new Pen(Brushes.Black, 4),
        new EllipseGeometry(new Point(50,50), 50, 50)
    );

ImageDrawing kiwiPictureDrawing = 
    new ImageDrawing(
        new BitmapImage(new Uri(@"sampleImages\kiwi.png", UriKind.Relative)), 
        new Rect(50,50,100,100));

GeometryDrawing ellipseDrawing2 =
    new GeometryDrawing(
        new SolidColorBrush(Color.FromArgb(102,181,243,20)),
        new Pen(Brushes.Black, 4),
        new EllipseGeometry(new Point(150, 150), 50, 50)
    );

// Create a DrawingGroup to contain the drawings.
DrawingGroup aDrawingGroup = new DrawingGroup();
aDrawingGroup.Children.Add(ellipseDrawing);
aDrawingGroup.Children.Add(kiwiPictureDrawing);
aDrawingGroup.Children.Add(ellipseDrawing2);

<DrawingGroup>

  <GeometryDrawing Brush="#66B5F314">
    <GeometryDrawing.Geometry>
      <EllipseGeometry Center="50,50" RadiusX="50"  RadiusY="50"/>
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Pen>
      <Pen Brush="Black" Thickness="4" />
    </GeometryDrawing.Pen>
  </GeometryDrawing>
  <ImageDrawing ImageSource="sampleImages\kiwi.png" Rect="50,50,100,100"/>
  <GeometryDrawing Brush="#66B5F314">
    <GeometryDrawing.Geometry>
      <EllipseGeometry Center="150,150" RadiusX="50"  RadiusY="50"/>
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Pen>
      <Pen Brush="Black" Thickness="4" />
    </GeometryDrawing.Pen>
  </GeometryDrawing>
</DrawingGroup>

You can use a DrawingGroup to apply a TransformOpacity setting, OpacityMaskBitmapEffectClipGeometry, or GuidelineSet to the drawings it contains. Because a DrawingGroup is also a Drawing, it can contain other DrawingGroup objects.

The following example is similar to the preceding example, except that it uses additional DrawingGroup objects to apply bitmap effects and an opacity mask to some of its drawings. The following illustration shows the output that this example produces.

A DrawingGroup with multiple drawings

Composite drawing that has multiple DrawingGroup objects

Note the gray border, which shows the bounds of the drawing.

// Create a DrawingGroup.
DrawingGroup mainGroup = new DrawingGroup();

//
// Create a GeometryDrawing
//
GeometryDrawing ellipseDrawing =
    new GeometryDrawing(
        new SolidColorBrush(Color.FromArgb(102, 181, 243, 20)),
        new Pen(Brushes.Black, 4),
        new EllipseGeometry(new Point(50, 50), 50, 50)
    );

//
// Use a DrawingGroup to apply a blur
// bitmap effect to the drawing.
//
DrawingGroup blurGroup = new DrawingGroup();
blurGroup.Children.Add(ellipseDrawing);
BlurBitmapEffect blurEffect = new BlurBitmapEffect();
blurEffect.Radius = 5;
blurGroup.BitmapEffect = blurEffect;

// Add the DrawingGroup to the main DrawingGroup.
mainGroup.Children.Add(blurGroup);

//
// Create an ImageDrawing.
// 
ImageDrawing kiwiPictureDrawing =
    new ImageDrawing(
        new BitmapImage(new Uri(@"sampleImages\kiwi.png", UriKind.Relative)),
        new Rect(50, 50, 100, 100));

//
// Use a DrawingGroup to apply an opacity mask
// and a bevel.
//
DrawingGroup maskedAndBeveledGroup = new DrawingGroup();
maskedAndBeveledGroup.Children.Add(kiwiPictureDrawing);

// Create an opacity mask.
RadialGradientBrush rgBrush =new RadialGradientBrush();
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(0,0,0,0), 0.55));
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(255,0,0,0), 0.65));
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(0,0,0,0), 0.75));
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(255,0,0,0), 0.80));
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(0,0,0,0), 0.90));
rgBrush.GradientStops.Add(new GradientStop(Color.FromArgb(255,0,0,0), 1.0));
maskedAndBeveledGroup.OpacityMask = rgBrush;

// Apply a bevel.
maskedAndBeveledGroup.BitmapEffect = new BevelBitmapEffect();

// Add the DrawingGroup to the main group.
mainGroup.Children.Add(maskedAndBeveledGroup);

//
// Create another GeometryDrawing.
//
GeometryDrawing ellipseDrawing2 =
  new GeometryDrawing(
      new SolidColorBrush(Color.FromArgb(102, 181, 243, 20)),
      new Pen(Brushes.Black, 4),
      new EllipseGeometry(new Point(150, 150), 50, 50)
  );

// Add the DrawingGroup to the main group.
mainGroup.Children.Add(ellipseDrawing2);

<DrawingGroup>

  <DrawingGroup>
    <GeometryDrawing Brush="#66B5F314">
      <GeometryDrawing.Geometry>
        <EllipseGeometry Center="50,50" RadiusX="50"  RadiusY="50"/>
      </GeometryDrawing.Geometry>
      <GeometryDrawing.Pen>
        <Pen Brush="Black" Thickness="4" />
      </GeometryDrawing.Pen>
    </GeometryDrawing>
    <DrawingGroup.BitmapEffect>
      <BlurBitmapEffect Radius="5" />
    </DrawingGroup.BitmapEffect>
  </DrawingGroup>

  <DrawingGroup>
    <ImageDrawing ImageSource="sampleImages\kiwi.png" Rect="50,50,100,100"/>
    <DrawingGroup.BitmapEffect>
      <BevelBitmapEffect  />
    </DrawingGroup.BitmapEffect>
    <DrawingGroup.OpacityMask>
      <RadialGradientBrush>
        <GradientStop Offset="0.55" Color="#00000000" />
        <GradientStop Offset="0.65" Color="#FF000000" />
        <GradientStop Offset="0.75" Color="#00000000" />
        <GradientStop Offset="0.80" Color="#FF000000" />
        <GradientStop Offset="0.90" Color="#00000000" />
        <GradientStop Offset="1.0" Color="#FF000000" />
      </RadialGradientBrush>
    </DrawingGroup.OpacityMask>
  </DrawingGroup>

  <GeometryDrawing Brush="#66B5F314">
    <GeometryDrawing.Geometry>
      <EllipseGeometry Center="150,150" RadiusX="50"  RadiusY="50"/>
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Pen>
      <Pen Brush="Black" Thickness="4" />
    </GeometryDrawing.Pen>
  </GeometryDrawing>

</DrawingGroup>

For more information about Drawing objects, see Drawing Objects Overview.





Create a GeometryDrawing


This example shows how to create and display a GeometryDrawing. A GeometryDrawing enables you to create shape with a fill and an outline by associating a Pen and a Brush with a Geometry. The Geometry describes the shape's structure, the Brush describes the shape's fill, and the Pen describes the shape's outline.

Example

The following example uses a GeometryDrawing to render a shape. The shape is described by a GeometryGroup and two EllipseGeometry objects. The shape's interior is painted with a LinearGradientBrush and its outline is drawn with a Black Pen. The GeometryDrawing is displayed using an ImageDrawing and an Image element.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SDKSample
{
    public class GeometryDrawingExample : Page
    {
        public GeometryDrawingExample()
        {

            //
            // Create the Geometry to draw.
            //
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50,50), 45, 20)
                );
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50, 50), 20, 45)
                );


            //
            // Create a GeometryDrawing.
            //
            GeometryDrawing aGeometryDrawing = new GeometryDrawing();
            aGeometryDrawing.Geometry = ellipses;

            // Paint the drawing with a gradient.
            aGeometryDrawing.Brush = 
                new LinearGradientBrush(
                    Colors.Blue, 
                    Color.FromRgb(204,204,255), 
                    new Point(0,0), 
                    new Point(1,1));

            // Outline the drawing with a solid color.
            aGeometryDrawing.Pen = new Pen(Brushes.Black, 10);

            //
            // Use a DrawingImage and an Image control
            // to display the drawing.
            //
            DrawingImage geometryImage = new DrawingImage(aGeometryDrawing);

            // Freeze the DrawingImage for performance benefits.
            geometryImage.Freeze();

            Image anImage = new Image();
            anImage.Source = geometryImage;
            anImage.Stretch = Stretch.None;
            anImage.HorizontalAlignment = HorizontalAlignment.Left;

            //
            // Place the image inside a border and
            // add it to the page.
            //
            Border exampleBorder = new Border();
            exampleBorder.Child = anImage;
            exampleBorder.BorderBrush = Brushes.Gray;
            exampleBorder.BorderThickness = new Thickness(1);
            exampleBorder.HorizontalAlignment = HorizontalAlignment.Left;
            exampleBorder.VerticalAlignment = VerticalAlignment.Top;
            exampleBorder.Margin = new Thickness(10);

            this.Margin = new Thickness(20);
            this.Background = Brushes.White;
            this.Content = exampleBorder;
        }

    }
}
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Margin="20" Background="White">

  <Border BorderBrush="Gray" BorderThickness="1" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="10">
    <Image Stretch="None" HorizontalAlignment="Left">
      <Image.Source>
        <DrawingImage PresentationOptions:Freeze="True">
          <DrawingImage.Drawing>

            <GeometryDrawing>
              <GeometryDrawing.Geometry>

                <!-- Create a composite shape. -->
                <GeometryGroup>
                  <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                  <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Brush>

                <!-- Paint the drawing with a gradient. -->
                <LinearGradientBrush>
                  <GradientStop Offset="0.0" Color="Blue" />
                  <GradientStop Offset="1.0" Color="#CCCCFF" />
                </LinearGradientBrush>
              </GeometryDrawing.Brush>
              <GeometryDrawing.Pen>

                <!-- Outline the drawing with a solid color. -->
                <Pen Thickness="10" Brush="Black" />
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingImage.Drawing>
        </DrawingImage>
      </Image.Source>
    </Image>
  </Border>


</Page>

The following illustration shows the resulting GeometryDrawing.

A GeometryDrawing of two ellipses

To create more complex drawings, you can combine multiple drawing objects into a single composite drawing using a DrawingGroup.





Draw an Image Using ImageDrawing


This example shows how to use an ImageDrawing to draw an image. An ImageDrawing enables you display an ImageSource with a DrawingBrushDrawingImage, or Visual. To draw an image, you create an ImageDrawing and set its ImageDrawing.ImageSource and ImageDrawing.Rect properties. The ImageDrawing.ImageSource property specifies the image to draw, and the ImageDrawing.Rect property specifies the position and size of each image.

Example

The following example creates a composite drawing using four ImageDrawing objects. This example produces the following image:

Several DrawingImage objects

Four ImageDrawing objects

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace SDKSample
{
    public class ImageDrawingExample : Page
    {
        public ImageDrawingExample()
        {
            // Create a DrawingGroup to combine the ImageDrawing objects.
            DrawingGroup imageDrawings = new DrawingGroup();

            // Create a 100 by 100 image with an upper-left point of (75,75). 
            ImageDrawing bigKiwi = new ImageDrawing();
            bigKiwi.Rect = new Rect(75, 75, 100, 100);
            bigKiwi.ImageSource = new BitmapImage(
                new Uri(@"sampleImages\kiwi.png", UriKind.Relative));

            imageDrawings.Children.Add(bigKiwi);

            // Create a 25 by 25 image with an upper-left point of (0,150). 
            ImageDrawing smallKiwi1 = new ImageDrawing();
            smallKiwi1.Rect = new Rect(0, 150, 25, 25);
            smallKiwi1.ImageSource = new BitmapImage(new Uri(@"sampleImages\kiwi.png", UriKind.Relative));
            imageDrawings.Children.Add(smallKiwi1);

            // Create a 25 by 25 image with an upper-left point of (150,0). 
            ImageDrawing smallKiwi2 = new ImageDrawing();
            smallKiwi2.Rect = new Rect(150, 0, 25, 25);
            smallKiwi2.ImageSource = new BitmapImage(new Uri(@"sampleImages\kiwi.png", UriKind.Relative));
            imageDrawings.Children.Add(smallKiwi2);

            // Create a 75 by 75 image with an upper-left point of (0,0). 
            ImageDrawing wholeKiwi = new ImageDrawing();
            wholeKiwi.Rect = new Rect(0, 0, 75, 75);
            wholeKiwi.ImageSource = new BitmapImage(new Uri(@"sampleImages\wholekiwi.png", UriKind.Relative));
            imageDrawings.Children.Add(wholeKiwi);

            //
            // Use a DrawingImage and an Image control to
            // display the drawings.
            //
            DrawingImage drawingImageSource = new DrawingImage(imageDrawings);

            // Freeze the DrawingImage for performance benefits.
            drawingImageSource.Freeze();

            Image imageControl = new Image();
            imageControl.Stretch = Stretch.None;
            imageControl.Source = drawingImageSource;

            // Create a border to contain the Image control.
            Border imageBorder = new Border();
            imageBorder.BorderBrush = Brushes.Gray;
            imageBorder.BorderThickness = new Thickness(1);
            imageBorder.HorizontalAlignment = HorizontalAlignment.Left;
            imageBorder.VerticalAlignment = VerticalAlignment.Top;
            imageBorder.Margin = new Thickness(20);
            imageBorder.Child = imageControl;

            this.Background = Brushes.White;
            this.Margin = new Thickness(20);
            this.Content = imageBorder;
        }

    }
}
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Background="White" Margin="20">
  <Border BorderBrush="Gray" BorderThickness="1" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="20">
    <Image Stretch="None">
      <Image.Source>
        <DrawingImage PresentationOptions:Freeze="True">
          <DrawingImage.Drawing>
            <DrawingGroup>

              <!-- The Rect property specifies that the image only fill a 100 by 100
                   rectangular area. -->
              <ImageDrawing Rect="75,75,100,100" ImageSource="sampleImages\kiwi.png"/>

              <!-- This image is set to fill a 25 by 25 rectangular area. -->
              <ImageDrawing Rect="0,150,25,25" ImageSource="sampleImages\kiwi.png"/>

              <!-- This image is set to fill a 25 by 25 rectangular area. -->
              <ImageDrawing Rect="150,0,25,25" ImageSource="sampleImages\kiwi.png"/>

              <!-- This image is set to fill a 75 by 75 rectangular area. -->
              <ImageDrawing Rect="0,0,75,75" ImageSource="sampleImages\wholekiwi.png"/>

            </DrawingGroup>
          </DrawingImage.Drawing>
        </DrawingImage>
      </Image.Source>
    </Image>
  </Border>
</Page>

For an example showing a simple way to display an image without using ImageDrawing, see How to: Use the Image Element.





Play Media using a VideoDrawing


To play an audio or video file, you use a VideoDrawing and a MediaPlayer. There are two ways to load and play media. The first is to use a MediaPlayer and a VideoDrawing by themselves, and the second way is to create your own MediaTimeline to use with the MediaPlayer and VideoDrawing.

System_CAPS_noteNote

When distributing media with your application, you cannot use a media file as a project resource, like you would an image. In your project file, you must instead set the media type to Content and set CopyToOutputDirectory to PreserveNewest or Always.

Example

The following example uses a VideoDrawing and a MediaPlayer to play a video file once.

//
// Create a VideoDrawing.
//      
MediaPlayer player = new MediaPlayer();

player.Open(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative));

VideoDrawing aVideoDrawing = new VideoDrawing();

aVideoDrawing.Rect = new Rect(0, 0, 100, 100);

aVideoDrawing.Player = player;

// Play the video once.
player.Play();        

To gain additional timing control over the media, use a MediaTimeline with the MediaPlayer and VideoDrawing objects. The MediaTimeline enables you to specify whether the video should repeat.

Example

The following example uses a MediaTimeline with the MediaPlayer and VideoDrawing objects to play a video repeatedly.

//
// Create a VideoDrawing that repeats.
//

// Create a MediaTimeline.
MediaTimeline mTimeline = 
    new MediaTimeline(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative)); 

// Set the timeline to repeat.
mTimeline.RepeatBehavior = RepeatBehavior.Forever;

// Create a clock from the MediaTimeline.
MediaClock mClock = mTimeline.CreateClock();

MediaPlayer repeatingVideoDrawingPlayer = new MediaPlayer();
repeatingVideoDrawingPlayer.Clock = mClock;

VideoDrawing repeatingVideoDrawing = new VideoDrawing();
repeatingVideoDrawing.Rect = new Rect(150, 0, 100, 100);
repeatingVideoDrawing.Player = repeatingVideoDrawingPlayer;  

Note that, when you use a MediaTimeline, you use the interactive ClockController returned from the Controller property of the MediaClock to control media playback instead of the interactive methods of MediaPlayer.





Use a Drawing as an Image Source


This example shows how to use a Drawing as the Source for an Image control. To display a Drawing with an Image control, use a DrawingImage as the Image control's Source and set the DrawingImage object's DrawingImage.Drawing property to the drawing you want to display.

Example

The following example uses a DrawingImage and an Image control to display a GeometryDrawing. This example produces the following output:

A GeometryDrawing of two ellipses

A DrawingImage

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SDKSample
{
    public class DrawingImageExample : Page
    {

        public DrawingImageExample()
        {

            //
            // Create the Geometry to draw.
            //
            GeometryGroup ellipses = new GeometryGroup();
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50,50), 45, 20)
                );
            ellipses.Children.Add(
                new EllipseGeometry(new Point(50, 50), 20, 45)
                );

            //
            // Create a GeometryDrawing.
            //
            GeometryDrawing aGeometryDrawing = new GeometryDrawing();
            aGeometryDrawing.Geometry = ellipses;

            // Paint the drawing with a gradient.
            aGeometryDrawing.Brush = 
                new LinearGradientBrush(
                    Colors.Blue, 
                    Color.FromRgb(204,204,255), 
                    new Point(0,0), 
                    new Point(1,1));

            // Outline the drawing with a solid color.
            aGeometryDrawing.Pen = new Pen(Brushes.Black, 10);

            //
            // Use a DrawingImage and an Image control
            // to display the drawing.
            //
            DrawingImage geometryImage = new DrawingImage(aGeometryDrawing);

            // Freeze the DrawingImage for performance benefits.
            geometryImage.Freeze();

            Image anImage = new Image();
            anImage.Source = geometryImage;
            anImage.HorizontalAlignment = HorizontalAlignment.Left;

            //
            // Place the image inside a border and
            // add it to the page.
            //
            Border exampleBorder = new Border();
            exampleBorder.Child = anImage;
            exampleBorder.BorderBrush = Brushes.Gray;
            exampleBorder.BorderThickness = new Thickness(1);
            exampleBorder.HorizontalAlignment = HorizontalAlignment.Left;
            exampleBorder.VerticalAlignment = VerticalAlignment.Top;
            exampleBorder.Margin = new Thickness(10);

            this.Margin = new Thickness(20);
            this.Background = Brushes.White;
            this.Content = exampleBorder;
        }

    }
}
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions"
  Background="White" Margin="20">

  <Border BorderBrush="Gray" BorderThickness="1" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Margin="10">

    <!-- This image uses a Drawing object for its source. -->
    <Image>
      <Image.Source>
        <DrawingImage PresentationOptions:Freeze="True">
          <DrawingImage.Drawing>
            <GeometryDrawing>
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                  <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Brush>
                <LinearGradientBrush>
                  <GradientStop Offset="0.0" Color="Blue" />
                  <GradientStop Offset="1.0" Color="#CCCCFF" />
                </LinearGradientBrush>
              </GeometryDrawing.Brush>
              <GeometryDrawing.Pen>
                <Pen Thickness="10" Brush="Black" />
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingImage.Drawing>
        </DrawingImage>
      </Image.Source>
    </Image>
  </Border>

</Page>






































'프로그래밍 > WPF' 카테고리의 다른 글

Data Binding  (0) 2017.01.10
Graphics and Multimedia - Animation Overview  (0) 2017.01.07
Documents  (0) 2016.11.19
Control Library 3  (0) 2016.11.18
Control Library 2  (0) 2016.11.13
:
Posted by 지훈2