<Pro WPF 4.5 in C#> - Note-02

50 篇文章 0 订阅
5 篇文章 0 订阅

Chapter 7: The Application


The Application


The Application Life Cycle


Application Tasks


Assembly Resources


Localization



Chapter 8: Element Binding


Binding Elements Together

The Binding Expression

<TextBlock Margin="10" Text="Simple Text" Name="lblSampleText" FontSize="{Binding ElementName=sliderFontSize, Path=Value}" >
</TextBlock>


Binding Modes

<TextBlock Margin="10" Text="Simple Text" Name="lblSampleText" FontSize="{Binding ElementName=sliderFontSize, Path=Value, Mode=TwoWay}" >
</TextBlock>

NameDescription
OneWayThe target property is updated when the source property changes.
TwoWayThe target property is updated when the source property changes, and the source property is updated when the target property changes.
OneTimeThe target property is set initially based on the source property value. However, changes are ignored from that point onward (unless the binding is set to a completely different object or you call BindingExpression.UpdateTarget(), as described later in this chapter). Usually, you'll use this mode to reduce overhead if you know the source property won't change.
OneWayToSourceSimilar to OneWay but in reverse. The source property is updated when the target property changes (which might seem a little backward), but the target property is never updated.
DefaultThe type of binding depends on the target property. It's either TwoWay (for usersettable properties, such as the TextBox.Text) or OneWay (for everything else). All bindings use this approach unless you specify otherwise.

Creating Bindings with Code

Binding binding = new Binding();
binding.Source = sliderFontSize;
binding.Path = new PropertyPath("Value");
binding.Mode = BindingMode.TwoWay;
lblSampleText.SetBinding(TextBlock.FontSizeProperty, binding);


BindingOperations.ClearAllBindings(lblSampleText);


Retrieving Bindings in Code

Binding binding = BindingOperations.GetBinding(lblSampleText, TextBlock.FontSize);


BindingExpression expression = BindingOperations.GetBindingExpression(lblSampleText, TextBlock.FontSize);
// Get the source element.
Slider boundObject = (Slider)expression.ResolvedSource;
// Get any data you need from the source element, including its bound property.
string boundData = boundObject.FontSize;


Multiple Bindings

<ListBox Margin="3" Grid.Row="3" Name="lstColors">
  <ListBoxItem Tag="Blue">Blue</ListBoxItem>
  <ListBoxItem Tag="DarkBlue">Dark Blue</ListBoxItem>
  <ListBoxItem Tag="LightBlue">Light Blue</ListBoxItem>
</ListBox>

<TextBlock Margin="3" Name="lblSampleText" 
	   FontSize="{Binding ElementName=sliderFontSize, Path=Value}"  Grid.Row="4"
	   Text="{Binding ElementName=txtContent, Path=Text}"           
	   Foreground="{Binding ElementName=lstColors, Path=SelectedItem.Tag}"
	   >      
</TextBlock>



Binding Updates

When you use OneWay or TwoWay binding, the changed value is propagated from the source to the target immediately. However, changes that flow in the reverse direction—from the target to the source—don't necessarily happen immediately. Instead, their behavior is governed by the Binding.UpdateSourceTrigger property:


NameDescription
PropertyChangedThe source is updated immediately when the target property changes.
LostFocusThe source is updated when the target property changes and the target loses focus.
ExplicitThe source is not updated unless you call the BindingExpression.UpdateSource() method.
DefaultThe updating behavior is determined by the metadata of the target property (technically, its FrameworkPropertyMetadata.DefaultUpdateSourceTrigger property). For most properties, the default behavior is PropertyChanged, although the TextBox. Text property has a default behavior of LostFocus.

If you choose the UpdateSourceTrigger.Explicit mode, it's up to your code to manually trigger the update. The BindingExpression object provides two methods for triggering an immediate update for one part of the binding: UpdateSource() and UpdateTarget().

// Get the binding that's applied to the text box.
BindingExpression binding = txtFontSize.GetBindingExpression(TextBox.TextProperty);
// Update the linked source (the TextBlock).
binding.UpdateSource();



Binding Delays



Binding to Objects That Aren't Elements

To draw the data from a nonvisual object, the only requirement is that the information you want to display must be stored in public properties. The WPF data-binding infrastructure won't pick up private information or public fields.


Source

You can use several approaches for getting the data object:

  • pull it out of a resource
  • generate it programmatically
  • get it with the help of a data provider



Pointing the Source to some static object that's readily available:

<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=Source}"></TextBlock>




Binding to an object that you've previously created as a resource:

<Window.Resources>
	<FontFamily x:Key="CustomFont">Calibri</FontFamily>
</Window.Resources>
<TextBlock Text="{Binding Source={StaticResource CustomFont}, Path=Source}"></TextBlock>


RelativeSource

<TextBlock>
	<TextBlock.Text>
		<Binding Path="Title">
			<Binding.RelativeSource>
				<RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}" />
			</Binding.RelativeSource>
		</Binding>
	</TextBlock.Text>
