13

XAML と MVVM を使用する C# WPF アプリケーションがあります。私の質問は次のとおりです。ユーザーが入力した無効なデータに対して、テキスト ボックスの上にバルーン ツールチップを表示するにはどうすればよいですか?

これには Microsoft のネイティブ バルーン コントロールを使用したいと考えています。これをアプリケーションにどのように実装しますか?

4

4 に答える 4

12

System.Windows.FormsC:\ Program Files \ Reference Assemblies \ Microsoft \ Framework.NETFramework \ v4.0 \ WindowsFormsIntegration.dllへの参照を追加してから、次の手順を実行 します。

    WindowsFormsHost host =new WindowsFormsHost();

    var toolTip1 = new System.Windows.Forms.ToolTip();

    toolTip1.AutoPopDelay = 5000;
    toolTip1.InitialDelay = 1000;
    toolTip1.ReshowDelay = 500;
    toolTip1.ShowAlways = true;
    toolTip1.IsBalloon = true;
    toolTip1.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
    toolTip1.ToolTipTitle = "Title:";

    System.Windows.Forms.TextBox tb = new System.Windows.Forms.TextBox();
    tb.Text="Go!";
    toolTip1.SetToolTip(tb, "My Info!");
    host.Child = tb;
    grid1.Children.Add(host);  //a container for windowsForm textBox 

これは、 WPFのWinFormToolTipBallonのサンプルです。

ここに画像の説明を入力してください

この助けを願っています!

于 2011-09-28T09:28:41.760 に答える
3

この BalloonDecorator プロジェクト は、ヘルプ ヒントとエラー通知を表示するために現在のプロジェクトで使用しているものです。赤い境界線の代わりにアイコンを表示できるように、エラー テンプレートを変更してこのデコレータを表示できることは知っています。デコレータを使用する利点は、見た目を自由に変更できることと、WinForms に依存する必要がないことです。

BalloonDecorator.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyNamespace
{
public class BalloonDecorator : Decorator
{
    private static double _thickness = 0;
    private static int OpeningGap = 10;

    public static readonly DependencyProperty BackgroundProperty =
        DependencyProperty.Register("Background", typeof (Brush), typeof (BalloonDecorator));

    public static readonly DependencyProperty BorderBrushProperty =
        DependencyProperty.Register("BorderBrush", typeof (Brush), typeof (BalloonDecorator));

    public static readonly DependencyProperty PointerLengthProperty = 
        DependencyProperty.Register("PointerLength", typeof (double), typeof (BalloonDecorator),
        new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender |
        FrameworkPropertyMetadataOptions.AffectsMeasure));

    public static readonly DependencyProperty CornerRadiusProperty = 
        DependencyProperty.Register("CornerRadius", typeof (double), typeof (BalloonDecorator),
        new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender |
        FrameworkPropertyMetadataOptions.AffectsMeasure));

    public Brush Background
    {
        get { return (Brush) GetValue(BackgroundProperty); }
        set { SetValue(BackgroundProperty, value); }
    }

    public Brush BorderBrush
    {
        get { return (Brush) GetValue(BorderBrushProperty); }
        set { SetValue(BorderBrushProperty, value); }
    }

    public double PointerLength
    {
        get { return (double) GetValue(PointerLengthProperty); }
        set { SetValue(PointerLengthProperty, value); }
    }

    public double CornerRadius
    {
        get { return (double) GetValue(CornerRadiusProperty); }
        set { SetValue(CornerRadiusProperty, value); }
    }

    protected override Size ArrangeOverride(Size arrangeSize)
    {
        UIElement child = Child;
        if (child != null)
        {
            double pLength = PointerLength;
            Rect innerRect =
                Rect.Inflate(new Rect(pLength, 0, Math.Max(0, arrangeSize.Width - pLength), arrangeSize.Height),
                             -1 * _thickness, -1 * _thickness);
            child.Arrange(innerRect);
        }

        return arrangeSize;
    }

    protected override Size MeasureOverride(Size constraint)
    {
        UIElement child = Child;
        Size size = new Size();
        if (child != null)
        {
            Size innerSize = new Size(Math.Max(0, constraint.Width - PointerLength), constraint.Height);
            child.Measure(innerSize);
            size.Width += child.DesiredSize.Width;
            size.Height += child.DesiredSize.Height;
        }

        Size borderSize = new Size(2 * _thickness, 2 * _thickness);
        size.Width += borderSize.Width + PointerLength;
        size.Height += borderSize.Height;

        return size;
    }

    protected override void OnRender(DrawingContext dc)
    {
        Rect rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);

        dc.PushClip(new RectangleGeometry(rect));
        dc.DrawGeometry(Background, new Pen(BorderBrush, _thickness), CreateBalloonGeometry(rect));
        dc.Pop();
    }

    private StreamGeometry CreateBalloonGeometry(Rect rect)
    {
        double radius = Math.Min(CornerRadius, rect.Height / 2);
        double pointerLength = PointerLength;

        // All the points on the path
        Point[] points =
            {
                new Point(pointerLength + radius, 0), new Point(rect.Width - radius, 0), // Top
                new Point(rect.Width, radius), new Point(rect.Width, rect.Height - radius), // Right
                new Point(rect.Width - radius, rect.Height), // Bottom
                new Point(pointerLength + radius, rect.Height), // Bottom
                new Point(pointerLength, rect.Height - radius), // Left
                new Point(pointerLength, radius) // Left
            };

        StreamGeometry geometry = new StreamGeometry();
        geometry.FillRule = FillRule.Nonzero;
        using (StreamGeometryContext ctx = geometry.Open())
        {
            ctx.BeginFigure(points[0], true, true);
            ctx.LineTo(points[1], true, false);
            ctx.ArcTo(points[2], new Size(radius, radius), 0, false, SweepDirection.Clockwise, true, false);
            ctx.LineTo(points[3], true, false);
            ctx.ArcTo(points[4], new Size(radius, radius), 0, false, SweepDirection.Clockwise, true, false);
            ctx.LineTo(points[5], true, false);

            ctx.ArcTo(points[6], new Size(radius, radius), 0, false, SweepDirection.Clockwise, true, false);

            // Pointer
            if (pointerLength > 0)
            {
                ctx.LineTo(rect.BottomLeft, true, false);
                ctx.LineTo(new Point(pointerLength, rect.Height - radius - OpeningGap), true, false);
            }
            ctx.LineTo(points[7], true, false);

            ctx.ArcTo(points[0], new Size(radius, radius), 0, false, SweepDirection.Clockwise, true, false);
        }
        return geometry;
    }
}
}

