Silverlight实用窍门系列:64.Silverlight中的DataContext和ItemsSource

本文详细介绍了Silverlight中数据绑定的两种方式:DataContext和ItemsSource的区别及用法,并通过一个具体示例展示了如何使用DataContext来绑定实体数据。

    在Silverlight中我们经常看到数据绑定源由DataContext或者ItemsSource指定,那么他们之间的区别有哪些呢?

    DataContext:从英文字母意思是数据上下文,在Silverlight中某个父级元素设置了DataContext,那么其子元素将可以继承并且使用DataContext中的属性。DataContext绑定的数据源可以是实体集合、实体、属性等。

    ItemsSource:其数据源通常是实体集合(多列数据),无法让其子元素继承使用。

    下面我们以一个实例主要讲解DataContext的用法,其中在父级元素Grid设置了一个DataContext属性绑定实体,该实体内部有一个属性为实体集合,此实体集合用于Grid的子元素ListBox的ItemsSource属性绑定。代码如下:

    首先我们看两个实体,其中一个实体属性为List<>:

    public class ClaModel
    {
        public ClaModel()
        {
            ClaName = "五年级三班";
            ClaInfo = "全校最好的班级,获得多项荣誉";
            StuList = new List<StuModel>()
            {
                new StuModel(){StuName="刘三", StuAge=15, StuInfo="他很勤奋"},
                new StuModel(){StuName="李四", StuAge=14, StuInfo="他很懒惰"},
                new StuModel(){StuName="王五", StuAge=16, StuInfo="他很聪明"}
            };
        }
        public string ClaName { get; set; }

        public string ClaInfo { get; set; }

        public List<StuModel> StuList { get; set; }
    }

    public class StuModel
    {
        public string StuName { get; set; }

        public int StuAge { get; set; }

        public string StuInfo { get; set; }

    }

    其次我们来看Xaml代码绑定如下:

<UserControl x:Class="SLDataContext.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SLDataContext"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <!--第一种方式-->
    <UserControl.Resources>
        <local:ClaModel x:Key="ClaSource" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ClaSource}">
        <TextBlock FontWeight="Bold" Width="60" Height="30" Text="{Binding ClaName}" 
                   VerticalAlignment="Top" HorizontalAlignment="Left"   />
        <TextBlock FontStyle="Italic"  Width="160" Height="30" Text="{Binding ClaInfo}"
                   VerticalAlignment="Top" Margin="70 0 0 0" HorizontalAlignment="Left"  />
        <ListBox Height="239" HorizontalAlignment="Left" Name="lbDetail"
                 VerticalAlignment="Top" Width="343" ItemsSource="{Binding StuList}" 
                 SelectedValuePath="StuAge" DisplayMemberPath="StuName" Margin="27,61,0,0" />
    </Grid>
</UserControl>

    最后我们看看另外一种后台绑定DataContext的方式。

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            //第二种方式:也可以用后台代码绑定DataContext
            //this.LayoutRoot.DataContext = new ClaModel();
        }
    }

    如需源码请点击 SLDataContext.zip 下载 ,效果图如下:

     

转载于:https://www.cnblogs.com/chengxingliang/archive/2012/04/23/2464952.html

