Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 水平项控件中的恒定项宽度_Wpf_Grid_Itemscontrol_Stackpanel - Fatal编程技术网

Wpf 水平项控件中的恒定项宽度

Wpf 水平项控件中的恒定项宽度,wpf,grid,itemscontrol,stackpanel,Wpf,Grid,Itemscontrol,Stackpanel,我需要一个水平组织的ItemsControl,该控件将其所有项约束为相同的宽度。我使用的项目是UserControls,并构建一个自动大小的TextBlock,显示一个int值(包含在依赖项属性中),周围有一个边框。问题是,较小的值会导致项目较窄,我需要所有项目都相同。我已经考虑了一些解决方案,但似乎没有任何效果 第一种方法是将ItemsPanel模板设置为网格。这样,我可以使用代码隐藏根据数据源生成所需的列数,并将所有列宽设置为*。难题在于如何为每个项目设置网格列附加属性 第二种解决方案是将I

我需要一个水平组织的
ItemsControl
,该控件将其所有项约束为相同的宽度。我使用的项目是
UserControl
s,并构建一个自动大小的
TextBlock
,显示一个int值(包含在依赖项属性中),周围有一个
边框。问题是,较小的值会导致项目较窄,我需要所有项目都相同。我已经考虑了一些解决方案,但似乎没有任何效果

第一种方法是将
ItemsPanel
模板设置为
网格
。这样,我可以使用代码隐藏根据数据源生成所需的列数,并将所有列宽设置为
*
。难题在于如何为每个项目设置网格列附加属性

第二种解决方案是将
ItemsPanel
模板设置为
StackPanel
。这会自动正确排列项目,但我无法将每个项目的宽度设置为最宽项目的宽度

最后一种解决方案是将
ItemsPanel
模板设置为带有代码隐藏的
UniformGrid
,以便在数据源更改时设置列数。这将自动正确排列项目,并提供统一的宽度。我这里的问题是,我根本无法得到任何项目显示。我尝试过手动添加按钮,它们显示得很好。我的
UserControl
不会出现。我在下面列出了这个解决方案

    <Window x:Class="Learning_WPF.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:Learning_WPF"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="DateTape" Height="176" Width="500">
        <Window.Resources>
            <my:DateList x:Key="dateList" CollectionChanged="DateList_CollectionChanged" />
        </Window.Resources>
        <ItemsControl x:Name="itemsControl1" ItemsSource="{Binding Source={StaticResource dateList}, Path=/}" Grid.Row="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid x:Name="daysGrid" Rows="1" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Window>

    public partial class MainWindow : Window
    {
        UniformGrid daysGrid;
        DateList dateList;

        public MainWindow()
        {
            InitializeComponent();
            daysGrid = (UniformGrid)itemsControl1.ItemsPanel.LoadContent();
            dateList = (DateList)FindResource("dateList");
            dateList.Fill(DateTime.Today, DateTime.Today.AddDays(10));
        }

        private void DateList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            daysGrid.Columns = dateList.Count;
        }

    }

    public class DateList : ObservableCollection<Date>
    {
        public void Fill(DateTime first, DateTime last)
        {
            // implementation fills the array with all of the days between first and last, inclusively
        }
    }

公共部分类主窗口:窗口
{
UniformGrid daysGrid;
日期表;
公共主窗口()
{
初始化组件();
daysGrid=(UniformGrid)ItemsControl 1.ItemsPanel.LoadContent();
日期列表=(日期列表)FindResource(“日期列表”);
dateList.Fill(DateTime.Today,DateTime.Today.AddDays(10));
}
私有无效日期列表\u CollectionChanged(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
daysGrid.Columns=dateList.Count;
}
}
公共类日期列表:ObservableCollection
{
公共空白填充(日期时间第一,日期时间最后)
{
//实现使用从第一天到最后一天的所有时间(包括第一天和最后一天)填充阵列
}
}

也许有更好的方法来实现我想要实现的目标(可能比使用控件更具图形化).

如果
UniformGrid
无法为您的解决方案解决此问题,您可以尝试为
ItemsControl
设置
itemscontainerstyle
(假设您可以将
ListBox
ListBoxItem
子项一起使用),如下所示:

<Setter Property="ItemContainerStyle">
    <Setter.Value>
        <Style TargetType="{x:Type ListBoxItem}" >
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <ContentPresenter Width="75" ... />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Setter.Value>
</Setter>

我终于用一个
网格让它工作起来了。我不得不在后面做一些重要的代码,而且由于三重布局,界面明显很慢,但它可以工作。欢迎提出改进建议。将此控件插入窗口时,在
EndDate
属性;否则VS将锁定

XAML


C#

