如何将两个控件的宽度总和绑定到另一个控件的最小宽度
How to Bind Sum of width of two control to MinWidth of another control
我想设置网格列的最小宽度,它应该是标签的实际宽度和放置在列的单元格内的另一个网格内的按钮控件的总和。为此,我正在使用 Converter class,但要找出 XAML 部分。
转换器在这里:
class StringSumtoIntConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
int sum = 0;
foreach (var item in value)
{
sum += System.Convert.ToInt32(item);
}
return sum;
}
//...Other implementations
}
XAML我写到现在的代码是:
xmlns:helperClasses="clr-namespace:EmbroidaryManagementSystem_V2._0.HelperClasses" <!--Import class-->
<helperClasses:StringSumtoIntConverter x:Key="StringSumtoIntConvert"/> <!--Inside Window.Resources tag-->
<ColumnDefinition Width="48*"> <!--Inside Grid-->
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
XAML 的完整实现在这里:
<Window x:Class="EmbroidaryManagementSystem_V2._0.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EmbroidaryManagementSystem_V2._0.View"
xmlns:y="clr-namespace:EmbroidaryManagementSystem_V2._0.ViewModel.CollectionsViewModel"
xmlns:helperClasses="clr-namespace:EmbroidaryManagementSystem_V2._0.HelperClasses"
mc:Ignorable="d"
Title="MainWindow" Height="655.512" Width="1120.159" FontSize="24" WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<helperClasses:StringSumtoIntConverter x:Key="StringSumtoIntConvert"/>
</Window.Resources>
<Window.DataContext>
<y:ClientCollectionVM/>
</Window.DataContext>
<Grid HorizontalAlignment="Left" Height="622" VerticalAlignment="Top" Width="1110" Background="#FFD6DBE9">
<Grid.RowDefinitions>
<RowDefinition Height="89*"/>
<RowDefinition Height="39*"/>
<RowDefinition Height="494*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="137*"/>
<ColumnDefinition Width="48*">
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="gridSplitter" Grid.Column="1" HorizontalAlignment="Left" Height="533" Grid.Row="1"
VerticalAlignment="Top" Width="2" Grid.RowSpan="2"/>
<Grid Grid.Column="1" Height="35" Background="#FF657695"
Grid.Row="1" VerticalAlignment="Top">
<Label x:Name="lblNotificationsHeader" Content="Notifications" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14.667" Height="30" Foreground="#FFEBF0EE"/>
<Button x:Name="btnNotificationsClose" Content="X"
Margin="0,5,8,0" VerticalAlignment="Top" Width="20" FontFamily="Verdana" HorizontalAlignment="Right" Background="Transparent" FontSize="13.333" Foreground="Black"/>
</Grid>
</Grid>
还有一个错误说:无法将类型 'EmbroidaryManagementSystem_V2._0.ViewModel.CollectionsViewModel.ClientCollectionVM' 的对象转换为类型 'System.IConvertible'。
在行:
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
不知道为什么。
您没有在绑定中指定任何内容,因此它传递了您的数据上下文,即 VM。 VM 不可转换为 int。您需要传入 {Binding ElementName=btnNotificationsClose, Path=ActualWidth} 并且 lblNotificationsHeader 也一样。
不过,老实说,听起来你把事情复杂化了。网格 row/columns 不能调整大小,除非你使用了你不是的分隔符。
您需要在 MultiBinding 中向转换器提供值。
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding ElementName="lblNotificationsHeader" Path="ActualWidth" />
<Binding ElementName="btnNotificationsClose" Path="ActualWidth" />
</MultiBinding>
错误是因为 Path 为空,这意味着它正在获取 DataContext 并试图将其传递给无法将 ClientCollectionVM 转换为 int 的转换器。
我不是 100% 确定您要处理所有这些,但您可能会修复转换器并执行以下操作:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
然后该列将展开以适合其内容。当然,您可能希望将内部 Grid 更改为水平方向的 StackPanel:
<StackPanel Grid.Row="1"
Grid.Column="1"
Height="35"
VerticalAlignment="Top"
Background="#FF657695"
Orientation="Horizontal">
<Label x:Name="lblNotificationsHeader"
Height="30"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="Notifications"
FontSize="14.667"
Foreground="#FFEBF0EE" />
<Button x:Name="btnNotificationsClose"
Margin="0,5,8,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
Content="X"
FontFamily="Verdana"
FontSize="13.333"
Foreground="Black" />
</StackPanel>
或者给内部 Grid 自己的列定义以将 Label 和 Button 分开。
更新
根据您添加 GridSplitter 的更新,我提供了一个完整的示例来说明如何实现您的目标。
请记住,在您的示例中,无论您将其拖动到哪个方向,GridSplitter 实际上都在调整左列的大小,而右列只是扩展以填充。所以我们的目标不是在你的右栏上有一个 MinWidth
,而是在我们的左栏上有一个 MaxWidth
。
对您的转换器进行快速更改,因为 ActualWidth
和 ActualHeight
是双精度数,让我们将转换器更改为使用双精度数而不是整数,这样我们就不会以杂散像素结束。
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
double sum = 0;
foreach (var item in value)
{
sum += System.Convert.ToDouble(item);
}
return sum;
}
我们将把 GridSplitter 放在它自己的列中,将列宽设置为 "2"
,将第一个 ColumnDefinition 的宽度设置为 "4*"
,将第三个设置为 "*"
。 "4*"
实际上只是一个随机数,星星的大小取决于百分比,所以 4 并不总是有效,它只是在这种情况下有效。
我们还需要向内部网格添加一些列,我们将为它们命名并使用这些元素来获取我们的 MultiBinding 的宽度。我们这样做而不是从元素本身获取宽度,因为 ActualWidth 不包括边距。
<Grid Background="#FFD6DBE9">
<Grid.RowDefinitions>
<RowDefinition Height="89*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="494*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="2" />
<ColumnDefinition Width="*">
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding ElementName="cdNotificationHeaderLabel" Path="ActualWidth" />
<Binding ElementName="cdNotificationHeaderButton" Path="ActualWidth" />
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="gridSplitter"
Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="1"
Width="2"
ResizeBehavior="PreviousAndNext" />
<Grid Grid.Row="1"
Grid.Column="2"
Height="35"
Background="#FF657695">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="cdNotificationHeaderLabel" Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition x:Name="cdNotificationHeaderButton" Width="Auto" />
</Grid.ColumnDefinitions>
<Label x:Name="lblNotificationsHeader"
Margin="0 0 5 0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Notifications"
FontSize="14.667"
Foreground="#FFEBF0EE" />
<Button x:Name="btnNotificationsClose"
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="Transparent"
Content="X"
FontFamily="Verdana"
FontSize="13.333"
Foreground="Black" />
</Grid>
</Grid>
综上所述,我建议从 GridSplitter 派生自定义控件并以这种方式处理它,但以上内容应该有助于让您振作起来 运行。
我想设置网格列的最小宽度,它应该是标签的实际宽度和放置在列的单元格内的另一个网格内的按钮控件的总和。为此,我正在使用 Converter class,但要找出 XAML 部分。 转换器在这里:
class StringSumtoIntConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
int sum = 0;
foreach (var item in value)
{
sum += System.Convert.ToInt32(item);
}
return sum;
}
//...Other implementations
}
XAML我写到现在的代码是:
xmlns:helperClasses="clr-namespace:EmbroidaryManagementSystem_V2._0.HelperClasses" <!--Import class-->
<helperClasses:StringSumtoIntConverter x:Key="StringSumtoIntConvert"/> <!--Inside Window.Resources tag-->
<ColumnDefinition Width="48*"> <!--Inside Grid-->
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
XAML 的完整实现在这里:
<Window x:Class="EmbroidaryManagementSystem_V2._0.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EmbroidaryManagementSystem_V2._0.View"
xmlns:y="clr-namespace:EmbroidaryManagementSystem_V2._0.ViewModel.CollectionsViewModel"
xmlns:helperClasses="clr-namespace:EmbroidaryManagementSystem_V2._0.HelperClasses"
mc:Ignorable="d"
Title="MainWindow" Height="655.512" Width="1120.159" FontSize="24" WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<helperClasses:StringSumtoIntConverter x:Key="StringSumtoIntConvert"/>
</Window.Resources>
<Window.DataContext>
<y:ClientCollectionVM/>
</Window.DataContext>
<Grid HorizontalAlignment="Left" Height="622" VerticalAlignment="Top" Width="1110" Background="#FFD6DBE9">
<Grid.RowDefinitions>
<RowDefinition Height="89*"/>
<RowDefinition Height="39*"/>
<RowDefinition Height="494*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="137*"/>
<ColumnDefinition Width="48*">
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="gridSplitter" Grid.Column="1" HorizontalAlignment="Left" Height="533" Grid.Row="1"
VerticalAlignment="Top" Width="2" Grid.RowSpan="2"/>
<Grid Grid.Column="1" Height="35" Background="#FF657695"
Grid.Row="1" VerticalAlignment="Top">
<Label x:Name="lblNotificationsHeader" Content="Notifications" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14.667" Height="30" Foreground="#FFEBF0EE"/>
<Button x:Name="btnNotificationsClose" Content="X"
Margin="0,5,8,0" VerticalAlignment="Top" Width="20" FontFamily="Verdana" HorizontalAlignment="Right" Background="Transparent" FontSize="13.333" Foreground="Black"/>
</Grid>
</Grid>
还有一个错误说:无法将类型 'EmbroidaryManagementSystem_V2._0.ViewModel.CollectionsViewModel.ClientCollectionVM' 的对象转换为类型 'System.IConvertible'。 在行:
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding Path=""></Binding>
</MultiBinding>
不知道为什么。
您没有在绑定中指定任何内容,因此它传递了您的数据上下文,即 VM。 VM 不可转换为 int。您需要传入 {Binding ElementName=btnNotificationsClose, Path=ActualWidth} 并且 lblNotificationsHeader 也一样。
不过,老实说,听起来你把事情复杂化了。网格 row/columns 不能调整大小,除非你使用了你不是的分隔符。
您需要在 MultiBinding 中向转换器提供值。
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding ElementName="lblNotificationsHeader" Path="ActualWidth" />
<Binding ElementName="btnNotificationsClose" Path="ActualWidth" />
</MultiBinding>
错误是因为 Path 为空,这意味着它正在获取 DataContext 并试图将其传递给无法将 ClientCollectionVM 转换为 int 的转换器。
我不是 100% 确定您要处理所有这些,但您可能会修复转换器并执行以下操作:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
然后该列将展开以适合其内容。当然,您可能希望将内部 Grid 更改为水平方向的 StackPanel:
<StackPanel Grid.Row="1"
Grid.Column="1"
Height="35"
VerticalAlignment="Top"
Background="#FF657695"
Orientation="Horizontal">
<Label x:Name="lblNotificationsHeader"
Height="30"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="Notifications"
FontSize="14.667"
Foreground="#FFEBF0EE" />
<Button x:Name="btnNotificationsClose"
Margin="0,5,8,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
Content="X"
FontFamily="Verdana"
FontSize="13.333"
Foreground="Black" />
</StackPanel>
或者给内部 Grid 自己的列定义以将 Label 和 Button 分开。
更新
根据您添加 GridSplitter 的更新,我提供了一个完整的示例来说明如何实现您的目标。
请记住,在您的示例中,无论您将其拖动到哪个方向,GridSplitter 实际上都在调整左列的大小,而右列只是扩展以填充。所以我们的目标不是在你的右栏上有一个 MinWidth
,而是在我们的左栏上有一个 MaxWidth
。
对您的转换器进行快速更改,因为 ActualWidth
和 ActualHeight
是双精度数,让我们将转换器更改为使用双精度数而不是整数,这样我们就不会以杂散像素结束。
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
double sum = 0;
foreach (var item in value)
{
sum += System.Convert.ToDouble(item);
}
return sum;
}
我们将把 GridSplitter 放在它自己的列中,将列宽设置为 "2"
,将第一个 ColumnDefinition 的宽度设置为 "4*"
,将第三个设置为 "*"
。 "4*"
实际上只是一个随机数,星星的大小取决于百分比,所以 4 并不总是有效,它只是在这种情况下有效。
我们还需要向内部网格添加一些列,我们将为它们命名并使用这些元素来获取我们的 MultiBinding 的宽度。我们这样做而不是从元素本身获取宽度,因为 ActualWidth 不包括边距。
<Grid Background="#FFD6DBE9">
<Grid.RowDefinitions>
<RowDefinition Height="89*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="494*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="2" />
<ColumnDefinition Width="*">
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding ElementName="cdNotificationHeaderLabel" Path="ActualWidth" />
<Binding ElementName="cdNotificationHeaderButton" Path="ActualWidth" />
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="gridSplitter"
Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="1"
Width="2"
ResizeBehavior="PreviousAndNext" />
<Grid Grid.Row="1"
Grid.Column="2"
Height="35"
Background="#FF657695">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="cdNotificationHeaderLabel" Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition x:Name="cdNotificationHeaderButton" Width="Auto" />
</Grid.ColumnDefinitions>
<Label x:Name="lblNotificationsHeader"
Margin="0 0 5 0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Notifications"
FontSize="14.667"
Foreground="#FFEBF0EE" />
<Button x:Name="btnNotificationsClose"
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="Transparent"
Content="X"
FontFamily="Verdana"
FontSize="13.333"
Foreground="Black" />
</Grid>
</Grid>
综上所述,我建议从 GridSplitter 派生自定义控件并以这种方式处理它,但以上内容应该有助于让您振作起来 运行。