このクラスの名前空間が XAML インポートに読み込まれていることを確認してください (私は "Framework" という名前の名前空間を使用しています)。これは簡単に使用できます。

    <Framework:BalloonDecorator  Background="#FFFF6600" PointerLength="50"
     CornerRadius="5" Opacity=".9" Margin="200,120,0,0"
     HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="{Binding UnitPriceChangedBalloonVisibility}">
        <Border CornerRadius="2">
            <Border CornerRadius="2">
                <Button Height="Auto" Command="{Binding CloseUnitPriceChangedBalloonCommand}" Background="Transparent" BorderBrush="{x:Null}">
                <TextBlock Text="Please review the price. The Units have changed."
                     HorizontalAlignment="Left"
                     VerticalAlignment="Top"
                     FontStyle="Italic"
                     TextWrapping="Wrap"
                     Margin="10"
                     />
                     </Button>
            </Border>
        </Border>
    </Framework:BalloonDecorator>

明らかに、可視性をバインディングに関連付けますが、それを true に設定して、これを Validation.ErrorTemplate 内に配置することもできます。

お役に立てれば!

于 2011-09-29T20:52:22.353 に答える
2

BalloonDecorator よりも優れたソリューションを探していたところ、http://www.hardcodet.net/projects/wpf-notifyicon プロジェクトに出くわしまし。最下位レベルで WinAPI を使用しているため、独自のソリューションを構築する上で有利なスタートを切ることができます。一見すると解決する可能性があるように見えますが、BalloonTip をあなたが説明したように動作させることができるかどうかを確認するのに十分な時間がありませんでした。

あなたのプロジェクトで頑張ってください!

于 2011-10-04T14:36:19.513 に答える
1

おそらく、 WindowsFormsHost型を使用して、WPF で Windows フォーム コントロールをホストできます。

これを行う方法については、MSDN で利用可能なウォークスルーがあります。

WPF で Windows フォーム複合コントロールをホストする

この手法を使用すると、おそらくSystem.Windows.Forms.ToolTipコントロールを使用できます。このコントロールのIsBalloon プロパティを true に設定すると、バルーン ウィンドウとして表示されます。

于 2011-09-24T21:05:14.307 に答える