3

我创建了一个简单的附加属性,可以在屏幕上拖动项目。

1/ 以下是您将如何在您的元素上实现它:

<Rectangle Fill="Green" local:MyExtension.CanMove="True" />

2/ 这就像一个魅力。这样做也是如此:

// in resources
<x:Boolean x:Key="MyCanMove">true</x:Boolean>
<Rectangle Fill="Blue" local:MyExtension.CanMove="{StaticResource MyCanMove}" />

3/ 但是一种语法不起作用。这失败了

<Rectangle Fill="Red" local:MyExtension.CanMove="{Binding Path=CanMove}" />

有什么不同?唯一不同的是,它将值绑定到附加属性中,而不是显式设置或通过静态资源设置。

我错过了一些东西。但它是什么?

这是完整的 XAML:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

    <Grid.DataContext>
        <local:ViewModel/>
    </Grid.DataContext>

    <ToggleSwitch Header="Enable Dragging" 
                  HorizontalAlignment="Center" 
                  IsOn="{Binding CanMove, Mode=TwoWay}">
        <ToggleSwitch.RenderTransform>
            <TranslateTransform Y="-100" />
        </ToggleSwitch.RenderTransform>
    </ToggleSwitch>

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel.Resources>
            <Style TargetType="Rectangle">
                <Setter Property="Height" Value="100" />
                <Setter Property="Width" Value="100" />
            </Style>
            <x:Boolean x:Key="MyCanMove">true</x:Boolean>
        </StackPanel.Resources>
        <Rectangle Fill="Green" local:MyExtension.CanMove="True" />
        <Rectangle Fill="Blue" local:MyExtension.CanMove="{StaticResource MyCanMove}" />
        <Rectangle Fill="Red" local:MyExtension.CanMove="{Binding Path=CanMove}" />
    </StackPanel>

</Grid>

这是完整的代码隐藏:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    bool m_CanMove = true;
    public bool CanMove
    {
        get { return m_CanMove; }
        set
        {
            m_CanMove = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("CanMove"));
        }
    }
}

public class MyExtension
{
    // canmove aproperty
    public static bool GetCanMove(DependencyObject obj)
    {
        return (bool)obj.GetValue(CanMoveProperty);
    }
    public static void SetCanMove(DependencyObject obj, bool value)
    {
        System.Diagnostics.Debug.WriteLine("SetCanMove");
        obj.SetValue(CanMoveProperty, value);

        var rectangle = obj as FrameworkElement;
        rectangle.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
        rectangle.ManipulationDelta -= rectangle_ManipulationDelta;
        if (value)
            rectangle.ManipulationDelta += rectangle_ManipulationDelta;
    }
    public static readonly DependencyProperty CanMoveProperty =
        DependencyProperty.RegisterAttached("CanMove", typeof(bool), typeof(MyExtension), new PropertyMetadata(false));

    // implementation
    static void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
    {
        var rectangle = sender as FrameworkElement;
        var canMove = System.Convert.ToBoolean(rectangle.GetValue(MyExtension.CanMoveProperty));
        if (canMove)
        {
            var transform = rectangle.RenderTransform as CompositeTransform;
            if (transform == null)
                rectangle.RenderTransform = (transform = new CompositeTransform());
            transform.TranslateX += e.Delta.Translation.X;
            transform.TranslateY += e.Delta.Translation.Y;
        }
    }
}

我会提醒您,这个附加属性在前两种语法中运行良好。结果,我无法想象错误出在附加属性中。而且,我在一些论坛上阅读了path=需要绑定到附加属性的内容,因此我将其包括在内(尽管它没有任何区别)。更改模式(OneWay、TwoWay)并没有什么不同。与 ElementName 绑定没有任何区别。我想知道这是否根本没有在 Windows 8.0 WinRT 中启用。其他人可以让它工作吗?

编辑:解决方案

问题是如果没有changed设置事件处理程序,绑定不会引发更改的事件。这是更新后的 MyExtension 代码:

public class MyExtension
{
    // canmove aproperty
    public static bool GetCanMove(DependencyObject obj) { return (bool)obj.GetValue(CanMoveProperty); }
    public static void SetCanMove(DependencyObject obj, bool value) { obj.SetValue(CanMoveProperty, value); }
    public static readonly DependencyProperty CanMoveProperty =
        DependencyProperty.RegisterAttached("CanMove", typeof(bool), typeof(MyExtension), new PropertyMetadata(false, OnCanMoveChanged));

    // respond to change
    private static void OnCanMoveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var rectangle = d as FrameworkElement;
        rectangle.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
        rectangle.ManipulationDelta -= rectangle_ManipulationDelta;
        if ((bool)e.NewValue)
            rectangle.ManipulationDelta += rectangle_ManipulationDelta;
    }

    // implementation
    static void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
    {
        var rectangle = sender as FrameworkElement;
        var canMove = System.Convert.ToBoolean(rectangle.GetValue(MyExtension.CanMoveProperty));
        if (canMove)
        {
            var transform = rectangle.RenderTransform as CompositeTransform;
            if (transform == null)
                rectangle.RenderTransform = (transform = new CompositeTransform());
            transform.TranslateX += e.Delta.Translation.X;
            transform.TranslateY += e.Delta.Translation.Y;
        }
    }
}
4

1 回答 1

4

这只是猜测,因为我面前没有编译器,但我想知道绑定基础结构是否不使用您创建的公开方法 GetCanMove 等。

尝试在 PropertyMetadata 中注册属性更改方法

new PropertyMetadata(false, OnCanMoveChanged)

并在那里有设置和拆卸代码

private void OnCanMoveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
于 2013-08-12T21:10:28.213 回答