简体   繁体   中英

How do I manage the width of controls through UserControl parameters?

In short, the goal is to propagate LabelWidth to its children in my UserControl class, PropertyView. See this fragment:

     <TabItem.Header>Press</TabItem.Header>
    <TabItem.DataContext>
      <Binding XPath="press_information"/>
    </TabItem.DataContext>
    <W3V:PropertyView LabelWidth="200"></W3V:PropertyView>

ANSWER (credit to Athari for his part). To make it work, I needed two elements: In C#, a dependency property:

      public double LabelWidth
      {            get { return (double)this.GetValue(LabelWidthProperty); }
        set { this.SetValue(LabelWidthProperty, value); }
      }
      public static readonly DependencyProperty LabelWidthProperty = 
          DependencyProperty.Register(
                   "LabelWidth", typeof(double), typeof(PropertyView), new PropertyMetadata(100.0)
                   );

In XAML, the following binding syntax:

      <W3V:SimpleControl x:Name="simple"  Content="{Binding}" 
            LabelWidth="{Binding LabelWidth,
                         RelativeSource={RelativeSource AncestorType=W3V:PropertyView}}" />

What didn't work (my original problem):

See the ????? below in the XAML code. I have NO IDEA what I can put in to make it so the SimpleControl will get a LabelWidth assigned, so that it will set its TextBlock's Width property.

I don't even care what approach is taken, it just needs to deal with the fact that PropertyView is bound to an XML object so it can display its properties, and LabelWidth needs to be a property the control-user sets that gets shoved down into the control. LabelWidth will vary depending on what object is being displayed, so it can't be global.

<UserControl x:Class="W3.Views.PropertyView" ... >

  <UserControl.Resources>
  </UserControl.Resources>
  <StackPanel Margin="2" CanVerticallyScroll="true">
    <Border Height="22">
    <TextBlock VerticalAlignment="Bottom"
    Text="{Binding XPath=@label}"
             FontSize="16" FontWeight="Bold" />
    </Border>
    <ItemsControl  ItemsSource="{Binding XPath=*}" Margin="20,0,0,0">
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <W3V:SimpleControl x:Name="simple"  
                             Content="{Binding}" 
                             LabelWidth=?????? />
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>

  </StackPanel>

</UserControl>

C#:

public partial class PropertyView : UserControl
{
      public double LabelWidth
      {
        get { return (double)this.GetValue(LabelWidthProperty); }
        set { this.SetValue(LabelWidthProperty, value); }
      }
      public static readonly DependencyProperty LabelWidthProperty = 
          DependencyProperty.Register(
                   "LabelWidth2", typeof(double), typeof(PropertyView), new PropertyMetadata(0.0)
                   );
      public PropertyView()
      {
        InitializeComponent();


      }          
}

I've searched extensively for a solution that deals with this combination of circumstances, tried many things without success (well, success for simpler situations, but not this), and I'm at a loss here.

Answer to edited question

Here's another go for your problem based on refined question. I'm still not 100% sure what you are trying to achieve but maybe the following points you to right direction, at least.

So there's a Window containing only UserControl. This user control is bound to XML file and it has three label fields. One shows node attritube and the following XML file content. First label's width is bound to property in MainWindow and the other to static converter resource inside the UserControl.

MainWindow XAML

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:user="clr-namespace:WpfApplication"
        Title="MainWindow" Height="350" Width="600">
    <Grid>
        <user:XmlUserControl />
    </Grid>
</Window>

MainWindow Codebehind

using System;
using System.Windows;

namespace WpfApplication
{
    public partial class MainWindow : Window
    {
        readonly Random _random = new Random();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public double ControlWidth
        {
            get { return _random.Next(200, 600); }
        }
    }
}

XmlUserControl XAML

<UserControl x:Class="WpfApplication.XmlUserControl"
             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:local="clr-namespace:WpfApplication2"
             mc:Ignorable="d" 
             d:DesignHeight="350" d:DesignWidth="350">

    <StackPanel>
        <StackPanel.Resources>
            <XmlDataProvider x:Key="XmlData" XPath="Data/Items" Source="Items.xml" />
            <local:NodeWidthConverter x:Key="NodeWidthConverter" />
        </StackPanel.Resources>

    <ItemsControl>
        <ItemsControl.ItemsSource>
            <Binding Source="{StaticResource XmlData}" XPath="*"/>
        </ItemsControl.ItemsSource>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <Label x:Name="Title" VerticalAlignment="Bottom" 
                           FontWeight="Bold" HorizontalAlignment="Left"
                           Content="{Binding XPath=@Title}" />
                        <Label Background="BurlyWood" HorizontalAlignment="Left" 
                               Content="{Binding}" Width="{Binding ControlWidth}" />
                        <Label Background="BlanchedAlmond" HorizontalAlignment="Left"
                               Content="{Binding}" Width="{Binding ElementName=Title, Converter={StaticResource NodeWidthConverter}}"/>
                    </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    </StackPanel>
</UserControl>

XmlUserControl codebehind

using System.Windows.Controls;

namespace WpfApplication
{
    public partial class XmlUserControl : UserControl
    {
        public XmlUserControl()
        {
            InitializeComponent();
        }
    }
}

NodeWidthConverter

using System;
using System.Globalization;
using System.Windows.Data;

namespace WpfApplication2
{
    public class NodeWidthConverter : IValueConverter 
    {
        public static Random Random = new Random();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Random.Next(200, 600);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Items.xml sample data

  <Data>
    <Items>
      <Item Title="Title 1">
        <Name>This is item name 1</Name>
        <Summary>Summary for item 1</Summary>
      </Item>
      <Item Title="Title 2">
        <Name>This is item name 2</Name>
        <Summary>Summary for item 2</Summary>
      </Item>
      <Item Title="Title 3">
        <Name>This is item name 3</Name>
        <Summary>Summary for item 3</Summary>
      </Item>
    </Items>
  </Data>

With this you'll get the following. Label has colored background to visualize the changing width properties.

未找到

Hope this helps!

So, you just need to bind SimpleControl.LabelWidth to PropertyView.LabelWidth ? It can be achieved this way:

<W3V:SimpleControl
    LabelWidth="{Binding Path=LabelWidth,
                     RelativeSource={RelativeSource AncestorType=PropertyView}}"

PS Your dependency property is registered as "LabelWidth2" (typo?). And new PropertyMetadata(0.0) is redundant, as default(double) == 0.0 .

Do you have a failed binding back to your StaticResources? Do you have values defined in the resources section? Try something like this (note that I wrote this directly here (not in VS), it should be pretty much correct :)

<UserControl ...>
    <UserControl.Resources>
        <System.Int x:Key="ContentWidth">100</System.Int> 
    </UserControl.Resources>



    <StackPanel Orientation="Horizontal" >
        <TextBlock Width="{StaticResource LabelWidth}" Text="test"/>
        <TextBox Width="{StaticResource ContentWidth}" />
    </StackPanel>
</UserControl>

I would ask if you are really intending to go to StaticResources or whether you meant to bind to a property on a viewmodel or in the code behind of the view?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM