我想创建一个画布,用户可以在其中删除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>
答案 0 :(得分:2)
问题在于,在绑定之前设置依赖项属性Canvas.Top,方法是将其添加到集合中。在此“添加”之前,您绑定的对象没有属性Canvas.Top
只需更改订单
items.Add(item);
item.SetValue(Canvas.LeftProperty, left);
item.SetValue(Canvas.TopProperty, top);
..它应该有用
/ Nykkel