public部分类DateTape:UserControl
{
公共静态只读从属属性StartDateProperty=
DependencyProperty.Register(“StartDate”)、typeof(DateTime)、typeof(DateTape),
新资产管理数据(新资产变更回拨(OnDatesChanged));
公共静态只读DependencyProperty EndDateProperty=
DependencyProperty.Register(“EndDate”、typeof(DateTime)、typeof(DateTape),
新资产管理数据(新资产变更回拨(OnDatesChanged));
[类别(“普通”),
TypeConverter(typeof(DateConverter))]
公共日期时间起始日期
{
获取{return(DateTime)GetValue(StartDateProperty);}
set{SetValue(StartDateProperty,value);}
}
[类别(“普通”),
TypeConverter(typeof(DateConverter))]
公共日期时间结束日期
{
获取{return(DateTime)GetValue(EndDateProperty);}
set{SetValue(EndDateProperty,value);}
}
公共数据磁带()
{
初始化组件();
}
私人空间布局()
{
int dayCount=(EndDate-StartDate).Days;
双最大值=0;
当前日期时间=起始日期;
列定义列定义;
边界;
文本块文本块;
有约束力;
无限大小=新大小(double.PositiveInfinity,double.PositiveInfinity);
厚度底部厚度=(厚度)资源[“底部厚度”],
topThickness=(厚度)资源[“topThickness”];
mainGrid.ColumnDefinitions.Clear();

对于(int i=0;我已尝试过UniformGrid。是否尝试过?我确实尝试过,但以前遇到过问题。从那时起,我重新构造了一点。我将重试…在我的示例中,我有一个集合,它具有属性DispayText,并且绑定到按钮内容。为此,我创建了一个转换器,它将使我
    <UserControl x:Class="MyProject.DateTape"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:my="clr-namespace:MyProject"
                 xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 mc:Ignorable="d" 
                 d:DesignHeight="45" d:DesignWidth="188">
        <UserControl.Resources>
            <Thickness x:Key="bottomThickness" Bottom="1" Top="1" Left="0.5" Right="0.5" />
            <Thickness x:Key="topThickness" Bottom="0" Top="1" Left="0.5" Right="0.5" />
            <Style TargetType="Border">
                <Setter Property="BorderBrush" Value="#FFBEBEBE"/>
            </Style>
            <Style TargetType="TextBlock">
                <Setter Property="TextAlignment" Value="Center"/>
                <Setter Property="Margin" Value="6,0"/>
            </Style>
        </UserControl.Resources>
        <Grid x:Name="mainGrid"/>
    </UserControl>
        public partial class DateTape : UserControl
        {
            public static readonly DependencyProperty StartDateProperty =
                DependencyProperty.Register("StartDate", typeof(DateTime), typeof(DateTape),
                                            new PropertyMetadata(new PropertyChangedCallback(OnDatesChanged)));
            public static readonly DependencyProperty EndDateProperty =
                DependencyProperty.Register("EndDate", typeof(DateTime), typeof(DateTape),
                                            new PropertyMetadata(new PropertyChangedCallback(OnDatesChanged)));

            [Category("Common"),
             TypeConverter(typeof(DateConverter))]
            public DateTime StartDate
            {
                get { return (DateTime)GetValue(StartDateProperty); }
                set { SetValue(StartDateProperty, value); }
            }
            [Category("Common"),
             TypeConverter(typeof(DateConverter))]
            public DateTime EndDate
            {
                get { return (DateTime)GetValue(EndDateProperty); }
                set { SetValue(EndDateProperty, value); }
            }

            public DateTape()
            {
                InitializeComponent();
            }

            private void Layout()
            {
                int dayCount = (EndDate - StartDate).Days;
                double max = 0;
                DateTime current = StartDate;
                ColumnDefinition columnDefinition;
                Border border;
                TextBlock textBlock;
                Binding binding;
                Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity);
                Thickness bottomThickness = (Thickness)Resources["bottomThickness"],
                          topThickness = (Thickness)Resources["topThickness"];
                mainGrid.ColumnDefinitions.Clear();
                for (int i = 0; i <= dayCount; i++, current += TimeSpan.FromDays(1))
                {
                    mainGrid.ColumnDefinitions.Add(columnDefinition = new ColumnDefinition());
                    // Add a day
                    border = new Border();
                    textBlock = new TextBlock();
                    textBlock.Text = current.Day.ToString();
                    border.Child = textBlock;
                    binding = new Binding();
                    binding.Source = bottomThickness;
                    border.SetBinding(Border.BorderThicknessProperty, binding);
                    mainGrid.Children.Add(border);
                    border.Measure(infinity);
                    max = Math.Max(max, border.DesiredSize.Width);
                    Grid.SetRow(border, 2);
                    Grid.SetColumn(border, i);
                }
                foreach (ColumnDefinition cd in mainGrid.ColumnDefinitions)
                {
                    cd.MinWidth = max;
                }
            }

            private static void OnDatesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                (d as DateTape).Layout();
            }