2012-02-02 68 views
4

我在窗口中有幾個自定義用戶控件。它們動態顯示,如工作區。 我需要在一個ItemsControl添加一個依賴屬性觸發,當一個項目被添加到綁定的觀察集合到我的ItemsControl,像這樣一個下滾: (用戶控件)用戶控件中的依賴屬性僅適用於第一個實例

<ScrollViewer VerticalScrollBarVisibility="Auto" > 
<ItemsControl Grid.Row="0" ItemsSource="{Binding Messages}" View:ItemsControlBehavior.ScrollOnNewItem="True">  
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <TextBox IsReadOnly="True" TextWrapping="Wrap" Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}" /> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate>  
</ItemsControl> 
</ScrollViewer> 

和我相依的代碼物業:

public class ItemsControlBehavior 
    { 
     static readonly Dictionary<ItemsControl, Capture> Associations = 
      new Dictionary<ItemsControl, Capture>(); 

    public static bool GetScrollOnNewItem(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(ScrollOnNewItemProperty); 
    } 

    public static void SetScrollOnNewItem(DependencyObject obj, bool value) 
    { 
     obj.SetValue(ScrollOnNewItemProperty, value); 
    } 

    public static readonly DependencyProperty ScrollOnNewItemProperty = 
     DependencyProperty.RegisterAttached(
      "ScrollOnNewItem", 
      typeof(bool), 
      typeof(ItemsControl), 
      new UIPropertyMetadata(false, OnScrollOnNewItemChanged)); 

    public static void OnScrollOnNewItemChanged(
     DependencyObject d, 
     DependencyPropertyChangedEventArgs e) 
    { 
     var mycontrol = d as ItemsControl; 
     if (mycontrol == null) return; 
     bool newValue = (bool)e.NewValue; 
     if (newValue) 
     { 
      mycontrol.Loaded += new RoutedEventHandler(MyControl_Loaded); 
      mycontrol.Unloaded += new RoutedEventHandler(MyControl_Unloaded); 
     } 
     else 
     { 
      mycontrol.Loaded -= MyControl_Loaded; 
      mycontrol.Unloaded -= MyControl_Unloaded; 
      if (Associations.ContainsKey(mycontrol)) 
       Associations[mycontrol].Dispose(); 
     } 
    } 

    static void MyControl_Unloaded(object sender, RoutedEventArgs e) 
    { 
     var mycontrol = (ItemsControl)sender; 
     Associations[mycontrol].Dispose(); 
     mycontrol.Unloaded -= MyControl_Unloaded; 
    } 

    static void MyControl_Loaded(object sender, RoutedEventArgs e) 
    { 
     var mycontrol = (ItemsControl)sender; 
     var incc = mycontrol.Items as INotifyCollectionChanged; 
     if (incc == null) return; 
     mycontrol.Loaded -= MyControl_Loaded; 
     Associations[mycontrol] = new Capture(mycontrol); 
    } 

    class Capture : IDisposable 
    { 
     public ItemsControl mycontrol{ get; set; } 
     public INotifyCollectionChanged incc { get; set; } 

     public Capture(ItemsControl mycontrol) 
     { 
      this.mycontrol = mycontrol; 
      incc = mycontrol.ItemsSource as INotifyCollectionChanged; 
      incc.CollectionChanged +=incc_CollectionChanged; 
     } 

     void incc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      if (e.Action == NotifyCollectionChangedAction.Add) 
      { 
        ScrollViewer sv = mycontrol.Parent as ScrollViewer; 
       sv.ScrollToBottom(); 
      } 
     } 

     public void Dispose() 
     { 
      incc.CollectionChanged -= incc_CollectionChanged; 
     } 
    } 
} 

在我的用戶控件的第一個實例化,它像一個魅力。 但是,當同一類型的另一個用戶控件被動態實例化時,DependencyProperty不再附加到我的滾動查看器中。只有第一個實例才能正常工作。 我知道依賴項屬性是靜態的,但這是否意味着它們不能同時添加到窗口中的同一類型的多個用戶控件上?

更新02/03:以下是我的視圖模型設置爲視圖(未編程):

 <ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:vm="clr-namespace:testDp.ViewModel" 
    xmlns:View="clr-namespace:testDp.View"> 


    <DataTemplate DataType="{x:Type vm:ChatTabViewModel}"> 
<View:ChatTabView /> 
    </DataTemplate>   
    </ResourceDictionary> 

即使X:在DataTemplate中標記共享= false時,將無法正常工作。 但是,如果我以像usercontrol.datacontext = new viewmodel()這樣的經典方式設置datacontext,它肯定有效。但建議有一個「共享」視圖,那麼我們如何使用這種「xaml」設置datacontext的方式來使依賴項屬性工作?

+0

您在DependencyProperty創建中的第二個typeof應該是所有者類的類型,但是您提供了ItemsControl,將其更改爲ItemsControlBehavior。但我不認爲這是造成你的問題。 – dowhilefor 2012-02-02 22:05:52

+0

我的不好...謝謝。不幸的是,問題仍然存在...... – KitAndKat 2012-02-02 22:11:01

+0

我可以看到兩個靜態函數充當get/set。爲什麼不按照約定使用屬性包裝器來處理dependencyproperty? – Jimmy 2012-02-03 10:33:26

回答

0

對不起,我無法重現您的問題。

我開始的Visual C#2010 Express中,創造了一個新的「WPF應用程序」,添加您的XAML到UserControl我想象力題爲UserControl1,並添加您的ItemsControlBehavior類。然後我修改了VC#我創建的主窗口如下:

MainWindow.xaml(<Window>元素的唯一內容):

<StackPanel Orientation="Vertical"> 
    <Button Content="Add user control" Click="ButtonAddUserControl_Click" /> 
    <Button Content="Add message" Click="ButtonAddMessage_Click" /> 
    <StackPanel Orientation="Horizontal" x:Name="sp" Height="300" /> 
</StackPanel> 

MainWindow.xaml.cs:

public partial class MainWindow : Window 
{ 
    public ObservableCollection<string> Messages { get; private set; } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     Messages = new ObservableCollection<string>() { "1", "2", "3", "4" }; 
     DataContext = this; 
    } 

    private void ButtonAddUserControl_Click(object sender, RoutedEventArgs e) 
    { 
     sp.Children.Add(new UserControl1()); 
    } 

    private void ButtonAddMessage_Click(object sender, RoutedEventArgs e) 
    { 
     Messages.Add((Messages.Count + 1).ToString()); 
    } 
} 

我對您的UserControl中的XAML以及您的ItemsControlBehavior類都不做任何修改。

我發現無論添加多少用戶控件,當我點擊'添加消息'按鈕時,他們的ScrollViewer都滾動到底部。

如果您只在一個用戶控件上看到滾動到底部的行爲,那麼肯定有一些您沒有告訴我們的東西。

+0

謝謝你的嘗試! 我會像你這樣一個非常簡單的測試項目做同樣的事情,看看,如果事情有效,我的項目有什麼不同,我會保持這篇文章的更新。 tks – KitAndKat 2012-02-03 09:23:47

+0

好吧,它的工作原理就是這樣。我不知道它是否與它有關,但在我的真實項目中,我沒有以編程方式設置View.DataContext = ViewModel,但我把它放在資源字典中,就像這樣:也許它只爲多個viewmodel創建一個視圖?僅在強制時分隔實例? – KitAndKat 2012-02-03 10:04:11

+0

@Anna是的,如果你用xaml創建它,它將被創建一次並被重用。有一個標誌可以用來在資源上使用x:Shared =「false」不共享它。 – dowhilefor 2012-02-03 15:12:22