質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

  • C#

    7714questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • XAML

    262questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

C# XAML triggerの挙動やzindexなどにその他いろいろについて

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,451

hartman

score 5

BreadCrumb.xaml.csには
public bool trigger;
public int zindex;
がいるだけです

BreadCrumb.xaml
<Grid  VerticalAlignment="Center" Panel.ZIndex="{Binding zindex}">
        <TextBlock x:Name="txt" VerticalAlignment="Center" Height="60" TextWrapping="Wrap" FontSize="20"> 
            <TextBlock.Background> 
                <VisualBrush>
                    <VisualBrush.Visual>
                        <Polygon x:Name="polygon"  Fill="AliceBlue" Points="0,60 0,0 65,00 80,30 65,60" Stroke="#000000" />
                    </VisualBrush.Visual>
                </VisualBrush>
            </TextBlock.Background>
             <TextBlock.Resources>
                <Style x:Key="style" TargetType="Polygon">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding trigger}" Value="true">
                            <Setter Property="Fill" Value="aqua"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding trigger}" Value="false">
                            <Setter Property="Fill" Value="LightCyan"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBlock.Resources>
        </TextBlock>
    </Grid>
Control.xaml.cs
 List<string> str = new List<string> { "あいうえお", "かきくけこ", "あああああ", "あいうえお", "かきくけこ",.............};

            double width = this.Width / str.Count;
            bool firstFlg = false;
            this.trigger = true;
            int zindex = str.Count;
            double mleft = width / 10;
            int i = str.Count-1;
            foreach(string msg in str){
                if (!firstFlg) {
                    BreadCrumbItems.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
                    BreadCrumbControl breadControl = new BreadCrumbControl();
                    breadControl.txb.Width = width;
                    breadControl.txb.Margin = new System.Windows.Thickness(0, 10, 0, 10);
                    breadControl.txb.Text = msg ;
                    breadControl.zindex = zindex;
                    breadControl.trigger = this.trigger;
                    breadControl.DataContext = breadControl;
                    breadControl.SetValue(Grid.RowProperty, 0); 
                    breadControl.SetValue(Grid.ColumnProperty, i);
                    BreadCrumbItems.Children.Add(breadControl);
                    firstFlg = true;
                } else {
                    BreadCrumbItems.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
                    BreadCrumbControl breadControl = new BreadCrumbControl();
                    breadControl.txb.Width = width + (mleft * 2.5);
                    breadControl.txb.Margin = new System.Windows.Thickness(0, 10, -(mleft * 2.5), 10);
                    breadControl.txb.Text = msg ;
                    breadControl.zindex = zindex;
                    breadControl.trigger = this.trigger;
                    breadControl.DataContext = breadControl;
                    breadControl.SetValue(Grid.RowProperty, 0);
                    breadControl.SetValue(Grid.ColumnProperty, i);
                    BreadCrumbItems.Children.Add(breadControl);
                }
                zindex--;
                i--;
            }
                firstFlg = false;
        }

Control.xaml
<Grid Name="BreadCrumbItems" HorizontalAlignment="Stretch" VerticalAlignment="Center" ShowGridLines="True" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
</Grid>

やりたいことは画面の横幅いっぱいに図形を均等に並べて
そこにメッセージを載せてパンくずのようにしたいです。

メッセージリストは可変です。

分からないところ・つまっている箇所は

上記で一応横いっぱいに並べることはできているのですが、一番右の図形が少し小さくなってしまいます。
polygonで描写している図形を使い、頭がとんがっている部分だけを右に置かれた図形乗っけたいです。

本当は左から詰めたいのですがBreadCrumb.xamlで指定しているzindexが効かない。本当にここで使えるものかどうかがわからないです。。。
なので右から詰めています。bindingはちゃんと値を見れています。

<TextBlock.Resources>内の<DataTrigger Binding="{Binding trigger}" Value="true">も
bindingの値は見れていますが背景の色が変わらないです。
他に背景に図形を指定する方法、またはtriggerを動かすにはどうしたらいいでしょうか?

TextBlock内の文字が縦方向の真ん中に移動してくれません。
VerticalAlignment="Center"はTextBlockだ効かないのでしょうか?

図形をかぶせるために少し伸ばしてその分をmarginに指定して図形をずらしていますが
ouble mleft = width / 10;
breadControl.txb.Width = width + (mleft * 2.5);
breadControl.txb.Margin = new System.Windows.Thickness(0, 10, -(mleft * 2.5), 10);
のmleftですが [10]とか[2.5]適当に数字を指定しています。

この数字を左側の図形のとんがった部分と右の図形が重なった部分の幅にしたいです。

