没有使用Silverlight的ItemsControl Canvas.TopProperty和Canvas.LeftProperty

时间:2010-09-02 16:57:16

标签: silverlight mvvm binding itemscontrol itemspanel

我想创建一个画布,用户可以在其中删除UI元素(表示任务)。然后他可以拖动它们来重新排列它们。元素包含在一个ObservableCollection中,它是DataContext。

我可以设置Canvas的Left和Top属性,但对象位置不受影响。有什么想法吗?

谢谢,

卡雷尔

更新: forgotton ItemsControl后裔(谢谢菲尔):

 public class CustomItemsCollection    : ItemsControl
{
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {            
        FrameworkElement contentitem = element as FrameworkElement;
        // contentitem.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
        // contentitem.VerticalAlignment = System.Windows.VerticalAlignment.Top;
        Binding leftBinding = new Binding("Left"); 
        leftBinding.Mode = BindingMode.TwoWay;

        contentitem.SetBinding(Canvas.LeftProperty, leftBinding);

        Binding topBinding = new Binding("Top");
        topBinding.Mode = BindingMode.TwoWay;
        contentitem.SetBinding(Canvas.TopProperty, topBinding);
        base.PrepareContainerForItemOverride(element, item);
    }
}

更多信息:

从usercontrol派生的绑定对象会引发异常,所以在一些谷歌搜索后我创建了一个valueconverter:

public class UIElementWrapper : IValueConverter
{
    private Dictionary<object, object> CollectionsPool = new Dictionary<object, object>();

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is INotifyCollectionChanged && value is IList)
        {
            ((INotifyCollectionChanged)value).CollectionChanged += UIElementWrapper_CollectionChanged;

            var result = new ObservableCollection<ProxyObject>();
            foreach (var item in (IList)value)
            {
                result.Add(new ProxyObject(item));
            }

            CollectionsPool.Add(result, value);
            return result;
        }
        else
        {
            throw new ArgumentException("value");
        }
    }

    void UIElementWrapper_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (CollectionsPool.ContainsValue(sender))
        {
            foreach (IList result in CollectionsPool.Keys)
            {
                if (CollectionsPool[result] == sender)
                {
                    switch (e.Action)
                    {
                        case NotifyCollectionChangedAction.Add:
                            var index = e.NewStartingIndex;
                            foreach (var item in e.NewItems)
                            {
                                result.Insert(index++, new ProxyObject(item));
                            }
                            break;
                        case NotifyCollectionChangedAction.Remove:
                            foreach (var item in e.OldItems)
                            {
                                var deleteList = new List<ProxyObject>();
                                foreach (ProxyObject p in result)
                                {
                                    if (p.Value == item) deleteList.Add(p);
                                }
                                foreach (var p in deleteList)
                                {
                                    result.Remove(p);
                                }
                            }
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            result[e.OldStartingIndex] = new ProxyObject(e.NewItems[0]);
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            result.Clear();
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

public class ProxyObject
{
    public ProxyObject(object value)
    {
        Value = value;
    }
    public object Value { get; private set; }
}

这很有效。 但是当我绑定ObservableCollection中包含的元素的Left和Top属性时,它们不被使用:所有项目都放在位置0,0

这是背后的代码:

public MainPage()
    {
        InitializeComponent();

        ObservableCollection<Border> items = new ObservableCollection<Border>();
        double left = 0.0;
        double top = 0.0;
        int i = 0;
        Border item = (Border)XamlReader.Load(
           "<Border Background=\"Green\" Height=\"140\" Width=\"180\"  xmlns=\"http://schemas.microsoft.com/client/2007\"></Border>");
        item.Name = string.Format("name {0}", i);
        item.SetValue(Canvas.LeftProperty, left);
        item.SetValue(Canvas.TopProperty, top);
        items.Add(item);

        i++;
        left += 200;
        top += 150;
        item = (Border)XamlReader.Load(
            "<Border Background=\"Yellow\" Margin=\"160, 120, 0, 0\" Height=\"120\" Width=\"160\"  xmlns=\"http://schemas.microsoft.com/client/2007\"></Border>");
        item.Name = string.Format("name {0}", i);
        item.SetValue(Canvas.LeftProperty, left);
        item.SetValue(Canvas.TopProperty, top);
        items.Add(item);

        i++;
        left += 170;
        top += 130;
        item = (Border)XamlReader.Load(
            "<Border Background=\"Red\" Height=\"60\" Width=\"80\"  xmlns=\"http://schemas.microsoft.com/client/2007\"></Border>");
        item.Name = string.Format("name {0}", i);
        item.SetValue(Canvas.LeftProperty, left);
        item.SetValue(Canvas.TopProperty, top);
        items.Add(item);

        left += 90;
        top += 70;
        item = (Border)XamlReader.Load(
            "<Border Background=\"Blue\" Height=\"30\" Width=\"40\"  xmlns=\"http://schemas.microsoft.com/client/2007\"></Border>");
        item.Name = string.Format("name {0}", i);

        item.SetValue(Canvas.LeftProperty, left);
        item.SetValue(Canvas.TopProperty, top);
        items.Add(item);



        try
        {
            // this.customItemsCollection1.ItemsSource = items;
            LayoutRoot.DataContext = items;
        }
        catch (Exception ex)
        {
            textBlock1.Text = ex.Message;
        }
    }

这是xaml:

<UserControl x:Class="ItemsControlTestProject.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:lh="clr-namespace:ItemsControlTestProject.Helpers"
         mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="560" xmlns:my="clr-namespace:ItemsControlTestProject">


<UserControl.Resources>
        <lh:UIElementWrapper x:Key="UIElementWrapper"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="AntiqueWhite">
            <my:CustomItemsCollection Canvas.Left="0" Canvas.Top="0" Background="Coral" x:Name="customItemsCollection1" Margin="0,0,0,0" Width="532" ItemsSource="{Binding Converter={StaticResource UIElementWrapper}}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas   Background="LightGoldenrodYellow" Canvas.Left="0" Canvas.Top="0" Width="350" Height="350"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Value}"  Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
        </my:CustomItemsCollection>
            <TextBlock  Height="61" Name="textBlock1" Text="TextBlock" AllowDrop="True" Width="526" Canvas.Left="6" Canvas.Top="367" Margin="20,388,14,0" />        
    </Grid>
</UserControl>





<UserControl.Resources>
        <lh:UIElementWrapper x:Key="UIElementWrapper"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="AntiqueWhite">
            <my:CustomItemsCollection Canvas.Left="0" Canvas.Top="0" Background="Coral" x:Name="customItemsCollection1" Margin="0,0,0,0" Width="532" ItemsSource="{Binding Converter={StaticResource UIElementWrapper}}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas   Background="LightGoldenrodYellow" Canvas.Left="0" Canvas.Top="0" Width="350" Height="350"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Value}"  Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
        </my:CustomItemsCollection>
            <TextBlock  Height="61" Name="textBlock1" Text="TextBlock" AllowDrop="True" Width="526" Canvas.Left="6" Canvas.Top="367" Margin="20,388,14,0" />        
    </Grid>
</UserControl>

1 个答案:

答案 0 :(得分:2)

问题在于,在绑定之前设置依赖项属性Canvas.Top,方法是将其添加到集合中。在此“添加”之前,您绑定的对象没有属性Canvas.Top

只需更改订单

items.Add(item);
item.SetValue(Canvas.LeftProperty, left);
item.SetValue(Canvas.TopProperty, top);

..它应该有用

/ Nykkel