Как связать Textbox.ReadOnly со свойством в родительской (владелец) модели представления - PullRequest
0 голосов
/ 06 марта 2020

Кажется, это решенный вопрос, но, попробовав несколько ответов, опубликованных здесь, я не смог решить свою проблему. Вот оно:

Я хочу установить (привязав) свойство IsReadonly объекта TextBox к свойству модели основного представления, которая содержит тип, к которому уже привязан TextBox. Также текстовое поле находится в DataTemplate, связанном с типом.

Попытка этого приводит к «Свойству 'IsReadOnly' not found» , что имеет смысл, поскольку шаблон данных связан с типом, который его нет:

<TextBox Name="PromoEntryForm" AutomationProperties.Name="Promo Description" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
                         Text="{Binding Path=FriendlyName, UpdateSourceTrigger=PropertyChanged}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" 
                     IsReadOnly="{Binding Path=IsReadOnly}" />

Попытка этого ничего не дает, что также имеет смысл, потому что это привязка к тому же TextBox.IsReadOnly, как я понимаю:

<TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
                            Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=IsReadOnly}" />

Я знаю Я должен привязать к свойству в родительском (модель представления контейнера), поэтому я также попытался это, что приводит к "System. Windows .Data Error: 4: Не удается найти источник для привязки со ссылкой 'RelativeSource FindAncestor, AncestorType = 'Catalo Go .ViewModel.PromoViewModel' , AncestorLevel = '1' '. BindingExpression: Path = IsReadOnly; DataItem = null; целевым элементом является TextBox (Name =' PrintableNameEntryF) свойство isReadOnly (тип Boolean) "

<TextBox Name="PrintableNameEntryForm" AutomationProperties.Name="Printable Name" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
                         Text="{Binding Path=PublicName, UpdateSourceTrigger=PropertyChanged}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" 
                     IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type localVm:PromoViewModel}}, Path=IsReadOnly}" />

Но тип равен , тот, который указан в сообщении об ошибке, и DataContext представления устанавливается в экземпляр PromoView Модель, поэтому я не знаю, почему он не может найти источник.

Это модель полного вида:

public class PromoViewModel : SupervisedEntity
{
    private ObservableCollection<Promo> _promos;
    private Promo _current;     
    private bool _editMode;
    private bool _isNew;        

    public string Title => "Promociones"; 

    public ObservableCollection<Promo> Promos
    {
        get => this._promos;
        set => this.SetPropertyValue(ref this._promos, value);
    }

    public Promo Current
    {
        get => this._current;
        set => this.SetPropertyValue(ref this._current, value);
    }

    public bool IsEditMode
    {
        get => this._editMode;
        set
        {
            this.SetPropertyValue(ref this._editMode, value);
            this.NotifyPropertyChanged(nameof(this.IsReadOnly));
            this.NotifyPropertyChanged(nameof(this.HideIfEditing));
            this.NotifyPropertyChanged(nameof(this.ShowIfEditing));
        }
    }

    public bool IsNew
    {
        get => this._isNew;
        set => this.SetPropertyValue(ref this._isNew, value);
    }

    public Promo Backup { get; set; }
    public bool IsReadOnly => !this.IsEditMode;
    public Visibility HideIfEditing => (this.IsReadOnly ? Visibility.Visible : Visibility.Collapsed);
    public Visibility ShowIfEditing => (this.IsReadOnly ? Visibility.Collapsed : Visibility.Visible);
}

И это соответствующее представление:

<Window x:Class="CataloGo.View.PromoWindow"
    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:localroot="clr-namespace:CataloGo"
    xmlns:local="clr-namespace:CataloGo.View"
    xmlns:localVm="clr-namespace:CataloGo.ViewModel"
    xmlns:localModel="clr-namespace:CataloGo.Model"
    mc:Ignorable="d"           
    d:DataContext="{d:DesignInstance localVm:PromoViewModel, d:IsDesignTimeCreatable=True}"
    Title="{Binding Path=Title}" SizeToContent="WidthAndHeight" MinWidth="640" MinHeight="480">

