精华内容
下载资源
问答
  • WPF Binding

    2013-01-11 23:22:41
    WPF Binding,里面有源代码,值得初学者学习
  • WPF BINDING

    2017-10-31 22:19:00
    WPF里分三种BindingBinding,PriorityBinding,MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension Binding 提供对绑定定义的高级别访问,绑定将绑定目标对象(通常为 WPF ...

    WPF里分三种Binding:Binding, PriorityBindingMultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension

    Binding

    提供对绑定定义的高级别访问,绑定将绑定目标对象(通常为 WPF 元素)的属性与任何数据源(例如数据库、XML 文件或包含数据的任何对象)连接起来。

    常见的使用Binding的代码:
    C#

    Binding binding = new Binding();
    // Set source object
    binding.Source = treeView;
    // Set source property
    binding.Path = new PropertyPath("SelectedItem.Header");
    // Attach to target property
    currentFolder.SetBinding(TextBlock.TextProperty, binding);

    XAML:

    <TextBlock x:Name=”currentFolder” DockPanel.Dock=”Top”
    Text=”{Binding ElementName=treeView, Path=SelectedItem.Header}”
    Background=”AliceBlue” FontSize=”16”/>

    所有FrameworkElement都包含SetBinding方法:SetBinding(DependencyProperty dp, String path), SetBinding(DependencyProperty dp, BindingBase binding),可以看出,FrameworkElement中的SetBinding只对DependencyProperty有效。

    另一种设置Binding的方法是:BindingOperations.SetBinding(currentFolder, TextBlock.TextProperty, binding);
    BindingOperations.SetBinding的原型是

    public static BindingExpressionBase SetBinding(
    	DependencyObject target,
    	DependencyProperty dp,
    	BindingBase binding
    )

    第一个参数是DependencyObject,所以我们可以对自定义DependencyObject或者继承自DependencyObject的类进行绑定。当然第二个参数还是DependencyProperty。

    清除Binding:
    BindingOperations.ClearBinding(currentFolder, TextBlock.TextProperty); //删除currentFolder上的TextBlock.TextProperty绑定
    BindingOperations.ClearAllBindings(currentFolder); //删除currentFolder上的所有绑定

    直接对dependency property赋值也可以解除binding, 不过只对单向binding有效。  


    Bingding的源:

    有三个属性用来设置源:ElementName(string)、Source(Object) 和 RelativeSource(RelativeSource)。注:这三个只能指定一个,否则异常。
    ElementName: 源为一个元素(Element),这里用的是此元素中设置的Name属性。
    Source:以object作为源。<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
    RelativeSource: 源相对于绑定目标的位置。
                            源是元素本身:{Binding RelativeSource={RelativeSource Self}}
                            源是Tempalte中元素的Parent:{Binding RelativeSource={RelativeSource TemplatedParent}}
                            源是绑定以collection形式的前一个数据:{Binding RelativeSource={RelativeSource PreviousData}},MSDN上关于PreviousData的说明并不多,这里有一篇文章可以参考
                            以上三项为RelativeSource中的Static值,使用这些值可以减少内存开销
                            源是Ancestor(可能比parent还高):{Binding RelativeSource={RelativeSource FindAncestor,
                                                                         AncestorLevel=n, AncestorType={x:Type desiredType}}}


    Path:

    Binding中的Path是 PropertyPath对象。

      • 在最简单的情况下,Path 属性值是要用于绑定的源对象的属性名称,如 Path=PropertyName。

      • 通过类似于 C# 中使用的语法,可以指定属性的子属性。例如,子句 Path=ShoppingCart.Order 将绑定设置为对象的子属性 Order 或属性 ShoppingCart。

      • 若要绑定到附加属性,请将附加属性用括号括起。例如,若要绑定到附加属性 DockPanel.Dock,则语法为 Path=(DockPanel.Dock)。

      • 在应用了索引器的属性名称之后的方括号内,可以指定属性的索引器。例如,子句 Path=ShoppingCart[0] 将绑定设置为与属性的内部索引处理文本字符串“0”的方式对应的索引。此外,还支持多个索引器。

      • 在 Path 子句中可以同时使用索引器和子属性,例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street]。

      • 在索引器内部,可以有多个由逗号 (,) 分隔的索引器参数。可以使用圆括号指定每个参数的类型。例如,可以使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空间。

      • 如果源为集合视图,则可以用斜杠 (/) 指定当前项。例如,子句 Path=/ 设置到视图中当前项的绑定。如果源为集合,则此语法指定默认集合视图的当前项。

      • 可以结合使用属性名和斜杠来遍历作为集合的属性。例如,Path=/Offices/ManagerName 指定源集合的当前项,该源集合包含同样是集合的 Offices 属性。其当前项是包含 ManagerName 属性的对象。

        也可以使用句点 (.)路径绑定到当前源。例如,Text=”{Binding}” 等效于 Text=”{Binding Path=.}”。

         


         

        BindingExpression

        Binding 类是高级别类。BindingExpression 类是基础对象,用于保持绑定源与绑定目标之间的连接。Binding 中包含可在多个 BindingExpression 对象之间共享的所有信息。也就是说,可以把一个Binding对象绑定对n个元素上,而针对这n个元素,分别有相应的n个BindingExpresion对象。
        Binding可以直接绑定普通的.net实例,比如int值。但是如果后台改变int值了,前台不能显示改变后的值,这时可以调用UpdateTarget()方法更新绑定。如下:BindingExpression be = button.GetBindingExpression(Button.ContentProperty);
        be.UpdateTarget(); 

         

        还有UpdateSource方法用来更新源。

         


         

        绑定到.net属性/对象:

         

        上面提到Binding绑到普通的.net属性,如果source变化了,UI上是不会显示的,除了用BindingExpression每次显式更新Target外,还可以使用如下技术:

        绑定到单个对象需实现INotifyPropertyChanged接口,这个接口只有一个成员:

        event PropertyChangedEventHandler PropertyChanged
         
        实现INotifyPropertyChanged的示例如下:
        using System.ComponentModel;
        
        namespace SDKSample
        {
          // This class implements INotifyPropertyChanged
          // to support one-way and two-way bindings
          // (such that the UI element updates when the source
          // has been changed dynamically)
          public class Person : INotifyPropertyChanged
          {
              private string name;
              // Declare the event
              public event PropertyChangedEventHandler PropertyChanged;
        
              public Person()
              {
              }
        
              public Person(string value)
              {
                  this.name = value;
              }
        
              public string PersonName
              {
                  get { return name; }
                  set
                  {
                      name = value;
                      // Call OnPropertyChanged whenever the property is updated
                      OnPropertyChanged("PersonName");
                  }
              }
        
              // Create the OnPropertyChanged method to raise the event
              protected void OnPropertyChanged(string name)
              {
                  PropertyChangedEventHandler handler = PropertyChanged;
                  if (handler != null)
                  {
                      handler(this, new PropertyChangedEventArgs(name));
                  }
              }
          }
        }
        或者显式实现INotifyPropertyChanged:
        
        #region INotifyPropertyChanged Members
        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add
            {
                this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value);
            }
            remove
            {
                this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value);
            }
        }
        #endregion
         
        看了上面代码着实没看出source值改变了,前台是通过什么机制反映的,正常的情况下公开了一个事件,必须有一个对此事件的实现体,而上面代码并没有实现PropertyChanged的方法。
        我猜想是Binding内部获取了这个接口并对PropertyChanged进行了赋值,因为在debug时,这个事件确实被赋值的,而赋值前的Stack是External Code调用的。
         
        绑定到集合需实现INotifyCollectionChanged,但是推荐使用ObservableCollection<T>,这个类实现了INotifyCollectionChanged和INotifyPropertyChanged。
         
        附:当绑定到普通的.net属性时,WPF使用反射取得source的值,当对象实现ICustomTypeDescriptor时,WPF使用这个接口取得值,性能上会有所提升。

         


         

        DataContext:


        DataContext在共享资源时最有用。

         

        <StackPanel x:Name="parent" DataContext="{StaticResource photos}">
        <Label x:Name="numItemsLabel"
        Content="{Binding Path=Count}"
        DockPanel.Dock="Bottom"/>
        也可以在代码这么写parent.DataContext = photos;
         

         


         

        Value Converters:

        IValueConverter可以在绑定时加入自己的逻辑,很好。

        public class RawCountToDescriptionConverter : IValueConverter
        {
        	public object Convert(object value, Type targetType, object parameter,
        		CultureInfo culture)
        	{
        		// Let Parse throw an exception if the input is bad
        		int num = int.Parse(value.ToString());
        		return num + (num == 1 ? " item" : " items");
        	}
        
        	public object ConvertBack(object value, Type targetType, object parameter,
        		CultureInfo culture)
        	{
        		throw new NotSupportedException();
        	}
        }
        IValueConverter就两个方法需要自己实现,Convert和ConvertBack,一个转过来,一个转过去。
        XAML代码如下
        <Label Background="{Binding Path=Count, Converter={StaticResource myConverter},
        Source={StaticResource photos}}"/>
        这里的myConverter是个resource,需要在xaml中预先定义:
        <Window.Resources>
        <local:CountToBackgroundConverter x:Key="myConverter"/>
        </Window.Resources>
         
        Path对应的Count值会作为第一个参数value传给Convert方法。
         
        注意,返回的值一定要是绑定时对应的值,比如绑定时需要绑到Geometry类上,那么Convert返回的也必须是Geometry类。
         
        Convert方法还带有一个parameter参数,可以在xaml中这么使用
        <Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, 
        ConverterParameter=Yellow, Source={StaticResource photos}}"/>

        ConverterParameter是object类型。
        C#代码中就可以得到parameter的值了。

        TIP:
        可以用Binding.DoNothing作返回值,以指示绑定引擎不要执行任何操作。
        可用使用[ValueConversion(typeof(DateTime), typeof(String))]来标识Converter要转化和返回的值类型,第一个参数是soure,第二个参数是target。这样在编译时,如果类型不匹配的话,编译器会抛出异常:error CS0592: Attribute 'ValueConversion' is not valid on this declaration type. It is only valid on 'class' declarations.

        .net自带一些converter,比如常用的BooleanToVisibilityConverter,可以根据checkbox是否勾上来隐藏其他控件。

        在collection中使用converter:使用DateTemplate,在其中使用Converter。(也可以使用Converter对整个collection进行转化,但是可能效率不好)

         


         

        Binding.Mode

        指示源和目标间数据流的方向。

        OneWay 源更新时,目标也更新
        TwoWay 源更新时目标也更新,或者目标更新时同时更新源
        OneTime 仅当应用程序启动时或 DataContext 进行更改时更新目标属性。绑一次就不更维护更新,目标相当于源的一次性镜像
        OneWayToSource 目标更新时更新源,和OneWay相反

        大部分WPF自带的控件的dependency property默认的是OneWay,像TextBox.Text默认的是TwoWay。
        值得注意的事,只读属性只能设置成OneWay,不能是TwoWay,否则运行时异常。

        对于 OneWay 或 TwoWay 绑定,对源的动态更改不会自动传播到目标。必须在源对象上实现 INotifyPropertyChanged 接口。 
        对于 TwoWay 绑定,对目标的更改不会自动传播到源,除非绑定目标是 Text 属性。在这种情况下,更新仅在 TextBox 失去焦点时发生。 
        对于 OneTime 和 OneWay 绑定,对 SetValue 的调用会自动更改目标值并删除绑定。

        再次提醒,源要实现了INotifyPropertyChanged 接口才能把改变反映到目标上。

        OneWayToSource 用于多个目标更改一个源的情况,可以想像成多人录入。或者用来实现源和目标倒置的情况。

         


         

        Binding.UpdateSourceTrigger

        指示使用TwoWay或OneWayToSource时,目标在什么情况下更新源。有三个枚举值

        PropertyChanged:目标属性改变时更新源
        LostFocus:失去焦点时更新源
        Explicit:只有在显式调用BindingExpression.UpdateSource方法时才更新源。BindingExpression可以通过BindingOperations.GetBindingExpression或FrameworkElement.GetBindingExpression方法获得

        Binding类中提供了SourceUpdated和TargetUpdated事件,可以用来记些log,不过必须相应的NotifyOnSourceUpdated或NotifyOnTargetUpdated设置成true才会激发事件。

         

         


         

        Binding的验证

         

        我们当然可以自己写代码验证数据的正确性,不过WPF提供了可以说是标准的方案,限于篇幅,我单独开了一贴,点这里查看。

      • http://www.cnblogs.com/iwteih/archive/2010/02/03/1662891.html

    转载于:https://www.cnblogs.com/sjqq/p/7764130.html

    展开全文
  • wpf binding

    2021-01-04 22:08:39
    第一种binding 绑定到元素上 <Slider x:Name="sd" Width="800" /> <TextBox Text="{Binding ElementName=sd ,Path=Value}"> 这种binding就是binding到元素上,第二行代码<TextBox Text="{Binding...

    第一种binding 绑定到元素上

    <Slider x:Name="sd" Width="800" />
    <TextBox Text="{Binding ElementName=sd ,Path=Value}">
    

    这种binding就是binding到元素上,第二行代码<TextBox Text="{Binding ElementName=sd ,Path=Value}">

    ElementName就是指定元素的Name  Path就是元素的属性值。

     

    第二种binding到资源上

    <Window.Resources>
        <TextBox x:Key="txt">Hello</TextBox>
    </Window.Resources>
    
    <Slider x:Name="sd" Width="800" />
    <TextBox Text="{Binding Source={StaticResource txt},Path=Text}"/>

    这种binding是binding到资源上,<TextBox Text="{Binding Source={StaticResource txt},Path=Text}"/>这个就是binding到资源的方式。StaticResource就是查找资源中的Name。

     

    第三种binding数据上下文

    XAML代码

    <TextBox x:Name="txt" Text="{Binding Name",FallbackValue="Not Found"}/>

    C#中代码

    public Mainwindow()
    {
        InitialzeComponent();
        txt.DataContext = new Person(){ Name = "ABC"}
    
    }
    public class Person
    {
        public string Name{get;set;}
    
    }

    其中txt.DataContext = new Person(){ Name = "ABC"}     FallbackValue是设置默认值的。

    这里面的Name是<TextBox x:Name="txt" Text="{Binding Name"/>中的Name,而txt是XAML中的Name属性。

    也可以把C#代码写到其他cs文件中,

    public class MainVieModel
    {
        public MainVieModel()
        {
            Name = "Hello";        
        }
        public string Name{get;set;}
    }

    在MainWindow函数中

    public Mainwindow()
    {
        InitialzeComponent();
        this.DataContext = new MainVieModel();
    }

    在XAML中

    <TextBox x:Name="txt" Text="{Binding Name",FallbackValue="Not Found"}/>

    在其他位置创建一个文件夹,保证命名空间一致即可。

     

    要想实时更新到UI

    xxx.cs中的代码

    public class MainVieModel : INotifyProertyChanged
    {
        public MainVieModel()
        {
            Name = "Hello";  
            task.Run(
                async() =>
                {
                    await Task.Delay(3000);//3s
                    Name = "No";
                }
            );      
        }
        public string Name;
    
        public string Name
        {
            get{return name;}
            set{
                name = value;
                OnPropertyChanged("Name");
            }
        }
        public event PropertyChangedEcentHandler ProertyChanged;
    
        protected void OnPropertyChanged(string properName)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(properName));
            }
        }
    }

    其他的不变

    这是个延时函数

            task.Run(
                async() =>
                {
                    await Task.Delay(3000);//3s
                    Name = "No";
                }
            ); 

     

    展开全文
  • Data Binding in WPF

    2013-09-03 08:35:00
    http://msdn.microsoft.com/en-us/magazine/cc163299.aspx#S1 Data Binding in WPF John Papa Code download available at:DataPoints2007_12.exe(161 KB) Contents Data Binding Specifics...
    http://msdn.microsoft.com/en-us/magazine/cc163299.aspx#S1
     
    Data Binding in WPF
    John Papa


    Code download available at:DataPoints2007_12.exe(161 KB)

    By now, many of you know that Windows® Presentation Foundation (WPF) makes it easy to design robust user interfaces. But what you probably didn't know is that it also provides powerful data-binding capabilities. With WPF, you can perform data manipulation using Microsoft® .NET Framework code, XAML, or a combination of both. You can bind to controls, public properties, XML, or objects, making data binding quick, flexible, and easier than ever. So let's take a look at how you can get started binding your controls to the data sources of your choice.

     

    Data Binding Specifics
    To use WPF data binding, you must always have a target and a source. The target of the binding can be any accessible property or element that is derived from DependencyProperty—an example is a TextBox control's Text property. The source of the binding can be any public property, including properties of other controls, common language runtime (CLR) objects, XAML elements, ADO.NET DataSets, XML Fragments, and so forth. To help you get the binding right, WPF includes two special providers—the XmlDataProvider and the ObjectDataProvider.
    Now let's take a look at how the WPF data-binding techniques work and I'll present practical examples that illustrate their use.

     

    Creating a Simple Binding
    Let's start with a simple example that illustrates how to bind a TextBlock's Text property to a ListBox's selected item. The code displayed in Figure 1 shows a ListBox that has six ListBoxItems declared. The second TextBlock in the code example has a property called Text (specified in XAML property-element syntax with the XML child element <TextBlock.Text>), which will contain the text for the TextBlock. The Text property declares a binding to the ListBox's selected item with the <Binding> tag. The ElementName attribute of the Binding tag indicates the name of the control that the TextBlock's Text property is bound to. The Path attribute indicates the property of the element (in this case the ListBox) that we will be binding to. The result of this code is that when a color is selected from the ListBox, the name of that color is shown in the TextBlock.

     

     
    <StackPanel> <TextBlock Width="248" Height="24" Text="Colors:" TextWrapping="Wrap"/> <ListBox x:Name="lbColor" Width="248" Height="56"> <ListBoxItem Content="Blue"/> <ListBoxItem Content="Green"/> <ListBoxItem Content="Yellow"/> <ListBoxItem Content="Red"/> <ListBoxItem Content="Purple"/> <ListBoxItem Content="Orange"/> </ListBox> <TextBlock Width="248" Height="24" Text="You selected color:" /> <TextBlock Width="248" Height="24"> <TextBlock.Text> <Binding ElementName="lbColor" Path="SelectedItem.Content"/> </TextBlock.Text> </TextBlock> </StackPanel>
    The code listed in Figure 1 can be modified slightly to use a shorthand syntax for data binding. For example, let's replace the TextBlock's <Binding> tag with the following code snippet:
     
    <TextBlock Width="248" Height="24" Text="{Binding ElementName=lbColor, Path=SelectedItem.Content}" />
    This syntax, called the attribute syntax, condenses the data binding code inside of the Text attribute of the TextBlock. Basically, the Binding tag gets pulled inside of the curly braces along with its attributes.

     

    Binding Modes
    I can take the previous example further, binding the background color of the TextBlock to the color that is selected in the ListBox. The following code adds a Background property to the TextBlock and uses the attribute binding syntax to bind to the value of the selected item in the ListBox:
     
    <TextBlock Width="248" Height="24" Text="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=OneWay}" x:Name="tbSelectedColor" Background="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=OneWay}"/>
    When the user selects a color in the ListBox, the name of that color will appear in the TextBlock and the background color of the TextBlock will change to the selected color (see Figure 2).

    Figure 2 Binding a Source to Two Targets 
    Notice the statement in the previous example that sets the Mode attribute to OneWay. The Mode attribute defines the binding mode that will determine how data flows between the source and the target. In addition to OneWay, there are three other binding modes available: OneTime, OneWayToSource, and TwoWay,
    When using OneWay binding, as shown in the preceding code snippet, the data flows from the source to the target each time a change is made on the source. And while I explicitly specified this binding mode in my example, OneWay binding is the default binding mode for the TextBlock's Text property and does not need to be specified. Like OneWay binding, OneTime binding sends data from the source to the target; however, it does this only when the application is started or when the DataContext changes and, as a result, does not listen for change notifications in the source. Unlike OneWay and OneTime binding, OneWayToSource binding sends data from the target to the source. Finally, TwoWay binding sends the source data to the target, and if there are changes in the target property's value, those will be sent back to the source.
    In the previous example, I used OneWay binding because I wanted the source (the selected ListBoxItem) to be sent to the TextBlock whenever a change is made in the ListBox selection. I do not want changes from the TextBlock to go back to the ListBox. Of course, there is no way for a user to edit a TextBlock. If I want to explore TwoWay binding, I can add a TextBox to this code, bind its text and background color to the ListBox, and set the Mode to TwoWay. When a user selects a color in the ListBox, the color is shown in the TextBox and its background color changes. When that user types in a color (such as Cyan) in the TextBox, the name of the color is updated in the ListBox (target to source) and in turn, since the ListBox was updated, the new value is sent to all elements that are bound to the ListBox's SelectedItem property. This means that the TextBlock will also have its color updated and its text value set to the new color (see Figure 3).

    Figure 3 TwoWay Binding in Action 
    Here's the code I used to bind the TextBlock (OneWay) and the TextBox (TwoWay) to the ListBox:
     
    <TextBlock Width="248" Height="24" Text="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=OneWay}" x:Name="tbSelectedColor" Background="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=OneWay}"/> <TextBox Width="248" Height="24" Text="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=TwoWay}" x:Name="txtSelectedColor" Background="{Binding ElementName=lbColor, Path=SelectedItem.Content, Mode=OneWay}"/>
    If I change the TwoWay mode back to OneWay, the user will be able to edit the color in the TextBox without causing the changed value to be sent back to the ListBox.
    Selecting the appropriate binding mode is important. I often employ OneWay when I want to display read-only data to a user. I use TwoWay binding when I want the user to be able to change the data in the control and have that change reflected in the data source (a DataSet, object, XML, or another bound control). I find OneWayToSource to be a good choice when I want to allow a user to change the data source without having the data source bind its data back to the target. I have used OneTime binding when I was tasked with showing, in a read-only control, the state of the data as it was when the screen loaded. Using OneTime binding, a series of read-only controls was bound to the data and, as the user interacted with the form and the data source's values were changed, the bound controls remained unchanged. This provided a way for the users to compare the changes that were made. Additionally, OneTime binding is a good choice when your source doesn't implement INotifyPropertyChanged.

     

    A Time to Bind
    In the previous example, the TextBox allows TwoWay binding to the selected ListBoxItem in the ListBox. This flow of data from the TextBox back to the ListBox happens when the TextBox loses focus. To change the event that causes the data to be sent back to the source, you can specify a value for UpdateSourceTrigger, which is the binding property that defines when the source should be updated. There are three values that can be set for the UpdateSourceTrigger: Explicit, LostFocus, and PropertyChanged.
    When you set the UpdateSourceTrigger to Explicit, the source will not be updated unless the BindingExpression.UpdateSource method is called from code. The LostFocus setting (the default value for the TextBox control) indicates that the source will be updated when the target control loses focus. The PropertyChanged value indicates that the target will update the source every time the target control's bound property changes. This setting is useful when you want to dictate when the binding will occur.

     

    Binding to XML
    Binding to data sources such as XML and objects is also handy. Figure 4 shows a sample of an XmlDataProvider that contains an embedded list of colors that will be used as a data source. The XmlDataProvider can be used to bind to an XML document or fragment that is either embedded in the XmlDataProvider tag or is in a file referred to in an external location.

     

     
    <StackPanel> <StackPanel.Resources> <XmlDataProvider x:Key="MoreColors" XPath="/colors"> <x:XData> <colors > <color name="pink"/> <color name="white"/> <color name="black"/> <color name="cyan"/> <color name="gray"/> <color name="magenta"/> </colors> </x:XData> </XmlDataProvider>
    Embedded XML content must be placed within a <x:XData> tag inside of an XmlDataProvider, as shown in Figure 4. The XmlDataProvider must be given an x:Key value so that it can be referred to by data-binding targets. Notice that the XPath attribute is set to "/colors". This attribute defines the level of the XML content that will be used as the data source. This becomes very useful when binding to a large XML structure that may be contained in a file or database and the data you want to bind to is not the root element.
    An XmlDataProvider is a resource that can be placed inside of a context-specific resource. As Figure 4 shows, the XmlDataProvider is defined as a resource within the context of the StackPanel. This means that the XmlDataProvider will be available to all content inside of that StackPanel. Setting the context of a resource helps limit the exposure of a data source to the appropriate areas. This enables you to create well-defined, self-contained regions of both controls and supporting resources within your page, thus improving readability.
    The syntax for binding to a resource is slightly different than it is for binding to an element. When binding to a control, you set the ElementName and the Path properties of the Binding. However, when you bind to a resource you set the Source and, since we are binding to an XmlDataProvider, you set the XPath property of the Binding as well. For example, the following code will bind the ListBox's items to the MoreColors resource. The Source property is set to a resource and it is specified as a StaticResource named MoreColors. The XPath property indicates that the items will be bound to the <color> element's name attribute within the XML data source:
     
    <ListBox x:Name="lbColor" Width="248" Height="56" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource MoreColors}, XPath=color/@name}"> </ListBox>
    I specified StaticResource in this case because the XML will not change. If changes occur in the data source, they will not be sent to the target. The DynamicResource setting indicates the opposite—changes will be sent. This is useful when referencing system themes, languages in globalization, or fonts. A DynamicResource will allow these types of settings to be propagated throughout the UI elements that are bound to them dynamically.
    The XmlDataProvider can also point to an external source for the XML content. For my example, I have a file named colors.xml that contains the list of colors I want my ListBox to be bound to. I can simply add a second XmlDataProvider resource to the StackPanel and direct it to the XML file. Notice I set the Source attribute to the name of the XML file and the x:Key to Colors:
     
    <XmlDataProvider x:Key="Colors" Source="Colors.xml" XPath="/colors"/>
    Both XmlDataProviders exist as resources within the same StackPanel. I can tell the ListBox to bind itself to this new resource by changing the name that the StaticResource is set to:
     
    <ListBox x:Name="lbColor" Width="248" Height="56" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource Colors}, XPath=color/@name}"> </ListBox>

     

    Object Binding and DataTemplates
    While the XmlDataProvider works great for XML, when you want to bind to an object or a list of objects, you can create an ObjectDataProvider as a resource. The ObjectDataProvider's ObjectType designates the object that will provide the data‑binding source while the MethodName indicates the method that will be invoked to get the data. For example, assuming I have a class called PersonService that has a method called GetPersonList that returns a List<Person>, the ObjectDataProvider would look like this:
     
    <StackPanel.Resources> <ObjectDataProvider x:Key="persons" ObjectType="{x:Type svc:PersonService}" MethodName="GetPersonList"></ObjectDataProvider> </StackPanel.Resources>
    If you want a more complete look, the PersonService and Person classes, as well as all other sample code, are contained in the code that accompanies this column.
    There are a handful of other properties that are available on the ObjectDataProvider. The ConstructionParameters property allows you to pass parameters to the constructor of the class being invoked. You can also specify parameters using the MethodParameters property, and you can use the ObjectInstance property to specify an existing instance of an object as the source.
    If you want the data to be retrieved asynchronously, you can set the IsAsynchronous property of the ObjectDataProvider to true. Then the user will be able to interact with the screen while waiting for the data to populate in the target control that is bound to the ObjectDataProvider's source.
    When adding an ObjectDataProvider, you have to qualify the namespace of the data-source class. In this case, I have to add an xmlns attribute to the <Window> tag so that the svc shortcut is qualified and indicates the proper namespace:
     
    xmlns:svc="clr-namespace:DataBindingWPF"
    Now that the data source is defined via the ObjectDataProvider, I want to bind items in a ListBox control to this data. I want to display two lines of text in each ListBoxItem. The first line will display the FullName property of the Person instance in bold and the second line will show the Title and City of the instance. In XAML, this is quite simple using DataTemplates, which allow you to define a data visualization strategy that can be reused.
    Figure 5 shows the completed XAML, which has a DataTemplate defined to display the Person information in the layout I designated. I set the DataType property of the DataTemplate to indicate that the DataTemplate will be referring to the Person class type. I do not specify the actual binding in the DataTemplate, as I will do this in the ListBox control. By omitting the Binding Source, the binding will be made to the current DataContext in scope.
    In Figure 5, I set the ListBox's ItemsSource property to bind to the persons resource so that I could bind the data to the ListBox but not format it. The data is correctly displayed by setting the ItemTemplate property to the personLayout resource, which is the DataTemplate's key name. The ultimate result is a screen that looks like Figure 6.

     

     
    <Window x:Class="DataBindingWPF.ObjectBinding" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:svc="clr-namespace:DataBindingWPF" Title="DataBindingWPF" Height="300" Width="300"> <StackPanel> <StackPanel.Resources> <ObjectDataProvider x:Key="persons" ObjectType="{x:Type svc:PersonService}" MethodName="GetPersonList" ></ObjectDataProvider> <DataTemplate x:Key="personLayout" DataType="Person"> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Path=FullName}" FontWeight="Bold" Foreground="Blue"> </TextBlock> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=Title}"></TextBlock> <TextBlock Text=", "></TextBlock> <TextBlock Text="{Binding Path=City}"></TextBlock> </StackPanel> </StackPanel> </DataTemplate> </StackPanel.Resources> <TextBlock></TextBlock> <ListBox x:Name="lbPersons" ItemsSource="{Binding Source={StaticResource persons}}" ItemTemplate="{DynamicResource personLayout}" IsSynchronizedWithCurrentItem="True"/> </StackPanel> </Window>

    Figure 6 Using a DataTemplate 

     

    Sorting the Data
    If you want to sort your data in a specific way, you can bind to a CollectionViewSource instead of directly to the ObjectDataProvider. The CollectionViewSource then becomes the data source and serves as an intermediary that intercepts the data from the ObjectDataProvider; provides sorting, grouping, and filtering functionality; and then propagates it to the target.
    The CollectionViewSource shown next has its Source attribute set to the resource name of the ObjectDataProvider (persons). I then defined a sort order for the data by indicating the properties to sort by and their direction:
     
    <CollectionViewSource x:Key="personView" Source="{Binding Source={StaticResource persons}}"> <CollectionViewSource.SortDescriptions> <ComponentModel:SortDescription PropertyName="City" Direction="Ascending" /> <ComponentModel:SortDescription PropertyName="FullName" Direction="Descending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource>
    The DataContext is used to bind all controls within a container control to a data source. This is very useful when you have several controls that all use the same binding source. The code could get repetitive if you indicated the binding source for every control. Instead, you can set the DataContext for the container of the controls to the binding source and simply omit the Source attribute from the contained controls. For example, here is a series of TextBlocks bound explicitly to the same binding source:
     
    <StackPanel> <TextBlock Text="{Binding Source={StaticResource personView}, Path=FullName}"></TextBlock> <TextBlock Text="{Binding Source={StaticResource personView}, Path=Title}"></TextBlock> <TextBlock Text="{Binding Source={StaticResource personView}, Path=City}"></TextBlock> </StackPanel>
    Here are the same three TextBoxes bound to the DataContext, which refers back to the controls' StackPanel container:
     
    <StackPanel DataContext="{Binding Source={StaticResource personView}}" > <TextBlock Text="{Binding Path=FullName}"></TextBlock> <TextBlock Text="{Binding Path=Title}"></TextBlock> <TextBlock Text="{Binding Path=City}"></TextBlock> </StackPanel>
    If the container does not define a DataContext, then it will continue to look at the next outer nested container until it finds the current DataContext.

     

    Forging Ahead
    WPF data binding offers a great deal of flexibility and control over the type of data that can be bound to, and how it can be controlled and displayed. With so much power and so many choices, I'm sure you'll want to get your hands dirty right away.

     

    Send your questions and comments for John to mmdata@microsoft.com.

    转载于:https://www.cnblogs.com/shawnzxx/p/3297988.html

    展开全文
  • WPF binding

    2012-07-22 13:05:37
    WPF里分三种BindingBinding, PriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension Binding 提供对绑定定义的高级别访问,绑定将绑定目标对象(通常...

    WPF里分三种Binding:Binding PriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension

    Binding

    提供对绑定定义的高级别访问,绑定将绑定目标对象(通常为 WPF 元素)的属性与任何数据源(例如数据库、XML 文件或包含数据的任何对象)连接起来。

    常见的使用Binding的代码:
    C#

    Binding binding = new Binding();
    // Set source object
    binding.Source = treeView;
    // Set source property
    binding.Path = new PropertyPath("SelectedItem.Header");
    // Attach to target property
    currentFolder.SetBinding(TextBlock.TextProperty, binding);

    XAML:

    <TextBlock x:Name=”currentFolder DockPanel.Dock=”Top
    Text=”{Binding ElementName=treeView, Path=SelectedItem.Header}
    Background=”AliceBlue FontSize=16/>

    所有FrameworkElement都包含SetBinding方法:SetBinding(DependencyProperty dp, String path), SetBinding(DependencyProperty dp, BindingBase binding),可以看出,FrameworkElement中的SetBinding只对DependencyProperty有效。

    另一种设置Binding的方法是:BindingOperations.SetBinding(currentFolder, TextBlock.TextProperty, binding);
    BindingOperations.SetBinding的原型是

    public static BindingExpressionBase SetBinding(
    	DependencyObject target,
    	DependencyProperty dp,
    	BindingBase binding
    )

    第一个参数是DependencyObject,所以我们可以对自定义DependencyObject或者继承自DependencyObject的类进行绑定。当然第二个参数还是DependencyProperty。

    清除Binding:
    BindingOperations.ClearBinding(currentFolder, TextBlock.TextProperty); //删除currentFolder上的TextBlock.TextProperty绑定
    BindingOperations.ClearAllBindings(currentFolder); //删除currentFolder上的所有绑定

    直接对dependency property赋值也可以解除binding, 不过只对单向binding有效。  


    Bingding的源:

    有三个属性用来设置源:ElementName(string)、Source(Object) 和 RelativeSource(RelativeSource)。注:这三个只能指定一个,否则异常。
    ElementName: 源为一个元素(Element),这里用的是此元素中设置的Name属性。
    Source:以object作为源。<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
    RelativeSource: 源相对于绑定目标的位置。
                            源是元素本身:{Binding RelativeSource={RelativeSource Self}}
                            源是Tempalte中元素的Parent:{Binding RelativeSource={RelativeSource TemplatedParent}}
                            源是绑定以collection形式的前一个数据:{Binding RelativeSource={RelativeSource PreviousData}},MSDN上关于PreviousData的说明并不多,这里有一篇文章可以参考
                            以上三项为RelativeSource中的Static值,使用这些值可以减少内存开销
                            源是Ancestor(可能比parent还高):{Binding RelativeSource={RelativeSource FindAncestor,
                                                                         AncestorLevel=n, AncestorType={x:Type desiredType}}}


    Path:

    Binding中的Path是 PropertyPath对象。

    在最简单的情况下,Path 属性值是要用于绑定的源对象的属性名称,如 Path=PropertyName。

    通过类似于 C# 中使用的语法,可以指定属性的子属性。例如,子句 Path=ShoppingCart.Order 将绑定设置为对象的子属性 Order 或属性 ShoppingCart。

    若要绑定到附加属性,请将附加属性用括号括起。例如,若要绑定到附加属性 DockPanel.Dock,则语法为 Path=(DockPanel.Dock)。

    在应用了索引器的属性名称之后的方括号内,可以指定属性的索引器。例如,子句 Path=ShoppingCart[0] 将绑定设置为与属性的内部索引处理文本字符串“0”的方式对应的索引。此外,还支持多个索引器。

    在 Path 子句中可以同时使用索引器和子属性,例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street]。

    在索引器内部,可以有多个由逗号 (,) 分隔的索引器参数。可以使用圆括号指定每个参数的类型。例如,可以使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空间。

    如果源为集合视图,则可以用斜杠 (/) 指定当前项。例如,子句 Path=/ 设置到视图中当前项的绑定。如果源为集合,则此语法指定默认集合视图的当前项。

    可以结合使用属性名和斜杠来遍历作为集合的属性。例如,Path=/Offices/ManagerName 指定源集合的当前项,该源集合包含同样是集合的 Offices 属性。其当前项是包含 ManagerName 属性的对象。

    也可以使用句点 (.)路径绑定到当前源。例如,Text=”{Binding}” 等效于 Text=”{Binding Path=.}”。


    BindingExpression

    Binding 类是高级别类。BindingExpression 类是基础对象,用于保持绑定源与绑定目标之间的连接。Binding 中包含可在多个 BindingExpression 对象之间共享的所有信息。也就是说,可以把一个Binding对象绑定对n个元素上,而针对这n个元素,分别有相应的n个BindingExpresion对象。
    Binding可以直接绑定普通的.net实例,比如int值。但是如果后台改变int值了,前台不能显示改变后的值,这时可以调用UpdateTarget()方法更新绑定。如下:BindingExpression be = button.GetBindingExpression(Button.ContentProperty);
    be.UpdateTarget();
     

    还有UpdateSource方法用来更新源。


    绑定到.net属性/对象:

    上面提到Binding绑到普通的.net属性,如果source变化了,UI上是不会显示的,除了用BindingExpression每次显式更新Target外,还可以使用如下技术:

    绑定到单个对象需实现INotifyPropertyChanged接口,这个接口只有一个成员:

    event PropertyChangedEventHandler PropertyChanged
     
    实现INotifyPropertyChanged的示例如下:
    using System.ComponentModel;
    
    namespace SDKSample
    {
      // This class implements INotifyPropertyChanged
      // to support one-way and two-way bindings
      // (such that the UI element updates when the source
      // has been changed dynamically)
      public class Person : INotifyPropertyChanged
      {
          private string name;
          // Declare the event
          public event PropertyChangedEventHandler PropertyChanged;
    
          public Person()
          {
          }
    
          public Person(string value)
          {
              this.name = value;
          }
    
          public string PersonName
          {
              get { return name; }
              set
              {
                  name = value;
                  // Call OnPropertyChanged whenever the property is updated
                  OnPropertyChanged("PersonName");
              }
          }
    
          // Create the OnPropertyChanged method to raise the event
          protected void OnPropertyChanged(string name)
          {
              PropertyChangedEventHandler handler = PropertyChanged;
              if (handler != null)
              {
                  handler(this, new PropertyChangedEventArgs(name));
              }
          }
      }
    }
    或者显式实现INotifyPropertyChanged:
    
    #region INotifyPropertyChanged Members
    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
    {
        add
        {
            this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value);
        }
        remove
        {
            this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value);
        }
    }
    #endregion
     
    看了上面代码着实没看出source值改变了,前台是通过什么机制反映的,正常的情况下公开了一个事件,必须有一个对此事件的实现体,而上面代码并没有实现PropertyChanged的方法。
    我猜想是Binding内部获取了这个接口并对PropertyChanged进行了赋值,因为在debug时,这个事件确实被赋值的,而赋值前的Stack是External Code调用的。
     
    绑定到集合需实现INotifyCollectionChanged,但是推荐使用ObservableCollection<T>,这个类实现了INotifyCollectionChanged和INotifyPropertyChanged。
     
    附:当绑定到普通的.net属性时,WPF使用反射取得source的值,当对象实现ICustomTypeDescriptor时,WPF使用这个接口取得值,性能上会有所提升。


    DataContext:


    DataContext在共享资源时最有用。

    <StackPanel x:Name="parent" DataContext="{StaticResource photos}">
    <Label x:Name="numItemsLabel"
    Content="{Binding Path=Count}"
    DockPanel.Dock="Bottom"/>
    也可以在代码这么写parent.DataContext = photos;
     


    Value Converters:

    IValueConverter可以在绑定时加入自己的逻辑,很好。

    public class RawCountToDescriptionConverter : IValueConverter
    {
    	public object Convert(object value, Type targetType, object parameter,
    		CultureInfo culture)
    	{
    		// Let Parse throw an exception if the input is bad
    		int num = int.Parse(value.ToString());
    		return num + (num == 1 ? " item" : " items");
    	}
    
    	public object ConvertBack(object value, Type targetType, object parameter,
    		CultureInfo culture)
    	{
    		throw new NotSupportedException();
    	}
    }
    IValueConverter就两个方法需要自己实现,Convert和ConvertBack,一个转过来,一个转过去。
    XAML代码如下
    <Label Background="{Binding Path=Count, Converter={StaticResource myConverter},
    Source={StaticResource photos}}"/>
    这里的myConverter是个resource,需要在xaml中预先定义:
    <Window.Resources>
    <local:CountToBackgroundConverter x:Key="myConverter"/>
    </Window.Resources>
     
    Path对应的Count值会作为第一个参数value传给Convert方法。
     
    注意,返回的值一定要是绑定时对应的值,比如绑定时需要绑到Geometry类上,那么Convert返回的也必须是Geometry类。
     
    Convert方法还带有一个parameter参数,可以在xaml中这么使用
    
    <Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, 
    ConverterParameter=Yellow, Source={StaticResource photos}}"/>

    ConverterParameter是object类型。
    C#代码中就可以得到parameter的值了。

    TIP:
    可以用Binding.DoNothing作返回值,以指示绑定引擎不要执行任何操作。
    可用使用[ValueConversion(typeof(DateTime), typeof(String))]来标识Converter要转化和返回的值类型,第一个参数是soure,第二个参数是target。这样在编译时,如果类型不匹配的话,编译器会抛出异常:error CS0592: Attribute 'ValueConversion' is not valid on this declaration type. It is only valid on 'class' declarations.

    .net自带一些converter,比如常用的BooleanToVisibilityConverter,可以根据checkbox是否勾上来隐藏其他控件。

    在collection中使用converter:使用DateTemplate,在其中使用Converter。(也可以使用Converter对整个collection进行转化,但是可能效率不好)


    Binding.Mode

    指示源和目标间数据流的方向。

    OneWay 源更新时,目标也更新
    TwoWay 源更新时目标也更新,或者目标更新时同时更新源
    OneTime 仅当应用程序启动时或 DataContext 进行更改时更新目标属性。绑一次就不更维护更新,目标相当于源的一次性镜像
    OneWayToSource 目标更新时更新源,和OneWay相反

    大部分WPF自带的控件的dependency property默认的是OneWay,像TextBox.Text默认的是TwoWay。
    值得注意的事,只读属性只能设置成OneWay,不能是TwoWay,否则运行时异常。

    对于 OneWay 或 TwoWay 绑定,对源的动态更改不会自动传播到目标。必须在源对象上实现 INotifyPropertyChanged 接口。
    对于 TwoWay 绑定,对目标的更改不会自动传播到源,除非绑定目标是 Text 属性。在这种情况下,更新仅在 TextBox 失去焦点时发生。
    对于 OneTime 和 OneWay 绑定,对 SetValue 的调用会自动更改目标值并删除绑定。

    再次提醒,源要实现了INotifyPropertyChanged 接口才能把改变反映到目标上。

    OneWayToSource 用于多个目标更改一个源的情况,可以想像成多人录入。或者用来实现源和目标倒置的情况。


    Binding.UpdateSourceTrigger

    指示使用TwoWay或OneWayToSource时,目标在什么情况下更新源。有三个枚举值

    PropertyChanged:目标属性改变时更新源
    LostFocus:失去焦点时更新源
    Explicit:只有在显式调用BindingExpression.UpdateSource方法时才更新源。BindingExpression可以通过BindingOperations.GetBindingExpression或FrameworkElement.GetBindingExpression方法获得

    Binding类中提供了SourceUpdated和TargetUpdated事件,可以用来记些log,不过必须相应的NotifyOnSourceUpdated或NotifyOnTargetUpdated设置成true才会激发事件。


    Binding的验证

    我们当然可以自己写代码验证数据的正确性,不过WPF提供了可以说是标准的方案,限于篇幅,我单独开了一贴,点这里查看。

     

     

    展开全文
  • WPF Binding Trace

    2020-04-10 10:52:11
    WPF中的Binding Trace 在WPF中,关于Binding的问题,由于不能直接调试跟踪,所以有时候很难fix,但是Binding支持log输出,通过相关的log信息,我们可以解决绝大部分问题。下面我看看如何使用它。 在XAML中添加...
  • WPF binding 参考

    2019-10-01 14:03:45
    This is an article on WPF Binding Cheat Sheet. Some of the Binding won't work for Silverlight 3. Basic Binding {Binding} Bind to current DataContext. {Bind...
  • BindingWPF中的使用

    2019-10-03 20:15:49
    闲来无事,不想打DOTA,在这里小小研究下wpf中关于Binding的东西。 咯咯 在我们印象中,Binding的意思是“绑定”,这个“绑”大概取自于Bind这个单词吧,这么理解的话就是以音译英了,没什么实际意义。 Bind这...
  • Enum Binding ItemsSource In WPF 原文:Enum Binding ItemsSource In WPFWPF中枚举绑定到ItemsSource。 一、通过ObjectDataProvider 获取Enum数据源 首先我们定义一个Enum类: public ...
  • 原贴:http://jimmangaly.blogspot.com/2009/04/debugging-data-binding-in-wpf.html ...What do you do when you suspect that a data binding is broken in your WPF application? Looking at the Output window f...
  • WPF学习之Binding(一)

    2014-12-29 16:35:00
    WPF的核心理念是传统的变UI驱动程序为数据驱动UI,支撑这个理念的基础就是Data Binding和与之相关的数据校验和转换。 使用Binding时,最重要的是准确设置它的源和路径。 Binding基础 Binding是数据的桥梁,两端...
  • WPFbinding

    2016-08-22 16:55:28
    深入浅出WPFBinding的使用(一)  在WPFBinding可以比作数据的桥梁,桥梁的两端分别是Binding的源(Source)和目标(Target)。一般情况下,Binding源是逻辑层对象,Binding目标是UI层的控件对象;这样,...
  • WPF TreeView Binding

    千次阅读 2013-11-18 20:15:06
    Bind Treeview In WPF TreeView Xmal ItemsSource="{Binding MenuDataSource}" Selec
  • WPF Binding 实验1

    2016-06-01 00:26:59
    WPF Binding 实验1

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,145
精华内容 1,258
关键字:

bindingwpf