Привязка ширины UserControl к входу TextBox - PullRequest
0 голосов
/ 13 декабря 2018

Я впервые использую MVVM pattern, и у меня возникли проблемы с пониманием того, как все связано друг с другом.

У меня есть UserControl с элементом Textbox, который должен изменять ширину указанного UserControl в зависимости от его ввода.

У меня две проблемы:

  1. Чтобы моя идея работала, мне нужно изменить и привязать к d:DesignWidth и моему ColumnDefinition Width.Как и где я могу реализовать эти изменения?Основываясь на моих знаниях MVVM, View (в данном случае мой UserControl) управляется ViewModel для указанного UserControl.Это необходимо для реализации одного или можно связать непосредственно с обоими свойствами?Я знаю, что могу назвать свое ColumnDefinition с помощью x:Name="MyColumnDefinition", но возможно ли то же самое для фактической ширины UserControl?

             mc:Ignorable="d" 
             d:DesignHeight="60" d:DesignWidth="170">
    
  2. У меня есть ObservableCollection, заполненный двумя различными пользовательскими элементами управления, и я хочу, чтобы элементы управления не перекрывались при их отображении.Я использую элемент ListBox для отображения ObservableCollection и реализую различные UserControls над DataTemplates с DataTemplateSelector.Теперь это работает нормально, но я беспокоюсь, если я динамически изменю ширину элемента управления, чтобы он просто перекрывал следующий элемент управления в списке.Как я могу гарантировать, что этого не произойдет?

Ниже приведен код, который у меня есть для UserControl:

<Border Background="LightGray" CornerRadius="6">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition Width="70"/>
            <ColumnDefinition Width="50"/>
        </Grid.ColumnDefinitions>

        <Button VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="0" 
                BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" 
                Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DeleteCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DeleteCommandParameter}">
            <Rectangle Width="8" Height="8" Fill="White">
                <Rectangle.OpacityMask>
                    <VisualBrush Visual="{StaticResource appbar_close}" Stretch="Fill" />
                </Rectangle.OpacityMask>
            </Rectangle>
        </Button>

        <TextBlock Grid.Column="1" Grid.Row="0" FontSize="12" Margin="0,4,0,18" Foreground="White" HorizontalAlignment="Center" Grid.RowSpan="2">Delay</TextBlock>

        <TextBox Grid.Column="1" Grid.Row="1" Width="46" Margin="0,4,0,16" HorizontalAlignment="Center" Grid.RowSpan="2" 
                 Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Delay.MiddlePosition, UpdateSourceTrigger=PropertyChanged}"></TextBox>

        <TextBlock Grid.Column="1" Grid.Row="2" FontSize="8" Margin="20,5,20,5" Foreground="Gray" HorizontalAlignment="Center">[s]</TextBlock>
    </Grid>
</Border>

Редактировать:

ListBox-XAML для хранения других элементов UserControls (Я пытаюсь построить ось, которая может быть заполнена пользовательскими элементами Positioning- и DelayControl:

<ListBox Name="Test" SelectionMode="Single" Grid.Column="1"
                 ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=BlockList}"
                 ItemTemplateSelector="{StaticResource BlockTemplateSelector}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="Focusable" Value="False"/>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>

Конечный результат должен выглядеть примерно так, но с блоками Positioning и Delay разного размера:

XZY axes with different Pos/Delay Commands

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Я долго пытался понять, как решить вашу проблему, и, хотя я не совсем доволен результатом, мне удалось его решить.

Сначала я создаю ListBox с DummyList, которыйсодержит Model-Objects с именем 'UserControlModel' с отдельным свойством 'modelWidth', из которого я создаю свои UserControls с размером по умолчанию.

        <ListBox ItemsSource="{Binding SimpleList, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Width="Auto" Height="200">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <osv:UserControl1 Width="{Binding modelWidth}" OnTextValidated="UserControlSizeChangeEvent"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

OnTextValidated - это RoutedEvent для передачи KeyDown-Event из моего текстового поляв мое окно (которое я покажу позже) UserControl1.xaml затем добавляет текстовое поле

 <TextBox Width="60" Height="30" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" KeyDown="TextBox_KeyDown" Text="{Binding myText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"></TextBox>

с событием KeyDown и текстовой привязкой.

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
  if (e.Key == Key.Return)//press enter to change
  {
    if (double.TryParse(myText, out double d) == true)
    {
      if (d >= 50) //minimum width, so i won't set it to 0 by accident
      {
        myWidth = d; //set the new Width
        OnTextValidated(this, new RoutedEventArgs()); //tell window to resize the UserControl
      }

    }
  }
}

Как только я проверил новый размерне является ни неправильным, ни слишком маленьким, я вызываю RoutedEventHandler

    private RoutedEventHandler m_OnTextValidated;
/// <summary>
/// 
/// </summary>
public RoutedEventHandler OnTextValidated
{
  get { return m_OnTextValidated; }
  set
  {
    m_OnTextValidated = value;
    OnPropertyChanged("CustomClick");
  }
}

, теперь я могу связать это, как показано выше.

Далее я должен передать свое событие из xaml.cs.в MinWindowViewModel

    //Variables
    private MainWindowViewModel m_DataContext;

//Constructor
DataContext = new MainWindowViewModel ();
m_DataContext = (MainWindowViewModel)this.DataContext;



        private void UserControlSizeChangeEvent(object sender, RoutedEventArgs e)
    {
        if (m_DataContext != null)
        {
            m_DataContext.UserControlSizeChangeEvent(sender, e);
        }
    }

и, наконец, обновите размер моего объекта в моем коде позади

  public void UserControlSizeChangeEvent(object sender, RoutedEventArgs e)
{
  UserControl1 uc = sender as UserControl1;
  uc.Width = uc.myWidth;
}

Примечание: Although это работает довольно хорошо, я был бы намного счастливее, если бы нашел способ изменить ширину модели вместо объекта, чтобы они все равно имели такую ​​же ширину в случае перерисовки списка.Я также не использовал шаблон MVVM для моего UserContrl, поэтому вам нужно сначала передать событие из вашего xaml.cs в вашу модель представления, как я это сделал для MainWindow

0 голосов
/ 13 декабря 2018

Отметьте, что этот код поможет вам установить ширину одного элемента управления для другого элемента управления.

<Border>
    <Grid x:Name="grv">
        <TextBox  Width="{Binding ElementName=grv,
                  Path=ActualWidth}">
            </TextBox>
    </Grid>
</Border> 
...