<Window.Resources>                        
    <CollectionViewSource
            Source="{Binding Path=Promos}"
            x:Key="PromoListingDataView" />
    <DataTemplate x:Key="PromoDetailTemplate" DataType="{x:Type localModel:Promo}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />                    
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="106" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Row="0" Grid.Column="0" 
                           Style="{StaticResource SmallTitleStyle}"
                           Margin="5">
                    Descripción:
            </TextBlock>

            <TextBlock Grid.Row="1" Grid.Column="0"
                           Style="{StaticResource SmallTitleStyle}" Margin="0,5,0,5">
                    Descuento (%):
            </TextBlock>
            <TextBox Name="PromoEntryForm" AutomationProperties.Name="Promo Description" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
                         Text="{Binding Path=FriendlyName, UpdateSourceTrigger=PropertyChanged}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" 
                     IsReadOnly="{Binding Path=IsReadOnly}" />

                <TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
                            Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=IsReadOnly}" >
                <TextBox.Text>
                    <Binding Path="DiscountPct" StringFormat="N2" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <ExceptionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </Grid>
    </DataTemplate>
</Window.Resources>
<Border Padding="20">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" MinHeight="300"/>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
                           Style="{StaticResource TitleStyle}"
                           Margin="5">
                    Promociones:
        </TextBlock>
        <Border Grid.Row="2" Grid.ColumnSpan="3" Style="{StaticResource BorderStyle}">
            <ListView Name="ListViewPromos" Grid.Row="1" Grid.ColumnSpan="3" ItemsSource="{Binding Source={StaticResource PromoListingDataView}}" 
                      IsSynchronizedWithCurrentItem="True"
                      SelectionChanged="OnSelectionChanged"
                      MouseDoubleClick="EnterEditMode"
                      IsEnabled="{Binding Path=IsReadOnly}">
                <ListView.View>
                    <GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Info de la promoción">
                        <GridViewColumn DisplayMemberBinding="{Binding Path=FriendlyName}" Header="Nombre de la promo" Width="300"/>                            
                        <GridViewColumn DisplayMemberBinding="{Binding Path=DiscountPct, StringFormat=N2}" Header="Descuento (%)" Width="150"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Border>
        <Grid Grid.Row="4" Grid.ColumnSpan="3">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />                    
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <ContentControl Name="PromoDetail" Grid.Row="0" Grid.ColumnSpan="2"
                    Content="{Binding Path=Current}"
                    ContentTemplate="{StaticResource PromoDetailTemplate}"
                    Margin="9,0,0,0" />

            <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
                <StackPanel.Resources>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Margin" Value="0,0,0,0"/>
                    </Style>
                </StackPanel.Resources>
                <Button Name="NewPromoButton" HorizontalAlignment="Right" Content="_Nueva" Style="{StaticResource AcctionButtonStyle}" 
                        Click="NewPromo" Visibility="{Binding Path=HideIfEditing}"/>
                <Button Name="EditPromoButton" HorizontalAlignment="Right" Content="_Modificar" Style="{StaticResource AcctionButtonStyle}" 
                        Click="EditPromo" Visibility="{Binding Path=HideIfEditing}"/>
                <Button Name="SubmitPromoButton" HorizontalAlignment="Right" Content="_Aceptar" Style="{StaticResource AcctionButtonStyle}"
                        Click="SubmitPromo" Visibility="{Binding Path=ShowIfEditing}"/>
                <Button Name="CancelEditButton" HorizontalAlignment="Right" Content="_Cancelar" Style="{StaticResource AcctionButtonStyle}"
                        Click="UndoEdit" Visibility="{Binding Path=ShowIfEditing}"/>
            </StackPanel>
        </Grid>
    </Grid>
</Border>

1 Ответ

0 голосов
/ 07 марта 2020

Используйте привязку элемента вместо относительного источника.

Сначала укажите имя для окна.

<Window x:Class="CataloGo.View.PromoWindow"
    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:localroot="clr-namespace:CataloGo"
    xmlns:local="clr-namespace:CataloGo.View"
    xmlns:localVm="clr-namespace:CataloGo.ViewModel"
    xmlns:localModel="clr-namespace:CataloGo.Model"
    mc:Ignorable="d"           
    x:Name="Window1"
    d:DataContext="{d:DesignInstance localVm:PromoViewModel, d:IsDesignTimeCreatable=True}"
    Title="{Binding Path=Title}" SizeToContent="WidthAndHeight" MinWidth="640" MinHeight="480">

Код привязки элемента в xaml

<TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
                            Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
                         Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding  ElementName=Window1, Path=DataContext.IsReadOnly}" >
                <TextBox.Text>
                    <Binding Path="DiscountPct" StringFormat="N2" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <ExceptionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
...