以上です。

特に解決したいのはメッセージの縦方向のセンター寄せとtriggerの部分です。

追記
回答ありがとうございます。

コード見にくくて申し訳ございません。

細かく教えていただきありがとうございます。

コードがスッキリしていて自分の汚いコードが恥ずかしいです。。。

図形を切り分けるという発想はありませんでした。
とういのも実は背景は固定の色で図形の枠の色を変えたかったというのがあり、

  /こういうこと?
    //動的に変えたいならBindingにするか、triggerの値を変えるたびに手動で更新する
    breadControl.Fill = this.trigger ? Brushes.Aqua : Brushes.LightCyan;


の部分ですが図形の枠の色を変えるために

if (this.trigger) {
 breadControl.Style = TryFindResource("PolygonAStyle") as Style;
} else {
 breadControl.Style = TryFindResource("PolygonBStyle") as Style;
}

リソース↓  *Bは枠の色を変えたもの
<Style x:Key="PolygonAStyle" TargetType="{x:Type Polygon}">
 <Setter Property="Fill" Value=" #FCC404"/>
 <Setter Property="Stroke" Value="#FF0000"/>
</Style>


のようにして枠の色を変えたかったのです。

これを適用してしまうと枠の色が上書きされて三角の左の縦線部分が下図のようにでてきしまうと思うのですが
枠線の色を出しつつ縦線を出さずに”>”の部分だけ線を引くことは可能でしょうか?
イメージ説明

下図のようなイメージです。
![イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

ご提示のコードはちょっとよくわからない部分が多かったです。
(BreadCrumbControlというのがBreadCrumb.xaml.csとBreadCrumb.xamlのクラス名?
breadControl.txbと書いてあるのは、txtの間違い?
Control.xaml.csの3行目以降の処理はどこに書かれているもの?this.triggerって何?)

とりあえず理解できた(気がする)範囲でお答えします。


  • VerticalAlignment="Center"は、そのコントロール自体(この場合はTextBlock自体)の配置を指定するものです。
    コントロール内の文字の配置を中央にしたい場合は、
    ・Paddingで調整する
    ・TextBlockをLabelに変えてVerticalContentAlignment="Center"を指定する
    ・TextBlockの外側にもうひとつLabelかBorderを置いて、Polygonをそっちに描画し、中のTextBlockにVerticalAlignment="Center"を指定する
    といった方法が考えられます。

  • 「bindingはちゃんと値を見れています」というのが、どこを見て確認した話なのかわかりませんが、とりあえず、
    これだけごりごりコードで書いている感じならば、特にBindingにこだわる必要がないのでは?と思います。
    ・zindexは breadControl.SetValue(Panel.ZIndexProperty, zindex); のようにして外から指定できます
    ・背景色についても(ぜひ習得しておきたいということでなければ)StyleのTriggerを使うことにこだわらず、 polygon.Fill = Brushes.Aqua; とやるのが早いかもしれません

  • ちなみに、現状のBindingが動かない理由については、
    ・zindexがBreadCrumb自体でなく、その中のGridに指定されている
    ・背景色を定めたStyle( x:Key="style" )がpolygonに適用されていない
    ・zindexとtriggerがただのフィールドなので、まずプロパティに変更し、さらに必要ならばINotifyPropertyChagnedを実装する
    といったあたりに問題がありそうです(説明は省略します)


  • marginの話ですが、そもそもbreadControlの横幅が変更されるときに
    とんがり部分の幅も広くなったり狭くなったりするのは意図した仕様なんでしょうか?
    とんがり部分の幅は常に固定(15?)で、それ以外の部分だけ幅が変わるようにすれば
    marginもめんどくさい計算をせず固定でよいのではないかと思いました。

  • 各ブロックの幅を頑張って計算されていますが、
    配置するGridのColumnDefinitionでWidth="*"(GridUnitType.Star)にすると
    指定した割合で領域を均等に割ってくれるので、
    自分でやるとしたらそうするだろうなあと思いました。


以上をふまえ簡単に書き直してみました。
#最初はできるだけもともとのコードを変えないようにしようかと思いましたが、
#いろいろ気になって、つい書き直しちゃいました…。

BreadCrumb.xaml

<UserControl x:Class="TeraTail65279.BreadCrumb"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="60">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <!--とんがり部の幅は固定(好きな値に調整してください)-->
            <ColumnDefinition Width="15" />
        </Grid.ColumnDefinitions>

        <!--とんがり部以外の境界線はBorderで-->
        <Border BorderBrush="#000000" BorderThickness="1,1,0,1" 
                Background="{Binding ElementName=poly, Path=Fill, Mode=OneWay}" />

        <!--とんがり部の三角形-->
        <Polygon x:Name="poly" Fill="AliceBlue" Grid.Column="1" Points="0,0 15,30 0,60" />
        <!--左の縦線を入れたくないので、境界線だけPolylineで-->
        <Polyline Stroke="#000000" Grid.Column="1" Points="{Binding ElementName=poly, Path=Points, Mode=OneWay}" />

        <!--TextBlockがPolygon図形と別コントロールになったのでVerticalAlignmentで中央に配置できる-->
        <TextBlock x:Name="txt" FontSize="20" VerticalAlignment="Center" />

    </Grid>
</UserControl>

BreadCrumb.xaml.cs

public partial class BreadCrumb : UserControl
{
    public BreadCrumb()
    {
        InitializeComponent();
    }

    //子要素のTextBlockやPolygonを外から直接いじらせたくないので
    //プロパティをラップして公開する

    public string Text
    {
        get
        {
            return txt.Text;
        }
        set
        {
            txt.Text = value;
        }
    }

    public Brush Fill
    {
        get
        {
            return poly.Fill;
        }
        set
        {
            poly.Fill = value;
        }
    }

    public double TextLeftMargin
    {
        get
        {
            return txt.Margin.Left;
        }
        set
        {
            txt.Margin = new Thickness(value, txt.Margin.Top, txt.Margin.Right, txt.Margin.Bottom);
        }
    }
}

Control.xaml, Control.xaml.csと書かれてたもの

<Grid Name="BreadCrumbItems" >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
</Grid>
bool isFirst = true;
int zindex = str.Count;

//左から追加していく
int i = 0;
foreach (string msg in str)
{
    //Columnの幅をGridUnitType.Starにするのがポイント
    BreadCrumbItems.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });

    var breadControl = new BreadCrumb();
    breadControl.Text = msg;
    breadControl.SetValue(Panel.ZIndexProperty, zindex);
    breadControl.SetValue(Grid.RowProperty, 0);
    breadControl.SetValue(Grid.ColumnProperty, i);
    BreadCrumbItems.Children.Add(breadControl);

    //こういうこと?
    //動的に変えたいならBindingにするか、triggerの値を変えるたびに手動で更新する
    breadControl.Fill = this.trigger ? Brushes.Aqua : Brushes.LightCyan;

    //最初かどうかで処理を変えるのは↓だけ
    if (isFirst)
    {
        isFirst = false;
    }
    else
    {
        //↓の処理をまとめてBreadCrumb側にメソッドとして持たせても良い
        breadControl.Margin = new System.Windows.Thickness(-17, 0, 0, 0);
        breadControl.TextLeftMargin = 17;
    }

    zindex--;
    i++;
}

