私の目標は、FlowDocumentScrollViewerの再利用可能な添付動作を作成して、FlowDocumentが更新(追加)されるたびにビューアが自動的に最後までスクロールするようにすることです。
これまでの問題:
- OnEnabledChangedは、ビジュアルツリーが完了する前に呼び出されるため、ScrollViewerが見つかりません。
- FlowDocumentを含むDependencyPropertyにアタッチする方法がわかりません。私の計画は、そのchangedイベントを使用してManagedRangeプロパティを初期化することでした。(必要に応じて、初めて手動でトリガーされます。)
- DependencyObjectがないため、range_Changedメソッド内からScrollViewerプロパティにアクセスする方法がわかりません。
私はそれらが潜在的に3つの別々の問題(別名質問)であることを理解しています。ただし、それらは相互に依存しており、この動作のために私が試みた全体的な設計です。私がこれを間違った方法で行っている場合に備えて、私はこれを単一の質問として尋ねています。私がそうなら、正しい方法は何ですか?
/// Attached Dependency Properties not shown here:
/// bool Enabled
/// DependencyProperty DocumentProperty
/// TextRange MonitoredRange
/// ScrollViewer ScrollViewer
public static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d == null || System.ComponentModel.DesignerProperties.GetIsInDesignMode(d))
return;
DependencyProperty documentProperty = null;
ScrollViewer scrollViewer = null;
if (e.NewValue is bool && (bool)e.NewValue)
{
// Using reflection so that this will work with similar types.
FieldInfo documentFieldInfo = d.GetType().GetFields().FirstOrDefault((m) => m.Name == "DocumentProperty");
documentProperty = documentFieldInfo.GetValue(d) as DependencyProperty;
// doesn't work. the visual tree hasn't been built yet
scrollViewer = FindScrollViewer(d);
}
if (documentProperty != d.GetValue(DocumentPropertyProperty) as DependencyProperty)
d.SetValue(DocumentPropertyProperty, documentProperty);
if (scrollViewer != d.GetValue(ScrollViewerProperty) as ScrollViewer)
d.SetValue(ScrollViewerProperty, scrollViewer);
}
private static ScrollViewer FindScrollViewer(DependencyObject obj)
{
do
{
if (VisualTreeHelper.GetChildrenCount(obj) > 0)
obj = VisualTreeHelper.GetChild(obj as Visual, 0);
else
return null;
}
while (!(obj is ScrollViewer));
return obj as ScrollViewer;
}
public static void OnDocumentPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue != null)
{
DependencyProperty dp = e.OldValue as DependencyProperty;
// -= OnFlowDocumentChanged
}
if (e.NewValue != null)
{
DependencyProperty dp = e.NewValue as DependencyProperty;
// += OnFlowDocumentChanged
// dp.AddOwner(typeof(AutoScrollBehavior), new PropertyMetadata(OnFlowDocumentChanged));
// System.ArgumentException was unhandled by user code Message='AutoScrollBehavior'
// type must derive from DependencyObject.
}
}
public static void OnFlowDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextRange range = null;
if (e.NewValue != null)
{
FlowDocument doc = e.NewValue as FlowDocument;
if (doc != null)
range = new TextRange(doc.ContentStart, doc.ContentEnd);
}
if (range != d.GetValue(MonitoredRangeProperty) as TextRange)
d.SetValue(MonitoredRangeProperty, range);
}
public static void OnMonitoredRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue != null)
{
TextRange range = e.OldValue as TextRange;
if (range != null)
range.Changed -= new EventHandler(range_Changed);
}
if (e.NewValue != null)
{
TextRange range = e.NewValue as TextRange;
if (range != null)
range.Changed -= new EventHandler(range_Changed);
}
}
static void range_Changed(object sender, EventArgs e)
{
// need ScrollViewer!!
}