</TextBlock>

<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}} }">
</TextBlock>


DataContext

<StackPanel>
	<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=Source}"></TextBlock>
	<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=LineSpacing}"></TextBlock>
	<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=FamilyTypefaces[0].Style}"></TextBlock>
	<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=FamilyTypefaces[0].Weight}"></TextBlock>
</StackPanel>

can be simplified as:

<StackPanel DataContext="{x:Static SystemFonts.IconFontFamily}">
<TextBlock Margin="5" Text="{Binding Path=Source}"></TextBlock>



Chapter 9: Commands


Commands

Imagine your program has an application method, which can be triggered in multiple ways, like through a main menu item, a context menu, a keyboard shortcut or a toolbar button. At certain points in your application's lifetime, you need to temporarily disable the method.

WPF includes a command model that can help you deal with these issues. It adds two key features:

  • It delegates events to the appropriate commands.
  • It keeps the enabled state of a control synchronized with the state of the corresponding command.




The WPF Command Model

Commands: A command represents an application task and keeps track of whether it can be executed. However, commands don't actually contain the code that performs the application task.

Command bindings: Each command binding links a command to the related application logic, for a particular area of your user interface. This factored design is important, because a single command might be used in several places in your application and have a different significance in each place. To handle this, you use the same command with different command bindings.

Command sources: A command source triggers a command. For example, a MenuItem and a Button can both be command sources. Clicking them executes the bound command.

Command targets: A command target is the element on which the command is being performed. For example, a Paste command might insert text into a TextBox, and an OpenFile command might pop a document into a DocumentViewer. The target may or may not be important, depending on the nature of the command.


The ICommand Interface

public interface ICommand
{
	void Execute(object parameter);
	bool CanExecute(object parameter);
	event EventHandler CanExecuteChanged;
}

It uses the Execute() method to fire off a process that eventually raises an event that's handled elsewhere in your application.

Finally, the CanExecuteChanged event is raised when the state changes. Any controls using the command that they should call the CanExecute() method to check. Hence command sources (such as a Button or MenuItem) can automatically enable/disable themselves.


The RoutedCommand Class

The RoutedCommand class is the only class in WPF that implements ICommand. In other words, all WPF commands are instances of RoutedCommand (or a derived class).

The RoutedCommand modifies the command so that it can bubble through the WPF element hierarchy to get to the correct event handler.


public void Execute(object parameter, IInputElement target) {...}

This event begins at the target element and bubbles up to higher-level containers until your application handles it to perform the appropriate task.


RoutedCommand also introduces three properties:

  • Name: the command name
  • OwnerType: the class that this command is a member of
  • InputGestures: keystrokes or mouse actions that can also be used to trigger the command

This design is to make sure you can handle this event in one place, even if it's fired by different command sources in the same window, you need the power of event bubbling.


The RoutedUICommand Class

RoutedUICommand class derives from RoutedCommand. It adds a single property—Text—which is the display text for that command.


The Command Library

WPF includes a basic command library that's stocked with more than 100 commands. These commands are exposed through the static properties of five dedicated static classes:


  • ApplicationCommands
  • NavigationCommands
  • EditingCommands
  • ComponentCommands
  • MediaCommands


Executing Commands

Command Sources

The easiest way to trigger commands is to hook them up to a control that implements the ICommandSource interface, which includes controls that derive from ButtonBase (Button, CheckBox, and so on), individual ListBoxItem objects, the Hyperlink, and the MenuItem.


ICommandSource interface defines three properties:

  • Command
  • CommandParameter
  • CommandTarget


<Button Command="ApplicationCommands.New">New</Button>

Can be:

<Button Command="New">New</Button>


Command Bindings


// Create the binding.
CommandBinding binding = new CommandBinding(ApplicationCommands.New);
// Attach the event handler.
binding.Executed += NewCommand_Executed;
// Register the binding.
this.CommandBindings.Add(binding);

private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
	MessageBox.Show("New command triggered by " + e.Source.ToString());
}


This works through event bubbling. Essentially, when the button is clicked, the CommandBinding.Executed event bubbles up from the button to the containing elements.

The CommandBindings property is actually defined in the base UIElement class. That means it's supported by any element. For greatest flexibility, command bindings are usually added to the top-level window. If you want to use the same command from more than one window, you'll need to create a binding in both windows.

If you wanted to pass additional information, you would set the CommandParameter property of the command source. And if you wanted to pass a piece of information drawn from another control, you would need to set CommandParameter by using a data-binding expression.


Binding using XAML:

<Window x:Class="Commands.TestNewCommand"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	Title="TestNewCommand">
	<Window.CommandBindings>
		<CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed"></CommandBinding>
	</Window.CommandBindings>
	<StackPanel Margin="5">
		<Button Padding="5" Command="ApplicationCommands.New">New</Button>
	</StackPanel>
</Window>


Using Multiple Command Sources

<Menu>
	<MenuItem Header="File">
		<MenuItem Command="New"></MenuItem>
	</MenuItem>
