2008-11-23 5 views
11

Je souhaite définir la largeur d'un TextBlock en fonction de la largeur de son conteneur, moins les marges définies sur le TextBlock.WPF - Transmettre la valeur d'un contrôle à un convertisseur pour définir la largeur sur un autre contrôle

Voici mon code

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

Et cela fonctionne très bien à l'exception du fait que le TextBlock est de 10 unités trop grand en raison de la Gauche et Droite marges bbeing réglé sur 5.

OK, Je pensais ... Utilisons un convertisseur. Mais je ne sais pas comment passer le contrôle ActualWidth de mon conteneur (VOIR CI-DESSUS: LayoutRoot).

Je sais comment utiliser des convertisseurs, et même des convertisseurs avec des paramètres, mais pas un paramètre comme ... Reliure ElementName = LayoutRoot, Path = ActualWidth

Par exemple, je ne peux pas faire ce travail ... J'espère que je l'ai fait assez clair et j'espère que vous pouvez aider parce que Google n'est d'aucune aide pour moi ce soir.

TIA!

Doug

Répondre

11

vous êtes censé utiliser l'autre contrôle que la source, pas le paramètre. Le paramètre doit être une constante et dans votre cas peut être -5.

Je ne suis pas près de VS au moment de sorte que la syntaxe peut-être inexact, mais il est quelque chose comme:

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

(Le convertisseur recevra -5 comme une chaîne et devra convertir en D'après mon expérience, il est préférable d'utiliser le rappel OnXXXChanged de DependecyProperty XXX, et ne pas lier les contrôles dans le même contrôle de fenêtre/racine les uns aux autres. L'une des raisons à cela est que vous voudrez peut-être les lier ultérieurement à un élément externe.

Ou bien, utilisez 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> 

et et un convertisseur qui convertit les deux paramètres à la valeur souhaitée.

+0

Merci Danny. Cela a très bien fonctionné. Mais j'espérais ne pas avoir à coder en dur la valeur du paramètre. Je ne savais pas que le paramètre devait être une constante. Merci! – Doug

+0

Merci beaucoup, très utile! – Jacob

3

Bien que je soupçonne qu'il existe peut-être une meilleure façon de résoudre votre problème, je pense que j'ai une réponse à ce que vous voulez faire. (Vous n'avez pas mentionné de quel type votre conteneur est. Un StackPanel par exemple prend en charge le calcul de la largeur pour vous. Voir l'encadré 2 ci-dessous)

D'abord le 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> 

Suivant le convertisseur. Nous avons un problème ici .. depuis the ConverterParameter for the Convert methods cannot be a dynamic value pour une raison quelconque. Donc nous nous faufilons dans la Textbox Margin via une propriété publique du Convertisseur que nous avons définie dans le ctor de Windows. 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. Merci pour l'exercice :)

+0

Thnaks Gishu! Votre échantillon m'a aidé à en apprendre plus sur les convertisseurs. Bien que votre réponse ait fonctionné, j'ai fini de marquer la réponse de danny comme LA réponse parce que c'était la solution que j'utilisais. J'étais fatigué et paresseux et son, moins flexible, était moins de code. Merci! – Doug

+0

Comment j'ai été hanté par les nombreuses solutions qui ont échoué, jusqu'à ce que je trouve celui-ci! Merci – nemesisfixx

0

Si votre enfant est un champ de saisie directe de LayoutRoot, vient de mettre la la propriété suivante dans votre zone de texte

HorizontalAlignment="Stretch" 
5

œuvres liant yes..multi pour moi .. en fait j'ai essayé de envoyer un élément en tant que convereterparameter, mais il n'accepte pas. C'est pourquoi j'ai passé l'élément en tant que valeur à la classe de convertisseur.

ci-dessous est mon exemple ..

<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> 

Dans Redimensionner la fenêtre, mon premier GridViewColumn doit être redimensionnée, pas les deux autres gridviewcolumns .. je suis passé actualWidth de listview et aussi tout objet GridView comme un élément .. si vous allez le code convertisseur ...

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 
} 

cela a fonctionné pour moi ... :)

Questions connexes