【问题标题】:Pass the value of one control to a Converter to set the width on another control将一个控件的值传递给 Converter 以设置另一个控件的宽度
【发布时间】:2010-09-23 15:30:32
【问题描述】:

我想根据容器的宽度减去 TextBlock 上设置的边距来设置 TextBlock 的宽度。

这是我的代码:

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

这很好用,除了 TextBlock 由于左右边距设置为 5 而太大了 10 个单位。

好的,所以我想...让我们使用转换器。但我不知道如何传递我的容器控件的 ActualWidth(见上图:LayoutRoot)。

我知道如何使用转换器,甚至是带参数的转换器,只是不是像... Binding ElementName=LayoutRoot,Path=ActualWidth 之类的参数

例如,我无法做到这一点:

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

我希望我说得足够清楚,并希望您能提供帮助,因为今晚 Google 对我没有帮助。

【问题讨论】:

    标签: wpf data-binding binding converters


    【解决方案1】:

    您应该使用另一个控件作为源,而不是参数。 参数必须是常数,在您的情况下可以是 -5。

    我现在不在 VS 附近,所以语法可能不准确,但是,它类似于:

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

    (转换器将接收 -5 作为字符串,在使用之前必须将其转换为数字。)

    根据我的经验,最好使用 DependecyProperty XXX 的 OnXXXChanged 回调,而不是将同一窗口/根控件中的控件相互绑定。 原因之一是您可能希望稍后将它们绑定到外部元素。

    或者,使用多重绑定:

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

    还有一个转换器,它将两个参数转换为你想要的值。

    【讨论】:

    • 谢谢丹尼。这工作得很好。但我希望不必对参数值进行硬编码。我不知道 Parameter 需要是一个常数。谢谢!
    • 非常感谢,太有帮助了!
    【解决方案2】:

    是的..multi 绑定对我有用.. 实际上我尝试将元素作为转换参数发送,但它不接受。这就是我将元素作为值传递给转换器类的原因。

    下面是我的例子..

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

    在窗口调整大小时,我的第一个 gridviewcolumn 必须调整大小,而不是其他两个 gridviewcolumn.. 我通过了列表视图的实际宽度以及总的gridview对象作为一个元素.. 如果你去转换器代码...

    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
    }
    

    这对我有用... :)

    【讨论】:

      【解决方案3】:

      虽然我怀疑可能有更好的方法来解决您的问题,但我想我对您想要做的事情有一个答案。 (您没有提到您的容器是什么类型。例如 StackPanel 会为您处理宽度计算。请参阅下面的 TextBox#2)

      首先是 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>
      

      接下来是转换器。我们这里有个问题..因为某种原因the ConverterParameter for the Convert methods cannot be a dynamic value。因此,我们通过在 Window 的 ctor 中设置的 Converter 的公共属性潜入 Textbox Margin。 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。感谢您的练习:)

      【讨论】:

      • 感谢吉舒!您的示例帮助我了解了有关转换器的更多信息。尽管您的答案有效,但我最终将 danny 的答案标记为答案,因为这是我使用的解决方案。我又累又懒,他的代码虽然不那么灵活,但代码更少。谢谢!
      • 我一直被许多无效的解决方案所困扰,直到我找到了这个!谢谢
      【解决方案4】:

      如果您的文本框是 LayoutRoot 的直接子级,只需在您的文本框中设置以下属性

      HorizontalAlignment="Stretch"
      

      【讨论】:

        【解决方案5】:

        根据http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b,如果您的转换器是从 DependencyObject 派生的,您可以将 Dependency 属性添加到您的自定义转换器。

        在这种情况下,您甚至可以使用数据绑定将值传递给您在 XAML 中定义转换器(在资源字典中)的那些属性。

        【讨论】:

          猜你喜欢
          • 2013-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-14
          • 2015-12-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多