简体   繁体   中英

XAML change TextBlock Margin property based on Rectangle's size

I'm trying to create something looking like this :

在此处输入图片说明

It's designed to be an XAML title for VMIX software, video broadcasting purposes.

I'm gonna get a lot of datas from a GSheet, handle in VMIX, and assign those datas to my TextBlocks such as "Candidate", "City" and the Votes %.

From that % I want the bar size to increase/decrease, I managed to do part of that.

But the main issue is to get the % TextBlock margin to fit on the right of the rectangle. Anyone knows how I could do that ?

I have never been coding in C#, I have a background in C, C++ and JS, so I've spent my day looking for that purpose and couldn't make it right.

I saw some binding methods that could fit, but I'm unable to use them.

Moreover I'm working on Blend for Visual Studio 2017, and I don't get why I can't run some simple code on it when pressing F5... It's another problem thought.

Thanks a lot for your help.

EDIT :

I've reached something new so far, really DIY solution but it's my lsat solution if I can't find better :

I'll have 2 TextBlock for 1 ProgressBar (Thanks to Chris)

<Grid Margin="0,0,-8,0">
    <TextBlock x:Name="Votes1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="{Binding Text, ElementName=MarginVotes1}" FontSize="72" Width="853" Height="188"><Run Text="6"/><Run Text="00"/></TextBlock>
    <ProgressBar HorizontalAlignment="Left" Height="79" Margin="171,503,0,0" VerticalAlignment="Top" Width="{Binding Path=Text, ElementName=Votes1}" Background="#FFEA4545"/>
    <TextBlock x:Name="MarginVotes1" HorizontalAlignment="Left" Margin="171,587,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="72" Height="98" Width="550"><Run Text="8"/><Run Text="0"/><Run Text="0"/><Run Text=","/><Run Text="4"/><Run Text="9"/><Run Text="0"/><Run Text=",0,0"/> 
   </TextBlock>

So this works fine, but I have to prepare before what my "MarginVotes1" value is (in GoogleSheet).

The best would be directly in code behind to do something like this :

CONVERT Votes1.Text to Int STORE in val

SET x to val + DefaultMargin

CONVERT x to String STORE in MarginX

CREATE String MarginVoteStr as MarginX + ",500, 0, 0"

SET Votes1.Margin as MarginVoteStr

Welcome to WPF. Here's some code I put together that you should be pretty close to what you need.

XAML:

<ItemsControl Grid.IsSharedSizeScope="True" ItemsSource="{Binding Candidates}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid HorizontalAlignment="Left">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition SharedSizeGroup="Candidate" Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Name}"/>
                <Rectangle Grid.Column="1" Height="10" Margin="5, 0" Width="{Binding BarWidth}" Fill="{Binding BarColor}"/>
                <TextBlock Grid.Column="2" Text="{Binding Percentage, StringFormat=P}"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

C#:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Candidates = new List<Candidate> { new Candidate { Name = "Joe", Percentage = .50, BarColor = Brushes.Green},
                                            new Candidate { Name = "Bob", Percentage = .30, BarColor = Brushes.Yellow},
                                            new Candidate { Name = "Sarah", Percentage = .20, BarColor = Brushes.Gray}};
    }
               
    public List<Candidate> Candidates
    {
        get { return (List<Candidate>)GetValue(CandidatesProperty); }
        set { SetValue(CandidatesProperty, value); }
    }
    public static readonly DependencyProperty CandidatesProperty =
        DependencyProperty.Register("Candidates", typeof(List<Candidate>), typeof(MainWindow));
}

public class Candidate
{
    public string Name { get; set; }
    public double Percentage { get; set; }
    public Brush BarColor { get; set; }

    //This is just shorter syntax for a readonly property.
    //The multiplier (200) should be whatever length you want a full bar to be
    public double BarWidth => Percentage * 200;
}

There are a number of points you should note:

ItemsControl and DataTemplate

Whenever you need to display multiple data items in WPF, especially if the number of items is variable, you should be using some type of ItemsControl .

An ItemsControl takes a collection of some kind and displays each item using a DataTemplate . An ItemsControl creates a new instance of its ItemTemplate for every item in its source collection. The link between the data and the visuals is established through data bindings .

Layout

Everything between the <DataTemplate> tags is the visual layout of a single item.

Notice that I am not using Margin to create the desired layout. Instead of using Margin in that way, I'm using one of WPFs many Panel controls: Grid . With Grid you can define rows and columns like a table.

Each item in my example is a Grid with 1 row and 3 columns. The elements that make up the item are placed in that grid using the Grid.Column property. Each column has Width="Auto" , which means it will grow to accommodate the width of what's inside. IsSharedSizeScope and SharedSizeGroup make it so that the Grid s of each individual item all have the same width for the first column.

Candidate class

This is the class that will be used to store and represent the data being displayed. Note that the property names match the {Binding ______} values from the DataTemplate .

My example main window has a collection of Candidate objects stored in a dependency property . This property is bound to the ItemsSource of the ItemsControl .

Overall

The idea is to populate your collection with whatever data items you need and let the ItemsControl take care of the rest, thus keeping the data and visuals of the project relatively independent. Even small visual aspects like formatting the percentage value correctly for display can be done using the DataTemplate instead of writing the code in C#, as shown using StringFormat=P .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM