最初のユーザーコントロールインスタンスにのみ添付された添付プロパティ

Josh Smithのmvvmワークスペースの例(顧客ビュー)に続いて、私はメインウィンドウとObservableCollection "ChatTabViewModel"を含むメインウィンドウモデルを持っています。

internal class FriendsListViewModel : ObservableObject
{
    #region bound properties
    private ICollectionView viewfriends;
    private ObservableCollection _chatTab; 
    ...
    #endregion
}

私はこのようなxamlでこのコレクションに専用の領域を持っています:


そして、私のリソース辞書で:


    



    
      <button
        Command="{Binding Path=CloseCommand}"
        Content="X"
        Cursor="Hand"
        DockPanel.Dock="Right"
        Focusable="False"
        FontFamily="Courier"
        FontSize="9"
        FontWeight="Bold"
        Margin="0,1,0,0"
        Padding="0"
        VerticalContentAlignment="Bottom"
        Width="16" Height="16"
        />
      
      
    



    

ユーザーイベントでは、私のコレクションに新しいChattabViewModelを追加し、それに関連するビューがメインウィンドウに表示されます。

しかし、ChattabViewのスクロールバーにアタッチされたプロパティを追加しようとすると、このプロパティは最初のChattabViewModelインスタンスにのみアタッチされ、他のタブはアタッチされたプロパティにバインドされません。 ChattabView XAMLは次のとおりです。

 
  
  
    
        
    
      


添付されたプロパティのコード

namespace GtalkOntre.View
{
    /// 
    /// Util class to scroll down when a new message is added.
    /// 
    /// attached property called ScrollOnNewItem that when set to true hooks into the INotifyCollectionChanged events of the itemscontrol items source and upon detecting a new item, scrolls the scrollbar to it.
    public class ItemsControlBehavior
    {
        static Dictionary Associations = new Dictionary();

        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 DependencyProperty ScrollOnNewItemProperty =
            DependencyProperty .RegisterAttached(
                "ScrollOnNewItem",
                typeof(bool),
                typeof(ItemsControlBehavior),
                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 += MyControl_Loaded;
                mycontrol.Unloaded += 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;
            }
        }
    }
}

だから、なぜchattabviewmodelコレクションの最初の "chattabview"が発生したときに、接続プロパティは一度だけバインドされますか?したがって、最初のchattabviewモデルでのみ動作します。 私がそれらをすべて閉じると、接続されたプロパティはchattabviewmodelの最後のインスタンスでアンバインドされ、新しい最初のchattabviewmodelを追加するとプロパティが正しくバインドされます。したがって、mainwindowviewmodelの "chattabviewmodel"コレクションの最初のインスタンスと最後のインスタンスでのみトリガされます。

1週間の検索の後、私は今、少し辛いです...

これまでの私の仮説は、問題は辞書リソースのビューモデルにビューを設定する方法に関連している可能性があります。ビューが共有され、最初のスクロールバーのみが反応する可能性があります。 DataTemplateタグに x:Shared = false 属性を追加しようとしましたが、何も変更されませんでした。

0

2 答え

ChatTabView の異なるインスタンスが作成されていますか?

WPFの TabControl は、新しいテンプレートを作成する代わりに既存のテンプレートを再利用し、単純にその DataContext を置き換えると考えています。

したがって、 ChatTabView のコピーを1つ作成するだけで、 ChatTabView DataContext をコレクションの別のアイテムに置き換えることができます。

2
追加された

TabControl が含まれているとしか思えないので、 ChatTabsTemplate は表示していません。もしそうなら、それはあなたが見ている行動を説明します。 TabControl は、子ビューのタブ項目を遅く読み込むため、現在のビューのみが初期化され、添付プロパティが適用されます。ただし、タブを切り替えると、同じアタッチされたプロパティが呼び出されます。そうじゃないの?

あなたの感情については、そうではありません。 DataTemplate は共有されていますが、 DataTemplate は共有されていないコンテンツの別個のインスタンスを作成するために使用されます。

2
追加された
@アンナ:私はあなたが少し誤解している(または多分私がする)と思います。タブを変更すると、 TabControl はビューをロードし、添付プロパティを実行する必要があります。ビューが遅延ロードされているため、直ちに実行されないことです。必要であれば(なぜなら、添付プロパティが実行されている間はなぜそれが気になるのかまだ分かりません)、 TabControl に遅延ロードではなくすべての子をロードするためのGoogleテクニックを使用できますそれら。
追加された 著者 Kent Boogaart,
はい、私はリソース辞書のChatTabsTemplateを見せました。多分あなたはそれを見逃しました( )tabcontrolのため、それは添付プロパティを一度だけバインドすることを理解しています。しかし、いいえ、接続されたプロパティは最初に開いたタブ(chattabviewmodelのインスタンスにバインドされている)に対してのみ起動し、それ以降のタブは必要な動作をしません。
追加された 著者 KitAndKat,
私はtabcontrolなしで試してみました。新しいビューモデルがコレクションに追加されるたびに、添付されたプロパティがバインドされ、完全に動作します。私はあなたが正しいと思う、それはviewmodelにビューを設定する方法ではなく、tabcontrolが一度だけバインドされた、接続されたプロパティを扱う方法です。だから、私はどのように私のtabcontrol内のすべてのタブで、アタッチされたプロパティの作業をすることになっています:
追加された 著者 KitAndKat,
私は理解しているので、私はより古典的な方法でビューをバインドしようとした:usercontrol.datacontext = viewmodelと私はデバッグモードでどのようにtabcontrol worked.Actuallyタブを変更すると関連するビューをロードし、このビューは、私がtabcontrol +リソースディクショナリでビューを設定する方法を使用すると、添付プロパティは最初のタブパネルでのみ機能します。あなたがタブを切り替えると、他のビューは添付プロパティにバインドされません。タブコントロールを使用して、辞書リソースのビューを設定することには、実際の問題があります。あなたはその組み合わせを試してみるでしょう。
追加された 著者 KitAndKat,
私は問題を発見した。この問題は、このようなteビューとviewmodel(表示されているような辞書リソース)を結び付けるこの方法のtabcontrolにあります。 datatemplateでビューをバインドすると、tabcontrolはビューを1回だけロードします。そのため、ユーザーコントロールは一度だけロードされるため、アタッチされたプロパティは最初のインスタンスにのみバインドされます。私は細かいことが目的であるのか、それともwpfバグのようなものか分かりません。
追加された 著者 KitAndKat,