WPF无视控制事件

时间:2010-03-30 19:38:36

标签: c# wpf xaml

我有以下课程:

public class LooklessControl : Control
{
    public List<int> IntList { get; private set; }
    public int CurrentInt { get; private set; }

    private int _index = 0;

    static LooklessControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LooklessControl), new FrameworkPropertyMetadata(typeof(LooklessControl)));
    }

    public LooklessControl()
    {
        IntList = new List<int>();
        for (int i = 0; i < 10; i++)
        {
            IntList.Add(i);
        }
        CurrentInt = IntList[_index];
    }

    public static readonly RoutedCommand NextItemCommand =
        new RoutedCommand("NextItemCommand", typeof(LooklessControl));

    private void ExecutedNextItemCommand(object sender, ExecutedRoutedEventArgs e)
    {
        NextItemHandler();
    }

    private void CanExecuteNextItemCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    public static readonly RoutedCommand PrevItemCommand =
        new RoutedCommand("PrevItemCommand", typeof(LooklessControl));

    private void ExecutedPrevItemCommand(ExecutedRoutedEventArgs e)
    {
        PrevItemHandler();
    }

    private void CanExecutePrevItemCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }


    public static readonly RoutedEvent NextItemEvent =
        EventManager.RegisterRoutedEvent("NextItemEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(LooklessControl));

    public event RoutedEventHandler NextItem
    {
        add { AddHandler(NextItemEvent, value); }
        remove { RemoveHandler(NextItemEvent, value); }
    }

    private void RaiseNextItemEvent()
    {
        RoutedEventArgs args = new RoutedEventArgs(LooklessControl.NextItemEvent);
        RaiseEvent(args);
    }

    public static readonly RoutedEvent PrevItemEvent =
        EventManager.RegisterRoutedEvent("PrevItemEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(LooklessControl));

    public event RoutedEventHandler PrevItem
    {
        add { AddHandler(PrevItemEvent, value); }
        remove { RemoveHandler(PrevItemEvent, value); }
    }

    private void RaisePrevItemEvent()
    {
        RoutedEventArgs args = new RoutedEventArgs(LooklessControl.PrevItemEvent);
        RaiseEvent(args);
    }

    private void NextItemHandler()
    {
        _index++;
        if (_index == IntList.Count)
        {
            _index = 0;
        }

        CurrentInt = IntList[_index];
        RaiseNextItemEvent();
    }

    private void PrevItemHandler()
    {
        _index--;
        if (_index == 0)
        {
            _index = IntList.Count - 1;
        }

        CurrentInt = IntList[_index];
        RaisePrevItemEvent();
    }
}

该类在Generic.xaml中有一个默认样式,如下所示:

<Style x:Key="{x:Type local:LooklessControl}" TargetType="{x:Type local:LooklessControl}">
    <Setter Property="Height" Value="200"/>
    <Setter Property="Width" Value="90"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:LooklessControl}">
                <Border BorderBrush="Black" BorderThickness="1" Padding="2">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="20"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Rectangle Grid.Row="0" Fill="LightGray"/>
                        <Rectangle Grid.Row="1" Fill="Gainsboro"/>
                        <Grid Grid.Row="0">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="10"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="10"/>
                            </Grid.ColumnDefinitions>
                            <Path Grid.Column="0" x:Name="pathLeftArrow" Data="M0,0.5 L1,1 1,0Z" Width="6" Height="14" Stretch="Fill"
                                  HorizontalAlignment="Center" Fill="SlateBlue"/>
                            <TextBlock Grid.Column="1" Name="textBlock" 
                                   Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CurrentInt}" 
                                   HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Junction" FontSize="13"/>
                            <Path Grid.Column="2" x:Name="pathRightArrow" Data="M0,0 L1,0.5 0,1Z" Width="6" Height="14" Stretch="Fill"
                                  HorizontalAlignment="Center" Fill="SlateBlue"/>
                        </Grid>
                        <ListBox Grid.Row="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Background="Transparent" 
                             ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IntList}"/>
                    </Grid>
                </Border>                    
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如何制作它,以便当用户点击pathLeftArrow时它会触发LooklessControl.PrevItemCommand,或者他们点击pathRightArrow并触发LooklessControl.NextItemCommand,或者他们点击ListBox中的一个项目并通知LooklessControl新选项目?

换句话说,没有将x:Class添加到Generic.xaml的顶部,从而为它创建一个代码隐藏文件,我假设你不想这样做,你如何处理你的元素的事件xaml没有Command属性(除了Button之外的其他所有东西)?

LooklessControl应该拥有它自己的XAML文件(很像你在创建一个新的UserControl时得到的文件)Generic.xaml只是将MergedDictionar作为默认模板引入吗?还是有一些其他公认的方法可以做我想做的事情吗?

1 个答案:

答案 0 :(得分:3)

回答你的上一个问题:不。无视控件不应该需要任何已知的XAML。这就是无望的意思。

这里有几个选项,但我建议使用基本为空的控件模板将元素包装在按钮中:

<ControlTemplate x:Key="contentOnlyButton" TargetType="{x:Type Button}">
    <ContentPresenter />
</ControlTemplate>

...

   <Button Grid.Column="0" Template="{StaticResource contentOnlyButton}"
           Command="{x:Static local:LooklessControl.PrevItemCommand}">
       <Path x:Name="pathLeftArrow" Data="M0,0.5 L1,1 1,0Z" Width="6" Height="14" 
             Stretch="Fill" HorizontalAlignment="Center" Fill="SlateBlue"/>
   </Button>

你的另一个选择(我想说这可能不是你应该对点击执行命令应该做的,但可能适用于其他情况),也就是在OnApplyTemplate中查找模板中的命名部分,然后连线事件发生了。

public override void OnApplyTemplate()
{
    var prevElement = this.GetTemplateChild("PART_PathLeftArrow") as UIElement;
    if (prevElement != null)
        prevElement.MouseDown += (o, e) => PrevItemHandler();
    ...
}

这样做有一点需要注意,模板不需要定义您要查找的部件,因此您需要优雅地检查该情况。在这里投掷NullReferenceExceptions将使重新控制您的控件成为意外删除所需元素的设计人员/开发人员的巨大痛苦。您还需要遵循标准做法,即使用PART_语法命名所需元素,并使用TemplatePart属性对您的类进行装饰。

[TemplatePart(Name = "PART_PathLeftArrow", Type = typeof(UIElement))]
[TemplatePart(Name = "PART_PathRightArrow", Type = typeof(UIElement))]
...
public class LooklessControl : Control

编辑:要让Button响应点击次数,您需要将CommandBindings设置为您已定义的功能。您可以像这样执行类命令绑定:

static LooklessControl()
{
    CommandManager.RegisterClassCommandBinding(
        typeof(LooklessControl),
        new CommandBinding(NextItemCommand, ExecutedNextItemCommand, CanExecuteNextItemCommand));

    CommandManager.RegisterClassCommandBinding(
        typeof(LooklessControl),
        new CommandBinding(PrevItemCommand, ExecutedPrevItemCommand, CanExecutePrevItemCommand));
}

执行类命令绑定的原因是,如果将其添加到控件的CommandBindings集合中,则使用您的控件的人可能会无意中删除它们。还要记住更新命令处理方法以获得静态语义。