<think>我们正在讨论WPF中的命令绑定事件处理问题。用户的问题:如何避免ComboBox的PreviewSelectionChanged事件触发TabControl的TabSelectionChangedCommand绑定。关键点:当ComboBox选择改变时,它可能会冒泡事件到父控件TabControl,从而触发TabControl的SelectionChanged事件,进而触发绑定的命令。解决方案思路:1.在ComboBox的事件处理中设置e.Handled=true,以停止事件冒泡。但注意:PreviewSelectionChanged事件是隧道事件(Tunneling),而SelectionChanged事件是冒泡事件(Bubbling)。如果TabControl监听的是SelectionChanged事件(冒泡阶段),那么在ComboBox的PreviewSelectionChanged(隧道阶段)中设置e.Handled=true并不会阻止冒泡阶段的事件。因此,我们需要在ComboBox的SelectionChanged事件(冒泡事件)中处理。2.另一种方法是检查事件源(e.OriginalSource)在TabControl的SelectionChanged事件处理中,如果事件源是ComboBox,则忽略该事件。3.使用命令绑定时,可以在命令执行前判断事件源,如果不是TabItem则忽略。具体实现:方法一:在ComboBox的SelectionChanged事件处理程序中标记事件已处理```csharpprivatevoidComboBox_SelectionChanged(objectsender,SelectionChangedEventArgse){//处理ComboBox的选择改变逻辑//...//阻止事件继续冒泡e.Handled=true;}```注意:此方法会阻止所有冒泡到父元素的SelectionChanged事件,如果父元素需要处理同一个事件则不可行。方法二:在TabControl的SelectionChanged事件处理程序中过滤事件源假设TabControl的SelectionChanged事件绑定了一个命令,我们可以在命令执行之前判断事件是否由TabItem触发。但是,命令绑定通常不直接提供事件源信息,所以我们可以通过事件处理程序来调用命令,并在其中进行过滤。例如,在TabControl的SelectionChanged事件处理程序中:```csharpprivatevoidTabControl_SelectionChanged(objectsender,SelectionChangedEventArgse){//检查事件源,如果事件源是ComboBox,则忽略if(e.OriginalSourceisComboBox)return;//否则,执行命令if(YourCommand.CanExecute(null))YourCommand.Execute(null);}```方法三:使用行为(Behavior)或附加属性来增强命令绑定,使其可以包含过滤条件。方法四:在命令绑定的命令执行方法中判断当前选中的TabItem是否真的改变。但是这种方法可能无法区分是TabItem改变还是内部的ComboBox改变触发的。根据用户的具体情况,可能更合适的是方法二,因为它直接过滤了由ComboBox触发的事件。然而,用户使用了TabSelectionChangedCommand绑定,可能是通过某种MVVM框架实现的,比如Prism。在Prism中,我们可以使用Interaction.Triggers来绑定命令,并且可以通过设置事件参数来过滤。在Prism中,我们可以这样写:```xml<TabControlprism:EventTriggerBase.EventName="SelectionChanged"><i:Interaction.Triggers><prism:EventTrigger><prism:InvokeCommandActionCommand="{BindingTabSelectionChangedCommand}"/></prism:EventTrigger></i:Interaction.Triggers><!--...--></TabControl>```但是,Prism的EventTrigger默认会传递EventArgs,我们需要过滤。我们可以通过创建一个自定义的TriggerAction来实现。自定义TriggerAction示例:```csharppublicclassFilteredSelectionChangedTriggerAction:InvokeCommandAction{protectedoverridevoidInvoke(objectparameter){if(parameterisSelectionChangedEventArgsargs&&args.OriginalSourceisComboBox)return;base.Invoke(parameter);}}```然后在XAML中使用:```xml<prism:EventTrigger><local:FilteredSelectionChangedTriggerActionCommand="{BindingTabSelectionChangedCommand}"/></prism:EventTrigger>```如果用户没有使用Prism,而是使用System.Windows.Interactivity的EventTrigger,同样可以创建类似的TriggerAction。考虑到用户可能希望最小化代码改动,方法二(在事件处理程序中过滤)可能是最直接的。总结:根据用户的具体框架代码结构,可以选择不同的方法。如果用户使用的是纯事件处理,方法二简单有效;如果使用Prism等框架,则可以通过自定义TriggerAction实现。相关问题:1.WPF中的事件路由(冒泡隧道)机制是怎样的?2.如何创建自定义的TriggerAction来过滤事件?3.在MVVM模式中,如何处理控件事件而不破坏模式?</think>### 避免ComboBox选择触发TabControl的TabSelectionChangedCommand 在WPF中,当`ComboBox`位于`TabControl`内部时,其`SelectionChanged`事件会冒泡到父控件,导致`TabControl`的`TabSelectionChangedCommand`被意外触发。以下是三种解决方案: --- #### 方法1:在ComboBox事件中标记事件已处理 ```xml <ComboBox SelectionChanged="ComboBox_SelectionChanged"/> ``` ```csharp private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { // 处理ComboBox逻辑 // ... e.Handled = true; // 阻止事件冒泡到TabControl } ``` **原理**:`e.Handled = true`终止路由事件向上传递[^1]。 --- #### 方法2:在命令中过滤事件源 在`TabSelectionChangedCommand`执行逻辑中添加源类型检查: ```csharp private void TabSelectionChangedCommandExecute(object parameter) { if (parameter is SelectionChangedEventArgs args && args.OriginalSource is ComboBox) // 检查事件源 { return; // 忽略ComboBox触发的事件 } // 正常处理Tab切换逻辑 } ``` --- #### 方法3:使用附加行为拦截事件 创建附加属性拦截`PreviewMouseLeftButtonDown`事件: ```csharp public static class ComboBoxBehavior { public static bool GetSuppressSelectionBubble(DependencyObject obj) => (bool)obj.GetValue(SuppressSelectionBubbleProperty); public static void SetSuppressSelectionBubble(DependencyObject obj, bool value) => obj.SetValue(SuppressSelectionBubbleProperty, value); public static readonly DependencyProperty SuppressSelectionBubbleProperty = DependencyProperty.RegisterAttached("SuppressSelectionBubble", typeof(bool), typeof(ComboBoxBehavior), new PropertyMetadata(false, OnSuppressChanged)); private static void OnSuppressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is ComboBox comboBox) { comboBox.PreviewMouseLeftButtonDown -= ComboBox_PreviewMouseDown; if ((bool)e.NewValue) { comboBox.PreviewMouseLeftButtonDown += ComboBox_PreviewMouseDown; } } } private static void ComboBox_PreviewMouseDown(object sender, MouseButtonEventArgs e) { e.Handled = true; // 阻止事件路由 ((ComboBox)sender).Focus(); // 保持焦点 } } ``` **使用方式**: ```xml <ComboBox local:ComboBoxBehavior.SuppressSelectionBubble="True"/> ``` --- #### 关键注意事项 1. **事件路由机制**:WPF事件采用`隧道→冒泡`路由策略,`ComboBox.SelectionChanged`是冒泡事件[^2] 2. **命令绑定差异**:`TabSelectionChangedCommand`通常绑定到`SelectionChanged`事件 3. **作用域隔离**:当`ComboBox`在`DataTemplate`中时,需通过`RelativeSource`定位父级`TabControl` > 推荐优先使用**方法1**,代码简洁且符合WPF事件处理规范。若需MVVM模式解耦,可选用**方法3**的附加行为方案。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值