1

以下のようにカスタム コントロールを定義しました。Generic.xaml ファイルには、「cvRoot」という名前のキャンバスを含むテンプレートのみが含まれています。

依存関係プロパティの 1 つが変更されたときに、コントロールを適切に再レンダリングすることができません。アプリケーションで使用すると描画される場合がありますが、測定しようとすると、常にサイズがゼロになります。コントロールを適切に配置するためにサイズを取得する必要があるため、これは非常にイライラします。

オプションを AffectsRender に設定して Dependency Property register メソッドで FrameworkPropertyMetadata を使用しようとしましたが、これは何が起こるかを変えません。また、各プロパティの Callback で InvalidateVisual を試してみましたが、喜びはありませんでした。

私は本当にここで髪を引っ張っています、何かアイデアはありますか?

namespace   GraphControls
{
    public class Marker :   Control
    {
        private Canvas cvRoot   =   null;
        private static Action   EmptyDelegate   =   delegate() { };

        static Marker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Marker), new FrameworkPropertyMetadata(typeof(Marker)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            cvRoot = GetTemplateChild("cvRoot") as Canvas;
        }



        protected   override void   OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);

            cvRoot.Children.Clear();

            // Text
            //
            TextBlock   tb = new TextBlock();
            tb.Text =   Text;
            tb.FontSize =   MarkerFontSize;
            tb.Foreground   =   TextColour;
            tb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // Background   Ellipse
            //
            Ellipse el = new Ellipse();
            el.Width = tb.DesiredSize.Height;
            el.Height   =   tb.DesiredSize.Height;
            el.Fill =   MarkerFill;

            // Add to   Canvas and reposition
            //
            cvRoot.Children.Add(el);
            cvRoot.Children.Add(tb);
            Canvas.SetLeft(tb, (el.Width / 2)   -   (tb.DesiredSize.Width   /   2));
            Canvas.SetTop(tb,   (el.Height / 2) -   (tb.DesiredSize.Height / 2));

            // Resize   the owning Canvas   so that external Measures   work
            //
            cvRoot.Width = el.Width;
            cvRoot.Height   =   el.Height;

        }

        public static   DependencyProperty TextProperty =   DependencyProperty.Register("Text", typeof(string), typeof(Marker),
                                        new PropertyMetadata("X",   new PropertyChangedCallback(OnGenericDependencyPropertyChanged)));
        public static   DependencyProperty MarkerFontSizeProperty   =   DependencyProperty.Register("MarkerFontSize",   typeof(double), typeof(Marker),
                                        new PropertyMetadata(12D,   new PropertyChangedCallback(OnGenericDependencyPropertyChanged)));
        public static   DependencyProperty MarkerFillProperty   =   DependencyProperty.Register("MarkerFill",   typeof(Brush), typeof(Marker),
                                        new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(OnGenericDependencyPropertyChanged)));
        public static   DependencyProperty TextColourProperty   =   DependencyProperty.Register("TextColour",   typeof(Brush), typeof(Marker),
                                        new PropertyMetadata(new SolidColorBrush(Colors.White), new PropertyChangedCallback(OnGenericDependencyPropertyChanged)));

        public string   Text
        {
            get {   return (string)GetValue(TextProperty); }
            set {   SetValue(TextProperty, value); }
        }

        public double   MarkerFontSize
        {
            get {   return (double)GetValue(MarkerFontSizeProperty); }
            set {   SetValue(MarkerFontSizeProperty, value); }
        }

        public Brush MarkerFill
        {
            get {   return (Brush)GetValue(MarkerFillProperty); }
            set {   SetValue(MarkerFillProperty, value); }
        }

        public Brush TextColour
        {
            get {   return (Brush)GetValue(TextColourProperty); }
            set {   SetValue(TextColourProperty, value); }
        }

        private static void OnGenericDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs   e)
        {
            ((Marker)d).Dispatcher.Invoke(DispatcherPriority.Render,    EmptyDelegate);
        }

        protected   override Size   MeasureOverride(Size constraint)
        {
            Size retval =   new Size();

            // Handle   the template not being called   yet
            //
            if (cvRoot !=   null)
            {
                cvRoot.Measure(constraint);
                retval = cvRoot.DesiredSize;
            }

            return retval;

        }

    }
}
4

1 に答える 1

1

コード例から、間違った種類のコントロールを使用して拡張しているようです。MSDNのControl Authoring Overviewページから:

コントロールから派生する利点

次のいずれかに該当する場合は、UserControl クラスを使用する代わりに Control から派生させることを検討してください。

コントロールの外観を ControlTemplate でカスタマイズできるようにしたい。

コントロールでさまざまなテーマをサポートする必要がある。

UserControl から派生する利点

次のすべてに該当する場合は、UserControl からの派生を検討してください。

•アプリケーションの構築方法と同様にコントロールを構築したい。

コントロールは、既存のコンポーネントのみで構成されています。

•複雑なカスタマイズをサポートする必要はありません。

UserControlしたがって、 を使用して XAML で UI 要素を宣言すると、はるかにうまくいくと思います。ただし、を使用することが確実な場合は、すべての UI 要素を XAML の でコントロール用にCustomControl定義する必要があります。それらはすべて自動的にレンダリングされ、手動で更新する必要はありません。ControlTemplategeneric.xaml

また、XAML で単純に実行できることを実行するためにメソッドを実際に使用するべきではありません。OnRenderこれは、WPF の他の UI 要素からまだ使用できないコントロールの新しいグラフィックスを定義するためによく使用されます。DependencyPropertiesUI で制御する任意のプロパティを作成してデータ バインドするだけです。注意すべきことは、RelativeSource Bindingそれらにアクセスするには a を使用する必要があることです ( XAML 名前空間プレフィックスgeneric.xamlを追加したと仮定します)。GraphControls

<Ellipse Fill="{Binding MarkerFill, 
    RelativeSource={RelativeSource AncestorType={x:Type GraphControls:Marker}}}" />
于 2014-02-06T22:27:52.860 に答える