Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 如何处理附加属性事件?_Wpf_Events_Mvvm_Attached Properties - Fatal编程技术网

Wpf 如何处理附加属性事件?

Wpf 如何处理附加属性事件?,wpf,events,mvvm,attached-properties,Wpf,Events,Mvvm,Attached Properties,我创建了一个扩展样式,它的标题中包含一个复选框。复选框状态绑定到附加的属性: <Style TargetType="{x:Type Expander}" x:Key="MyCheckboxExpander"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Expander}">

我创建了一个扩展样式,它的标题中包含一个复选框。复选框状态绑定到附加的属性:

<Style TargetType="{x:Type Expander}" x:Key="MyCheckboxExpander">
    <Setter Property="Template">
         <Setter.Value>
              <ControlTemplate TargetType="{x:Type Expander}">
               (...)
                   <CheckBox x:Name="ExpanderHeaderChk" VerticalAlignment="Center" Margin="4,0,0,2" 
                                          IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(my:AP.IsChecked)}" />
                (...)

(...)
(...)
在我的视图中,扩展器内有一个带有组合框的stackpanel

每当用户选中expander的复选框时,我不希望combobox选中第一个项目;另一方面,每当用户取消选中它时,我不希望combobox的selecteditem为空


我怎样才能做到这一点?我遵循MVVM模式,但由于这更多是一个视图问题,我愿意接受代码隐藏建议。

好吧,我认为您的设计不是最优的。你看,你正试图改变
扩展器的语义。真正的扩展器没有附加复选框的语义,因此您正在创建的控件不再是扩展器

我建议您切换到用户控件(或者自定义控件,看看您的语义),并在控件的类中公开所需的事件。用户控件的XAML可能应该是带有复选框的扩展器


编辑:带有UserControl的示例(未测试)

(XAML)


...
...
(代码隐藏)

公共类MyCheckboxExpander:UserControl
{
MyCheckboxExpander()
{
初始化组件();
cb.Check+=OnCheck;
}
void OnCheck(对象发送方,whatever2参数)
{
如果(CheckboxTriggered!=null)
CheckboxTriggered(新事件参数);
}
公共事件事件args CheckboxTriggered;
}

嗯,我认为你的设计不是最优的。你看,你正试图改变
扩展器的语义。真正的扩展器没有附加复选框的语义,因此您正在创建的控件不再是扩展器

我建议您切换到用户控件(或者自定义控件,看看您的语义),并在控件的类中公开所需的事件。用户控件的XAML可能应该是带有复选框的扩展器


编辑:带有UserControl的示例(未测试)

(XAML)


...
...
(代码隐藏)

公共类MyCheckboxExpander:UserControl
{
MyCheckboxExpander()
{
初始化组件();
cb.Check+=OnCheck;
}
void OnCheck(对象发送方,whatever2参数)
{
如果(CheckboxTriggered!=null)
CheckboxTriggered(新事件参数);
}
公共事件事件args CheckboxTriggered;
}

WPF是一个功能强大的框架,您只需使用下一种样式的Expander即可解决问题:

 <Style x:Key="myExpanderStyle" TargetType="{x:Type Expander}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <StackPanel>
                            <CheckBox x:Name="PART_CheckBox" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
                            <ComboBox x:Name="PART_ComboBox" ItemsSource="{TemplateBinding Content}" />
                        </StackPanel>

                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="True">
                                <Setter TargetName="PART_ComboBox" Property="SelectedIndex" Value="0"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

样本:

<Expander Style="{StaticResource myExpanderStyle}">
            <x:Array Type="sys:String">
                <sys:String>1</sys:String>
                <sys:String>2</sys:String>
                <sys:String>3</sys:String>
            </x:Array>
        </Expander>

1.
2.
3.
只是XAML!我喜欢XAML声明性