</Menu>


This MenuItem object doesn't set the Header property. It automatically picks up Ctrl+N shortcut, and it  appears in the menu alongside the menu text.


Fine-Tuning Command Text


<Button Command="New" Content="{x:Static ApplicationCommands.New}"></Button>


<Button Margin="5" Padding="5" Command="ApplicationCommands.New" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
</Button>


<Button Margin="5" Padding="5" Command="ApplicationCommands.New" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}">
	<Image ... />
</Button>



Invoking a Command Directly

ApplicationCommands.New.Execute(null, targetElement);


The target element is simply the element where WPF begins looking for the command binding. You can use the containing window (which has the command binding) or a nested element (such as the actual element that fired the event).

this.CommandBindings[0].Command.Execute(null);


This method doesn't give you a way to respond to the command's state change, if you...


Disabling Commands

...


Controls with Built-in Commands

Some input controls handle command events on their own. For example, the TextBox class handles the Cut, Copy, and Paste commands, as well as Undo and Redo.

When a control has its own hardwired command logic, you don’t need to do anything to make your command work.

If you place your buttons in a different container (other than a ToolBar or Menu), you won't have this benefit. That means your buttons won't work unless you set the CommandTarget property manually.

<Button Command="Cut" CommandTarget="{Binding ElementName=txtDocument}">Cut</Button>
<Button Command="Copy" CommandTarget="{Binding ElementName=txtDocument}">Copy</Button>
<Button Command="Paste" CommandTarget="{Binding ElementName=txtDocument}">Paste</Button>

Another, simpler option is to create a new focus scope by using the attached FocusManager.

<StackPanel FocusManager.IsFocusScope="True">
	<Button Command="Cut">Cut</Button>
	<Button Command="Copy">Copy</Button>
	<Button Command="Paste">Paste</Button>
</StackPanel>


In some rare cases, you might not want to enable some built-in commands of a control. In this situation, you have three options for supressing the command:

...


Advanced Commands


Custom Commands

The way to do this is pretty straightforward, you don't need to code your command's implementation, it is just a RoutedUICommand instance First of all, you need a class to hold your command:

public class DataCommands
{
	private static RoutedUICommand requery;
	
	static DataCommands()
	{
		InputGestureCollection inputs = new InputGestureCollection();
		inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R"));
		requery = new RoutedUICommand("Requery", "Requery", typeof(DataCommands), inputs);
	}
	 
	public static RoutedUICommand Requery
	{
		get { return requery; }
	}
}

The rest is exactly the same as what you do with the normal commands. You can use it in XAML like:

<Window.CommandBindings>
	<CommandBinding Command="local:DataCommands.Requery" Executed="RequeryCommand"/>
</Window.CommandBindings>

Of course you will need to implement your handler method for that command:

private void RequeryCommand(object sender, ExecutedRoutedEventArgs e)
{
	MessageBox.Show("Requery");
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Microsoft's Windows Presentation Foundation (WPF) provides you with a development framework for building high-quality user experiences for the Windows operating system. It blends together rich content from a wide range of sources and allows you unparalleled access to the processing power of your Windows computer. Pro WPF 4.5 in C# provides a thorough, authoritative guide to how WPF really works. Packed with no-nonsense examples and practical advice you'll learn everything you need to know in order to use WPF in a professional setting. The book begins by building a firm foundation of elementary concepts, using your existing C# skills as a frame of reference, before moving on to discuss advanced concepts and demonstrate them in a hands-on way that emphasizes the time and effort savings that can be gained. What you’ll learn •Understand the fundamentals of WPF programming from XAML to controls and data flow. •Develop realistic application scenarios to see navigation, localization and deployment in action. •Explore the advanced user interface controls that WPF provides. •Learn to manage documents from within WPF: Text layout, printing, and document packaging are all covered. •Use graphics and multimedia to add punch to your applications Who this book is for This book is designed for developers encountering WPF for the first time in their professional lives. A working knowledge of C# and the basic architecture of .NET is helpful to follow the examples easily, but all concepts will be explained from the ground up. Table of Contents 01.Introducing WPF 02.XAML 03.Layout 04.Dependency Properties 05.Routed Events 06.Controls 07.The Application 08.Element Binding 09.Commands 10.Resources 11.Styles and Behaviors 12.Shapes, Brushes, and Transforms 13.Geometries and Drawings 14.Effects and Visuals 15.Animation Basics 16.Advanced Animation 17.Control Templates 18.Custom Elements 19.Data Binding 20.Formatting 21.Bound Data 22.Data Views 23.Lists, Trees, and Grids 24.Windows Pages and Navigation 25.Menus, Toolbars, and Ribbons 26. Sound and Video 27.3-D Drawing 28.Documents 29. Printing 30.Interacting with Windows Forms 31.Multithreading 32.The Add-in Model 33.ClickOnce Deployment ----------------------------------------------------------- Pro WPF 4th edition,喜欢的朋友请支持正版。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值