wpf 将一个控件的值传递给 Converter 以设置另一个控件的宽度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/312044/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:48:45  来源:igfitidea点击:

Pass the value of one control to a Converter to set the width on another control

wpfdata-bindingbindingconverters

提问by Doug

I want to set the width of a TextBlock based on the width of its container, minus the margins set on the TextBlock.

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

Here is my 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>

And that works great except for the fact that the TextBlock is 10 units too big due to the Left and Right Margins bbeing set to 5.

除了由于左右边距 b 设置为 5 导致 TextBlock 大 10 个单位之外,这非常有效。

OK, so I thought... Let's use a Converter. But I don't know how to pass the ActualWidth of my container control (SEE ABOVE: LayoutRoot).

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

I know how to use converters, and even converters with parameters, just not a parameter like... Binding ElementName=LayoutRoot,Path=ActualWidth

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

For example, I can't make this work:

例如,我无法完成这项工作:

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

I hope I made this clear enough and hope that you can help because Google is no help for me tonight.

我希望我说的够清楚了,希望你能帮忙,因为今晚谷歌对我没有帮助。

采纳答案by Danny Varod

you're supposed to use the other control as the source, not the parameter. The parameter has to be a constant and in your case can be -5.

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

I'm not near VS at the moment so the syntax maybe inaccurate, however, it is something like:

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

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

(The converter will receive -5 as a string and will have to convert it into a number before using it.)

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

From my experience it is better to use the OnXXXChanged callback of DependecyProperty XXX, and not bind controls within the same window/root control one to another. One of the reasons for this is that you may want to bind them to an external element later on.

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

Or alternatively, use 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>

and and a converter which converts the two parameters to the value you want.

和一个转换器,它将两个参数转换为您想要的值。

回答by Danny Varod

yes..multi binding works for me.. actually i tried to send a element as a convereterparameter, but its not accepting. thats why i passed the element as a value to the converter class.

是的..多绑定对我有用..实际上我试图发送一个元素作为convereterparameter,但它不接受。这就是为什么我将元素作为值传递给转换器类的原因。

below is my example..

下面是我的例子..

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

In window resize, my first gridviewcolumn has to be resized, not the other two gridviewcolumns.. i passed Actualwidth of listview and also total gridview object as an element.. if you go the converter code...

在窗口调整大小中,我的第一个 gridviewcolumn 必须调整大小,而不是其他两个 gridviewcolumns .. 我传递了列表视图的实际宽度和总 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
}

this worked for me... :)

这对我有用... :)

回答by Gishu

Although I suspect there may be a better way to solve your problem, I think I have an answer for what you want to do. ( You didn't mention what type your container is. A StackPanel for instance takes care of the width calculation for you. See TextBox#2 below)

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

First the XAML

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

Next the Converter. We have a problem here.. since the ConverterParameter for the Convert methods cannot be a dynamic valuefor some reason. So we sneak in the Textbox Margin via a public property of the Converter that we set in Window's ctor. WidthSansMarginConverter.cs

接下来是转换器。我们在这里遇到了问题.. 因为Convert 方法的 ConverterParameter由于某种原因不能是动态值。因此,我们通过在 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

Window2.xaml.cs

        public Window2()
        {
            InitializeComponent();

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

HTH. Thanks for the exercise :)

哈。谢谢你的练习:)

回答by viggity

If your textbox is a direct child of LayoutRoot, just set the the following property in your textbox

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

HorizontalAlignment="Stretch"

回答by George Birbilis

According to http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b, you can add a Dependency property to your custom converter if your converter is derived from DependencyObject.

根据http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b,如果您的转换器来自依赖对象。

In that case you could even use data binding to pass values to those properties where you define the converter (in the resource dictionary) in XAML.

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