• EssentialWPF_chapter6_Data


    Resource:

    Static Resources is static assignment, just can be used once.

    Dynamic resource

    The lookup path for resources is

    1. Element hierarchy

    2. Application.Resources

    3. Type theme

    4. System theme

     

    A resource needs to be used more than once: FrameworkElementFactory. For elements

    in control templates, we create a factory instead of creating the elements

    directly.

    Most visual objects (brushes, pens, meshes, etc.) dont require a

    factory, because they support multiuse by virtue of deriving from

    Freezable.3

    (Freezable objects support sharing by having a frozen mode, in which they cannot be

    changed. The frozen mode allows for a single instance to be used by multiple objects, without

    consumers having to watch for changes in the object)

     

    <Button Background='{DynamicResource toShare}' Click='Clicked'>

    this.Resources["toShare"] = newBrush;

     

    button1.SetResourceReference(

    Button.BackgroundProperty,

    "toShare");

     

     

    We can explicitly set the

    DataContext property on any element and that data source will be used for

    any bindings on that element (or its children).

     

    Panel1.DataContext = new Name();

     

    When any resource is changed, the entire tree is updated. Therefore,

    static and dynamic resource references can be used in many places without

    a cost per reference being incurred. What this means is that we should not

    make frequent changes of resources to update the UI. It also means that we

    should not worry about using lots of resource references.

     

    resources are optimized for coarse-grained changes.

     

     

    Basic Binding:

     

    Binding bind = new Binding();

    bind.Source = textBox1;

    bind.Path = new PropertyPath("Text");

     

    contentControl1.SetBinding(ContentControl.Content, bind);

     

    <ContentControl Margin='5' x:Name='contentControl1'

    Content='{Binding ElementName=textBox1,Path=Text}' />

     

     

    ValueConverter

     

    public class HumanConverter : IValueConverter {

    public object Convert(object value, Type targetType,

    object parameter, CultureInfo culture) {

    Human h = new Human();

    h.Name = (string)value;

    return h;

    }

    public object ConvertBack(object value, Type targetType,

    object parameter, CultureInfo culture) {

    return ((Human)value).Name;

    }

    }

     

     

      <ContentControl  Margin="5" BorderThickness="3">

                <ContentControl.Content >

                    <Binding  ElementName="textbox1" Path="Text">

                        <Binding.Converter>

                            <l:HumanConverter></l:HumanConverter>

                        </Binding.Converter>

                    </Binding>

                </ContentControl.Content>

                <ContentControl.ContentTemplate >

                    <DataTemplate DataType="{x:Type l:Human}">

                        <Border Margin='5' Padding='5' BorderBrush='Black' BorderThickness='3' CornerRadius='5'>

                               <TextBlock Text='{Binding Path=Name}' />

                        </Border>

                    </DataTemplate>

                </ContentControl.ContentTemplate>

            </ContentControl>

     

    Property Change:

     

    To enable our Person object model to support change notification,

    we have three options: (1) implement INotifyPropertyChanged,

    (2) Add events that report changes to properties, or (3) create Dependency-

    Property-based properties.

     

    Generally, when creating data models we should implement INotify-

    PropertyChanged. Using DependencyProperty-based properties adds the

    requirement of deriving from DependencyObject, which in turn ties the

    data object to an STA thread.

     

    public class Name : INotifyPropertyChanged

        {

            private string _first;

     

            public string First

            {

                get { return _first; }

                set { _first = value; NotifyChanged("First"); }

            } private void NotifyChanged(string property)

            {

                if (PropertyChanged != null)

                {

                    PropertyChanged(this,new PropertyChangedEventArgs(property));

                }

           

            }

     

     

            #region INotifyPropertyChanged Members

     

            public event PropertyChangedEventHandler PropertyChanged;

     

            #endregion

    }

     

    <StackPanel.DataContext >

             <l:Name  x:Name="myName" First="daf" Last="ddfdf"></l:Name>

    </StackPanel.DataContext>

    <Label Grid.Row='0' Grid.Column='0'>First</Label>

                        <TextBox Grid.Row='0' Grid.Column='1'

                        Text='{Binding Path=First}' />

                        <Label Grid.Row='1' Grid.Column='0'>Last</Label>

    <TextBox Grid.Row='1' Grid.Column='1'

                        Text='{Binding  UpdateSourceTrigger=PropertyChanged,Path=Last}' />

     

    bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

     

     

    Lists are more complicated than just property changes:

     

    INotifyCollectionChanged

     

    public class NotifyCollectionChangedEventArgs : EventArgs {

    public NotifyCollectionChangedAction Action { get; }

    public IList NewItems { get; }

    public int NewStartingIndex { get; }

    public IList OldItems { get; }

    public int OldStartingIndex { get; }

    }

    public enum NotifyCollectionChangedAction {

    Add,

    Remove,

    Replace,

    Move,

    Reset,

    }

     

    The ObservableCollection<T> has inherited INotifyCollectionChanged, so we can use it directly.

       public class Persion

        {

            private IList<Address> addresses = new ObservableCollection<Address>();

     

            public IList<Address> Addresses

            {

                get { return addresses; }

                set { addresses = value; }

            }

     

     

    }

    public class Address:INotifyPropertyChanged

     

    <StackPanel.Resources >

                    <DataTemplate x:Key='addressTemplate'>

                        <StackPanel Orientation='Horizontal'>

                            <TextBlock Text='{Binding Path=Street1}' />

                            <TextBlock Text=',' />

                            <TextBlock Text='{Binding Path=City}' />

                            <TextBlock Text=',' />

                            <TextBlock Text='{Binding Path=State}' />

                            <TextBlock Text=',' />

                            <TextBlock Text='{Binding Path=Zip}' />

                            </StackPanel>

                    </DataTemplate>

                </StackPanel.Resources>

    <StackPanel.DataContext >

                    <l:Persion></l:Persion>

                </StackPanel.DataContext>

                <ListBox ItemsSource="{Binding Path =Addresses}" ItemTemplate="{DynamicResource addressTemplate}"> //这里我还在想用IValueConverter,template

     

                </ListBox>

                <Button Click="AddButton">Add</Button>

     

    private void AddButton(object sender, RoutedEventArgs e)

            {

                Address a = new Address();

                a.Street1 = "street1";

                a.City = "city";

                a.State = "state";

                a.Zip = "zip";

                ((Persion)(CollectionStackPanel.DataContext)).Addresses.Add(a);

            }

     

     

    XML Binding:

    public class Window1 : Window {

    public Window1() {

    XmlDocument doc = new XmlDocument();

    doc.LoadXml(...);

    XmlDataProvider dataSource = new XmlDataProvider();

    dataSource.Document = doc;

    Binding bind = new Binding();

    bind.Source = dataSource;

    bind.XPath = "/Media/Book/@Title";

    ListBox list = new ListBox();

    list.SetBinding(ListBox.ItemsSourceProperty, bind);

    Title = "XML Binding";

    Content = list;

    }

     

    }

    <Window x:Class='BookScratch.Window1'

    xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'

    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'

    Text='XML Binding'

    DataContext='{DynamicResource dataSource}'

    <Window.Resources>

    <XmlDataProvider x:Key='dataSource'>

    ...

    </XmlDataProvider>

    </Window.Resources>

    <ListBox

    ItemsSource= '{Binding XPath=/Media/Book/@Title}' />

    </Window>

     

     

    DataTemplate:

     

    data templates allow us to define how a piece of

    data will appear.

     

    The DataTemplate type resembles ControlTemplate quite a bit. They

    both leverage FrameworkElementFactory to define the display tree. Control-

    Template defines a display tree for a control, within which we use template

    binding to wire up display properties to control properties. DataTemplate,

    however, defines a display tree for a data item, within which we use data

    binding to wire up display properties to data properties. DataTemplate also

    automatically sets the data context of the display tree to be the template

    data item.

     

     

    public class Window1 : Window {

    public Window1() {

    XmlDocument doc = new XmlDocument();

    doc.LoadXml(...);

    XmlDataProvider dataSource = new XmlDataProvider();

    dataSource.Document = doc;

    Binding bind = new Binding();

    bind.Source = dataSource;

    bind.XPath = "/Media/Book";

    ListBox list = new ListBox();

    list.SetBinding(ListBox.ItemsSourceProperty, bind);

    Title = "XML Binding";

    Content = list;

    }

    }

     

    ///////////create our template

    DataTemplate template = new DataTemplate();

    template.DataType = typeof(XmlElement);

     

    FrameworkElementFactory textFactory =

    new FrameworkElementFactory(typeof(TextBlock));

     

    Binding bind = new Binding();

    bind.XPath="@Title";

    textFactory.SetBinding(TextBlock.TextProperty, bind);

     

    template.VisualTree = textFactory;

    <Window ...

    xmlns:sx='clr-namespace:System.Xml;assembly=System.Xml'

    Title='XML Binding'

    DataContext='{DynamicResource dataSource}'

    <Window.Resources>

    <XmlDataProvider x:Key='dataSource'>

    ...

    </XmlDataProvider>

    <DataTemplate x:Key='template' DataType='{x:Type sx:XmlElement}'>

    <TextBlock Text='{Binding XPath=@Title}' />

    </DataTemplate>

    </Window.Resources>

    <ListBox

    ItemsSource= '{Binding XPath=/Media/Book }'

    ItemTemplate='{DynamicResource template}' />

    </Window>

     

     

    DataTemplate Selector:

     

    DataTemplateSelector provides a single method, SelectTemplate,

    that allows us to perform any logic we want to determine which template

    to return. We can find the template in the contained element (i.e., ListBox)

    and return some hard-coded templates, or even dynamically create a template

    for each item.

     

     

    <Window ... Title='XML Binding'>

    <Window.Resources>

    <XmlDataProvider x:Key='dataSource'>

    <x:XData>

    <Media xmlns=''>

    <Book Author='John' Title='Fish are my friends' />

    <Book Author='Dave' Title='Fish are my enemies' />

    <Book Author='Jane' Title='Fish are my food' />

    <CD Artist='Jane' Title='Fish sing well' />

    <DVD Director='John' Title='Fish: The Movie'>

    <Actor>Jane</Actor>

    <Actor>Dave</Actor>

    </DVD>

    </Media>

    </x:XData>

    </XmlDataProvider>

    </Window.Resources>

    <ListBox

    ItemsSource =

    '{Binding XPath=/Media/Book/@Title,Source={StaticResource dataSource}}'

    />

    </Window>

     

     

    public class LocalNameTemplateSelector : DataTemplateSelector {

    public override DataTemplate SelectTemplate(object item,

    DependencyObject container) {

    XmlElement data = item as XmlElement;

    if (data != null) {

    return ((FrameworkElement)container).FindResource(data.LocalName)

    as DataTemplate;

    }

    return null;

    }

    }

    <Window.Resources>

    <XmlDataProvider x:Key='dataSource'>

    ...

    </XmlDataProvider>

    <DataTemplate x:Key='Book' DataType='{x:Type sx:XmlElement}'>

    ...

    </DataTemplate>

    <DataTemplate x:Key='CD' DataType='{x:Type sx:XmlElement}'>

    ...

    </DataTemplate>

    <DataTemplate x:Key='DVD' DataType='{x:Type sx:XmlElement}'>

    ...

    </DataTemplate>

    </Window.Resources>

    <ListBox

    ItemsSource= '{Binding XPath=/Media/*}'>

    <ListBox.ItemTemplateSelector>

    <l:LocalNameTemplateSelector

    xmlns:l='clr-namespace:EssentialWPF' />

    </ListBox.ItemTemplateSelector>

    </ListBox>

     

     

     Hierarchical Binding:

    <ListBox ItemsSource='{Binding}'> // a period (.) path can be used to bind to the current source. For example, Text=”{Binding}” is equivalent to Text=”{Binding Path=.}”.

    <ListBox

                    ItemsSource='{Binding}' Width ="300">

                    <ListBox.ItemTemplate>

                        <DataTemplate>

                            <StackPanel>

                                <TextBlock Text='{Binding Path=Name}' />

                                <ListBox Height='75' Width="250">

                                <!-- ItemsSource for the inner ListBox

                                is going to be the collection of

                                child items. -->

                                <ListBox.ItemsSource>

                                <Binding Path='.'>

                                <Binding.Converter>

                                <l:GetFileSystemInfosConverter />

                                </Binding.Converter>

                                </Binding>

                                </ListBox.ItemsSource>

                                <!-- The items inside of the inner ListBox

                                get to be just TextBlocks. -->

                               </ListBox>

                               </StackPanel>

                        </DataTemplate>

                    </ListBox.ItemTemplate>

                </ListBox>

    "{Binding RelativeSource={x:Static RelativeSource.Self},

                            Path=(Validation.Errors)[0].ErrorContent}"/

     

    Use Resource:

    <StackPanel Name="filesStackPanel" xmlns:io='clr-namespace:System.IO;assembly=mscorlib'>

                <StackPanel.Resources >

                    <DataTemplate DataType='{x:Type io:DirectoryInfo}'>

                        <StackPanel>

                            <TextBlock Text='{Binding Path=Name}' />

                            <ListBox>

                            <ListBox.ItemsSource>

                            <Binding Path='.'>

                            <Binding.Converter>

                            <l:GetFileSystemInfosConverter />

                            </Binding.Converter>

                            </Binding>

                            </ListBox.ItemsSource>

                            </ListBox>

                            </StackPanel>

                    </DataTemplate>

                </StackPanel.Resources>        

    Wait! Where is the recursion? Data templates can be discovered

    by the DataType property. This means that when ListBox sees an

    item of type DirectoryInfo, it will automatically find the template that we

    just defined. Within that template is a nested list box that will do the same

    thing.

     

     

    For a control, like TreeView or Menu, that natively supports hierarchy,

     

    public class HierarchicalDataTemplate : DataTemplate {

    public BindingBase ItemsSource { get; set; }

    public DataTemplate ItemTemplate { get; set; }

    public DataTemplateSelector ItemTemplateSelector { get; set; }

    }

     

    Datacontext 是一个directoryInfo[], 但是datatemplate用的时候好像直接作为DirectoryInfo,itemssource 接受collection value.是因为itemsSource 在一个一个调用item时,用directoryInfo template 来处理。

    <HierarchicalDataTemplate DataType='{x:Type io:DirectoryInfo}'>

                        <HierarchicalDataTemplate.ItemsSource>

                            <Binding Path='.'>

                                <Binding.Converter>

                                    <l:GetFileSystemInfosConverter />

                                </Binding.Converter>

                            </Binding>

                        </HierarchicalDataTemplate.ItemsSource>

                        <TextBlock Text='{Binding Path=Name}' />

                    </HierarchicalDataTemplate>

                </StackPanel.Resources>

     

                <TreeView ItemsSource='{Binding}'/>

     

    Collection Views:

    Up to now we have talked about three objects in play to perform binding:

    the data source, the binding, and the target element. With list binding

    there is actually a fourth player: the collection view.

    We can think of the collection view as a lightweight wrapper on the underlying data that allows us to have multiple views on top of the same data.

     

    with larger data sets it

    becomes increasingly important not to load the data into memory more

    than once.

    同一组数据,不同的view

     

    The most important service that a collection view supplies is currency

    management, tracking the current item in a list. IsSynchronizedWithCurrentItem

    This property synchronizes the list selection with the current item in the view.

     

     

  • 相关阅读:
    正则表达式基础知识
    成功的基本法则
    Java实现简单的格式化信函生成器
    C实现哈希表
    C实现求解给定文本中以指定字符开头和结尾的子串数量的三种算法
    Java实现求解二项式系数及代码重构
    Java 异常处理学习总结
    C实现大整数幂求模问题的两种算法
    linux 学习前言
    提高编程能力的10种方法
  • 原文地址:https://www.cnblogs.com/liangouyang/p/1296166.html
Copyright © 2020-2023  润新知