WPF - Passa il valore di un controllo a un convertitore per impostare la larghezza su un altro controllo

StackOverflow https://stackoverflow.com/questions/312044

Domanda

Voglio impostare la larghezza di un TextBlock in base alla larghezza del suo contenitore, meno i margini impostati su TextBlock.

Ecco il mio codice

<TextBlock x:Name="txtStatusMessages" 
           Width="{Binding ElementName=LayoutRoot,Path=ActualWidth }"
                   TextWrapping="WrapWithOverflow" 
           Foreground="White" 
           Margin="5,5,5,5">This is a message
</TextBlock>

E funziona benissimo, tranne per il fatto che TextBlock è 10 unità troppo grande a causa dei margini sinistro e destro impostati su 5.

OK, quindi ho pensato ... Usiamo un convertitore. Ma non so come passare ActualWidth del mio controllo container (VEDI SOPRA: LayoutRoot).

So come usare i convertitori e persino i convertitori con parametri, ma non un parametro come ... Binding ElementName = LayoutRoot, Path = ActualWidth

Ad esempio, non posso farlo funzionare ...

Width="{Binding Converter={StaticResource PositionConverter},  
       ConverterParameter={Binding ElementName=LayoutRoot,Path=ActualWidth }}"

Spero di averlo chiarito abbastanza e spero che tu mi possa aiutare perché Google non è di aiuto per me stasera.

TIA!

Doug

È stato utile?

Soluzione

dovresti usare l'altro controllo come sorgente, non come parametro. Il parametro deve essere una costante e nel tuo caso può essere -5.

Al momento non sono vicino a VS, quindi la sintassi potrebbe non essere precisa, tuttavia è qualcosa del tipo:

Width="{Binding ElementName=LayoutRoot, Path=ActualWidth,
Converter={StaticResource PositionConverter}, ConverterParameter=-5}"

(Il convertitore riceverà -5 come stringa e dovrà convertirlo in un numero prima di usarlo.)

Dalla mia esperienza è meglio usare il callback OnXXXChanged di DependecyProperty XXX, e non associare i controlli all'interno dello stesso controllo finestra / radice l'uno all'altro. Uno dei motivi di ciò è che potresti voler legarli a un elemento esterno in seguito.

O in alternativa, utilizzare multibinding:

<TextBlock>
    <TextBlock.Width>
        <MultiBinding Converter="{StaticResource yourConverter}">
            <MultiBinding.Bindings>
                <Binding /> <!-- Bind to parameter 1 here -->
                <Binding /> <!-- Bind to parameter 2 here -->
          </MultiBinding.Bindings>
        </MultiBinding>
    </TextBlock.Width>
</TextBlock>

ee un convertitore che converte i due parametri nel valore desiderato.

Altri suggerimenti

sì..multi binding funziona per me .. in realtà ho provato a inviare un elemento come parametro di conversione, ma non accetta. ecco perché ho passato l'elemento come valore alla classe del convertitore.

di seguito è il mio esempio ..

<ListView ... >
<ListView.View>
<GridView>
    <GridViewColumn Header="xyz" >

        <GridViewColumn.Width>
            <MultiBinding Converter="{StaticResource GetWidthfromParentControl}">
                <MultiBinding.Bindings>
                    <Binding ElementName="lstNetwork" Path="ActualWidth"/>
                    <Binding ElementName="MyGridView"/>
                </MultiBinding.Bindings>
            </MultiBinding>
        </GridViewColumn.Width>
    ....
    </GridViewColumn>
    <GridViewColumn ...>
    ....
    </GridViewColumn>
</GridView>
</ListView.View>
</ListView>

Nel ridimensionamento della finestra, il mio primo gridviewcolumn deve essere ridimensionato, non gli altri due gridviewcolumns. ho passato Actualwidth di listview e anche l'oggetto gridview totale come elemento .. se vai al codice del convertitore ...

class GetWidthfromParentControl : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        GridView view = values[1] as GridView;
        GridViewColumnCollection collc = view.Columns;
        double actualWidths = collc[1].ActualWidth + collc[2].ActualWidth;
        return ((double)values[0] - actualWidths );
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }

    #endregion
}

questo ha funzionato per me ... :)

Anche se sospetto che ci possa essere un modo migliore per risolvere il tuo problema, penso di avere una risposta per quello che vuoi fare. (Non hai menzionato il tipo di contenitore. Uno StackPanel, ad esempio, si occupa del calcolo della larghezza per te. Vedi TextBox # 2 di seguito)

Innanzitutto XAML

<Window x:Class="WpfApplication1.Window2" ...
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window2" Height="300" Width="300">
    <Window.Resources>
        <local:WidthSansMarginConverter x:Key="widthConverter" />
    </Window.Resources>
    <Grid>
        <StackPanel x:Name="stack">
            <TextBlock x:Name="txtStatusMessages" 
                    Width="{Binding ElementName=stack,Path=ActualWidth, 
                        Converter={StaticResource widthConverter}}"
                    TextWrapping="WrapWithOverflow" 
                    Background="Aquamarine" 
                    Margin="5,5,5,5">
                This is a message
            </TextBlock>
            <TextBlock x:Name="txtWhatsWrongWithThis" 
                    TextWrapping="WrapWithOverflow" 
                    Background="Aquamarine" 
                    Margin="5,5,5,5">
                This is another message
            </TextBlock>
        </StackPanel>
    </Grid>
</Window>

Avanti il ??convertitore. Abbiamo un problema qui .. poiché ConverterParameter per i metodi Convert non può essere un valore dinamico per qualche motivo. Quindi ci intrufoliamo nel margine della casella di testo tramite una proprietà pubblica del convertitore che abbiamo impostato nel ctor di Window. WidthSansMarginConverter.cs

public class WidthSansMarginConverter : IValueConverter
    {
        private Thickness m_Margin = new Thickness(0.0);

        public Thickness Margin
        {
            get { return m_Margin; }
            set { m_Margin = value; }
        }
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (targetType != typeof(double)) { return null; }

            double dParentWidth = Double.Parse(value.ToString());
            double dAdjustedWidth = dParentWidth-m_Margin.Left-m_Margin.Right;
            return (dAdjustedWidth < 0 ? 0 : dAdjustedWidth);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

Window2.xaml.cs

        public Window2()
        {
            InitializeComponent();

            WidthSansMarginConverter obConverter = this.FindResource("widthConverter") as WidthSansMarginConverter;
            obConverter.Margin = txtStatusMessages.Margin;
        }

HTH. Grazie per l'esercizio :)

Se la casella di testo è una figlia diretta di LayoutRoot, basta impostare la seguente proprietà nella casella di testo

HorizontalAlignment="Stretch"

Secondo http: //social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b , puoi aggiungere una proprietà Dependency al tuo convertitore personalizzato se il tuo convertitore è derivato da DependencyObject.

In tal caso, potresti persino utilizzare l'associazione dei dati per passare valori a quelle proprietà in cui definisci il convertitore (nel dizionario delle risorse) in XAML.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top