1点、ヘボい言い訳ですが、とんがり部の幅が15なのにMargin幅を17にしているのは、
上記のようにBorder部とPolygon部に分けて背景色を塗った場合に、
BorderとPolygonの間(Polygon側)に微妙に隙間ができてしまうらしく
裏にくる右隣のBreadCrumbの線が透けてみえてしまうようだったためです
(Marginを15にしてみていただければわかるかと思います)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/18 10:07

    すみません、追記に気づいてませんでした・・・。
    すでに解決されたかもしれませんが、一応お答えしておきます。

    >枠線の色を出しつつ縦線を出さずに”>”の部分だけ線を引くことは可能でしょうか?

    上記回答に載せた「BreadCrumb.xaml」について、いまいちどれがどの部分にあたるのか
    まだご理解されてない感じでしょうか?
    構造的には以下のようになっています。
    ・TextBlock:文字だけ
    ・Border:右の三角形部以外の背景と枠線
    ・Polygon:三角形の背景
    ・Polyline:三角形の枠線(左の縦線は無し)

    なので、枠線の色を変えたいならば、PolygonでなくてBorderとPolylineをいじってやればいいわけです。
    BorderとPolylineに名前を付けておいてから、BreadCrumb.xaml.csに以下のようなプロパティを作っておいて
    ---
    public Brush Stroke
    {
    get
    {
    return border.BorderBrush;
    }
    set
    {
    border.BorderBrush = value;
    polyline.Stroke = value;
    }
    }
    ---
    以下のようにして外から指定してやればよいと思います。
    ---
    if (this.trigger)
    {
    breadControl.Stroke = Brushes.Black;
    }
    else
    {
    breadControl.Stroke = new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));
    }
    this.trigger = !this.trigger; //交互にする場合
    ---

    キャンセル

同じタグがついた質問を見る

  • C#

    7714questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • XAML

    262questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。