警告: これは長いコメントです。基本的には、@ Rick Sladkeyの応答に対する私の変更を説明しているだけです。それは素晴らしい出発点でしたが、私が見たいくつかのことでいくつかの変更が加えられたことに気付きました.
カスタムコントロールを実行しているときに、これに似たものが必要でした(スクロールのポップアップを閉じたいと思っていました)、答えはRick Sladkeyの答えと非常に似ていることがわかりました。いくつかの小さな変更を加えて、いくつかのアイテムを改善するのに役立ちます.
私が行った変更は、主に 3 つの項目に関するものでした。1つ目は、ScrollViewer_ScrollChanged
アクティブにスクロールしていないときにイベントが発生していることを確認していたことです(他のことが明らかにそれを引き起こしました)。次に、コントロールをアンロードするときにsScrollViewer_ScrollChanged
から切り離されていなかったScrollViewer
ので、3 を追加してから 1 を削除してスクロールすると、2 ではなく 3 回起動します。コントロールの消費者が IsOpen プロパティを動的に設定できるようにする機能。
これで、変更したバージョンのScrollTrigger
クラスは次のようになります。
public class ScrollTrigger : TriggerBase<FrameworkElement>
{
public bool TriggerOnNoChange
{
get
{
var val = GetValue(TriggerOnNoChangeProperty);
if (val is bool b)
{
return b;
}
return false;
}
set => SetValue(TriggerOnNoChangeProperty, value);
}
public static readonly DependencyProperty TriggerOnNoChangeProperty =
DependencyProperty.Register(
"TriggerOnNoChange",
typeof(bool),
typeof(ScrollTrigger),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
protected override void OnAttached()
{
AssociatedObject.Loaded += AssociatedObject_Loaded;
AssociatedObject.Unloaded += AssociatedObject_Unloaded;
}
private void AssociatedObject_Loaded(
object sender,
RoutedEventArgs e)
{
foreach (var scrollViewer in GetScrollViewers())
scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
}
private void AssociatedObject_Unloaded(
object sender,
RoutedEventArgs e)
{
foreach (var scrollViewer in GetScrollViewers())
scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
}
private void ScrollViewer_ScrollChanged(
object sender,
ScrollChangedEventArgs e)
{
if(TriggerOnNoChange ||
Math.Abs(e.VerticalChange) > 0 ||
Math.Abs(e.HorizontalChange) > 0)
InvokeActions(e.OriginalSource);
}
private IEnumerable<ScrollViewer> GetScrollViewers()
{
for (DependencyObject element = AssociatedObject;
element != null;
element = VisualTreeHelper.GetParent(element))
if (element is ScrollViewer viewer) yield return viewer;
}
}
ここでの最初の変更はScrollViewer_ScrollChanged
、オフセット値が実際に変更されたかどうかを確認するロジックを追加したことです。必要に応じてそのロジックをバイパスできるように、トリガーに依存関係プロパティを追加しました。関連付けられたオブジェクトにアンロード イベントを追加した 2 番目の変更。これにより、コントロールが削除された場合に、関連するアクションが に削除され、コントロールを動的に追加および削除するときに呼び出しが行われる ScrollViewers
回数が減ります。ScrollViewer_ScrollChanged
これらの変更と、コントロールのコンシューマーがポップアップの表示方法を指定できるようにしたいという事実を考慮して、.xaml は次のようになりました。
<UserControl ...
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:tgrs="clr-namespace:NameSpace.To.ScrollTrigger.class.Namespace"
x:Name="MyControlNameRoot"
.../>
<i:Interaction.Triggers>
<tgrs:ScrollTrigger TriggerOnNoChange="False">
<i:InvokeCommandAction Command="{Binding ElementName=MyCommandNameRoot, Path=ClosePopupCommand}"/>
</tgrs:ScrollTrigger>
</i:Interaction.Triggers>
...
<Popup ...
IsOpen="{Binding ElementName=MyControlNameRoot, Path=IsPopupOpen, Mode=OneWay}"
.../>
...
</Popup>
...
</UserControl>
バインドするものが必要になりました。カスタム コントロールを作成しているため、コード ビハインドにいくつかの依存関係プロパティとその他の項目を作成しました。MVVM でこのアプローチを使用している場合は、 ' INotifyProperty
' を記述し、バインディングがそれらであることを確認する必要があります (方法によっては、バインディングの ElementName 部分が必要ない場合があります)。これを行うには多くの方法があります。わからない場合は、「mvvm データ バインディング INotifyPropertyChanged」をグーグルで検索すると、簡単に見つけることができます。
ちなみに、私も Prism を使っているのでDelegateCommand
s を使っていますが、好きな実装を使って構いICommand
ません。これで、コード ビハインドは次のようになりました。
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
ClosePopupCommand = new DelegateCommand(OnPopupCommand);
InitializeComponent();
}
...
public ICommand ClosePopupCommand { get; }
private OnClosePopupCommand ()
{
IsPopupOpen = false;
}
public static readonly DependencyProperty IsPopupOpenProperty =
DependencyProperty.Register(
"IsPopupOpen",
typeof(bool),
typeof(MyUserControl),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public bool IsPopupOpen
{
get
{
var val = GetValue(IsPopupOpenProperty);
if (val is bool b)
{
return b;
}
return false;
}
set => SetValue(IsPopupOpenProperty, value);
}
...
}
これにより、実際に変更があり、不要な呼び出しがなく、開いているかどうかをユーザーが変更できるようにするスクロールトリガーで閉じるポップアップを作成できます。
ここまでできたら、よろしくお願いします。ご尽力に感謝いたします。これが少しでもお役に立てば幸いです。