zoukankan      html  css  js  c++  java
  • Property trigger VS DataTrigger

    Original: http://blog.sina.com.cn/s/blog_4cc3c0380100j9ra.html

    Consider the following screenshot. There is a ListBox which simply hold several string items. We want the items get red foreground when the mouse hover the item. How can we achieve this simply requirement?


    #1 Generally, we may use the DataTrigger in this case. We bind the IsMouseOver property of the current ListBoxItem using the find ancestor syntax. Something like the following:

    <DataTrigger Binding="{Binding Path=IsMouseOver,
    RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="True" >
    <
    Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </
    DataTrigger>

    【PCH】:沿着VisualTree找到ListBoxItem,查询他的IsMouseOver属性,这当然是可行的。注意ListBox显示集合的方法是对集合中的每一项,都用一个ListBoxItem包起来,就算是实现了DataTemplate也是一样的,ListBoxItem里面有一个ContentPresenter用来显示内容的。



    #2

    If necessary, we can utilize a value converter to detect the details in the binding. In additional to this approach, are there other ways doable?

    Of course, we can use property trigger to achieve this goal. Now let’s try the explorer.

    <Trigger Property="IsMouseOver" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </Trigger> 

    【PCH】:这个也是可行的,这个是Property Trigger,其实所有的属性都是查询或者应用于ContentPresenter的,因为ContentPresenter具有IsMouseOver属性,这当然是可行的。



    Run the code above, we surprisedly find that it works. So who is the element that the IsMouseOver applied on? In order to research it more, we can use RelativeSource binding syntax like below:



    #3.

    <DataTrigger Binding="{Binding Converter={StaticResource converter}, RelativeSource={RelativeSource Self}}" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </DataTrigger> 


    【PCH
    】:注意这里RelativeSource Self,找到的是ContentPresenter所以,这个也是可行的。

    TestConverter: (PCH: 仅仅用于测试用的)



    public class TestConverter : IValueConverter
     {
     #region IValueConverter Members
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
     return value; // add break point here 
     }
     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
     throw new NotImplementedException();
    }
     #endregion
     } 


    We add a break point at the Convert method in the code behind to see the value type. Wow, the value is of type ContentPresenter.No wonder the IsMouseOver property trigger works in this way. Actually, if we have a look at the default template of the ListBoxItem, we could figure that the DataTemplate is the ContentTemplate of the ContentPresenter.



    <ListBoxItem.Template>
     <!--other code-->
     <ContentPresenter
     Content="{TemplateBinding ContentControl.Content}"
     ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
     ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
     HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
     VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
     SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
    </ListBoxItem.Template> 



    Yep, armed with this knowledge, we can also do it like this, just add the Path in the binding:



    #3:



    <DataTrigger Binding="{Binding Path=IsMouseOver, Converter={StaticResource converter}, RelativeSource={RelativeSource Self}}" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </DataTrigger> 


    Here is the full version of the code:



    <Window x:Class="WpfDataTriggerTest.Window1"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:local="clr-namespace:WpfDataTriggerTest"
     xmlns:s="clr-namespace:System;assembly=mscorlib"
     Title="Window1" Height="300" Width="300">
    <Window.Resources>
    <x:Array Type="{x:Type s:String}" x:Key="data">
    <s:String>Item1</s:String>
    <s:String>Item2</s:String>
    <s:String>Item3</s:String>
    <s:String>Item5</s:String>
    <s:String>Item6</s:String>
    </x:Array>
    <local:TestConverter x:Key="converter" />
    </Window.Resources>
    <StackPanel>
     <!--<local:UserControl1>
    </local:UserControl1>-->
     <ListBox DataContext="{Binding Source={StaticResource data}}"
     ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
    <DataTemplate>
    <TextBlock Text="{Binding}" Name="textBlock" />
    <DataTemplate.Triggers>
     <!--# use property trigger-->
     <Trigger Property="ContentPresenter.IsMouseOver" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </Trigger>
     <!--#2 the Self value is ContentPresenter-->
     <DataTrigger Binding="{Binding Path=IsMouseOver, Converter={StaticResource converter}, 
     RelativeSource={RelativeSource Self}}" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </DataTrigger>
     <!--#3 the AncestorType is ListBox -->
     <DataTrigger Binding="{Binding Path=IsMouseOver, Converter={StaticResource converter}, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </DataTrigger>
     <!--#4 it's the items object, not the UI element ListBoxItem-->
     <DataTrigger Binding="{Binding}" Value="True" >
    <Setter Property="Foreground" Value="Red" TargetName="textBlock" />
    </DataTrigger>
    </DataTemplate.Triggers>
    </DataTemplate>
    </ListBox.ItemTemplate>
    </ListBox>
    </StackPanel>
    </Window>
     



    In the code behind:



    using System;
     using System.Windows;
     using System.Windows.Data;
     namespace WpfDataTriggerTest
    {
     public partial class Window1 : Window
     {
     public Window1()
    {
    InitializeComponent();
    }
    }
     public class TestConverter : IValueConverter
     {
     #region IValueConverter Members
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
     return value; // add break point here
     }
     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
     throw new NotImplementedException();
    }
     #endregion
     }
    } 



    The key point is this scenario is having a clear idea of what is the Self object, and what is the {Binding} section stands for.



    Just as a kind reminder, when we use the RelativeSource={RelativeSource Self} syntax here, the Self is of ContentPresent type. While using the



    Binding="{Binding}" syntax, we get the object item here. Namely the item: item1, item2, item3, etc.

  • 相关阅读:
    好记性不如烂笔杆android学习笔记<十四> EditText 画行,解决光标压线问题
    好记性不如烂笔杆android学习笔记<十五> GridView简单用法
    分享个好玩的算法游戏
    ubuntu环境下lnmp环境搭建(3)之Php
    数据可视化之美之疾病潜在关联
    ubuntu环境下lnmp环境搭建(2)之Nginx
    乐观锁和悲观锁
    表单无刷新上传图片
    ubuntu环境下lnmp环境搭建(1)之Mysql
    祭旗篇关于提高技术团队技术氛围的一些尝试
  • 原文地址:https://www.cnblogs.com/puncha/p/3877036.html
Copyright © 2011-2022 走看看