Свойство зависимости в пользовательском контроле работает только в первом случае - PullRequest
4 голосов
/ 03 февраля 2012

У меня есть несколько пользовательских элементов управления в окне. Они появляются динамически, как рабочие пространства. Мне нужно добавить свойство зависимости в itemscontrol, чтобы вызвать прокрутку при добавлении элемента в связанную наблюдаемую коллекцию в мой itemscontrol, например, так: (UserControl)

<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 больше не присоединяется к моему scrollviewer. Только первый экземпляр будет работать правильно. Я знаю, что свойства зависимостей являются статическими, но означает ли это, что они не могут работать одновременно на нескольких пользовательских элементах управления одного типа, добавленных в окно?

Обновление 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: shared = false в теге datatemplate, это не сработает. Но если я установлю datacontext классическим способом, например usercontrol.datacontext = new viewmodel (), это определенно сработает. Но рекомендуется иметь «общее» представление, так как нам заставить свойства зависимостей работать с этим «xaml» способом установки datacontext?

1 Ответ

0 голосов
/ 03 февраля 2012

Извините, я не смог воспроизвести вашу проблему.

Я запустил Visual C # 2010 Express, создал новое «Приложение WPF», добавил ваш XAML в UserControl, который я образно назвал UserControl1,и добавил свой ItemsControlBehavior класс.Затем я изменил MainWindow, созданный для меня 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());
    }
}

Я не вносил изменений ни в XAML, ни в ваш UserControl, ни в ваш ItemsControlBehavior класс.

Я обнаружил, что независимо от того, сколько пользовательских элементов управления было добавлено, все их ScrollViewers прокручивались довнизу, когда я нажал кнопку «Добавить сообщение».

Если вы видите только прокрутку вниз на одном из ваших пользовательских элементов управления, то должно быть что-то, что вы неговорит нам.

...