但是从MVVM的角度来看,这种方法有一个缺点——我不能用单元测试来描述这种情况。因此,我宁愿:

  • 创建具有以下属性的视图模型:IsChecked(绑定到复选框), 选择EdItem(绑定到ComboBox)和Source(ComboBox的ItemsSource)- 在没有任何控件参考的情况下对我的真实视图进行抽象
  • 在视图模型中编写一个逻辑,根据需要设置或取消设置SelectedItem 关于被检查的财产
  • 用单元测试覆盖这个逻辑(是的,你可以 如果您喜欢测试优先的方法,甚至可以从这一点开始)

  • WPF是一个功能强大的框架,您只需使用下一种Expander样式即可解决您的问题:

     <Style x:Key="myExpanderStyle" TargetType="{x:Type Expander}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Expander}">
                            <StackPanel>
                                <CheckBox x:Name="PART_CheckBox" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
                                <ComboBox x:Name="PART_ComboBox" ItemsSource="{TemplateBinding Content}" />
                            </StackPanel>
    
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsExpanded" Value="True">
                                    <Setter TargetName="PART_ComboBox" Property="SelectedIndex" Value="0"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    
    
    
    样本:

    <Expander Style="{StaticResource myExpanderStyle}">
                <x:Array Type="sys:String">
                    <sys:String>1</sys:String>
                    <sys:String>2</sys:String>
                    <sys:String>3</sys:String>
                </x:Array>
            </Expander>
    
    
    1.
    2.
    3.
    
    只是XAML!我喜欢XAML声明性

    但是从MVVM的角度来看,这种方法有一个缺点——我不能用单元测试来描述这种情况。因此,我宁愿:

  • 创建具有以下属性的视图模型:IsChecked(绑定到复选框), 选择EdItem(绑定到ComboBox)和Source(ComboBox的ItemsSource)- 在没有任何控件参考的情况下对我的真实视图进行抽象
  • 在视图模型中编写一个逻辑,根据需要设置或取消设置SelectedItem 关于被检查的财产
  • 用单元测试覆盖这个逻辑(是的,你可以 如果您喜欢测试优先的方法,甚至可以从这一点开始)

  • 我遵循@Baboon提供的建议,创建了一个自定义控件,其中包含一个名为CheckedChanged的路由事件,这样我就可以通过视图的xaml和隐藏代码访问它:

     [TemplatePart(Name = "PART_Expander", Type = typeof(Expander))]
    [TemplatePart(Name = "PART_CheckBox", Type = typeof(CheckBox))]
    public class MyCustomExpander : Expander
    {
        static MyCustomExpander()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomExpander), new FrameworkPropertyMetadata(typeof(MyCustomExpander)));
        }
    
        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(MyCustomExpander),
                                         new UIPropertyMetadata(false));
    
        #region Events
    
        private CheckBox chkExpander = new CheckBox();
        public CheckBox ChkExpander { get { return chkExpander; } private set { chkExpander = value; } }
    
        public static readonly RoutedEvent CheckedChangedEvent = EventManager.RegisterRoutedEvent("ExtraButtonClick", 
                                                                                                   RoutingStrategy.Bubble, 
                                                                                                   typeof(RoutedEventHandler),
                                                                                                   typeof(MyCustomExpander));
    
        public event RoutedEventHandler CheckedChanged
        {
            add { AddHandler(CheckedChangedEvent, value); }
            remove { RemoveHandler(CheckedChangedEvent, value); }
        }
    
        void OnCheckedChanged(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(CheckedChangedEvent, this));
        } 
    
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
    
            CheckBox chk = base.GetTemplateChild("PART_CheckBox") as CheckBox;
            if (chk != null)
            {
                chk.Checked += new RoutedEventHandler(OnCheckedChanged);
                chk.Unchecked += new RoutedEventHandler(OnCheckedChanged);
            }
        }
    
        #endregion
    
    }
    

    我要感谢@Baboon和@Vlad的帮助。

    我遵循了@Baboon提供的建议,创建了一个自定义控件,其中包含一个名为CheckedChanged的路由事件,这样我就可以通过视图的xaml和代码来访问它:

     [TemplatePart(Name = "PART_Expander", Type = typeof(Expander))]
    [TemplatePart(Name = "PART_CheckBox", Type = typeof(CheckBox))]
    public class MyCustomExpander : Expander
    {
        static MyCustomExpander()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomExpander), new FrameworkPropertyMetadata(typeof(MyCustomExpander)));
        }
    
        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(MyCustomExpander),
                                         new UIPropertyMetadata(false));
    
        #region Events
    
        private CheckBox chkExpander = new CheckBox();
        public CheckBox ChkExpander { get { return chkExpander; } private set { chkExpander = value; } }
    
        public static readonly RoutedEvent CheckedChangedEvent = EventManager.RegisterRoutedEvent("ExtraButtonClick", 
                                                                                                   RoutingStrategy.Bubble, 
                                                                                                   typeof(RoutedEventHandler),
                                                                                                   typeof(MyCustomExpander));
    
        public event RoutedEventHandler CheckedChanged
        {
            add { AddHandler(CheckedChangedEvent, value); }
            remove { RemoveHandler(CheckedChangedEvent, value); }
        }
    
        void OnCheckedChanged(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(CheckedChangedEvent, this));
        } 
    
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
    
            CheckBox chk = base.GetTemplateChild("PART_CheckBox") as CheckBox;
            if (chk != null)
            {
                chk.Checked += new RoutedEventHandler(OnCheckedChanged);
                chk.Unchecked += new RoutedEventHandler(OnCheckedChanged);
            }
        }
    
        #endregion
    
    }
    

    我要感谢@Baboon和@Vlad的帮助。

    看起来他在使用自定义控件(!=UserControl)好的,这很有意义。我将在谷歌上搜索“自定义控件公开事件”,因为我对自定义控件不太了解……它应该是一个自定义控件,他不是在对功能进行分组,而是在重新部署框架的控件。@Baboon:我的回答是,我不认为重新部署