'View don't change the value of property until I change xaml option of property one times

WPF, C#, .net framework 4.8,

Why wasn't the View-property update applied? View didn't apply value(but it get the value like in Image 2 with break-point) from ViewModel until I change xaml under debug(delete/add some options in XAML View-property whitch bind to the ViewModel-Property). After this changing all work properly. I share link to video with will be more handy then 1000 words. link Video

I have a problem updating the view property. It don't work until I change xaml option of XAML property.

  1. I create a View dynamically(Image_1 - 1), and after that I create a dynamic ViewModel(Image_1 - 2) and bind them(Image_1 - 3).
var view = new MapControlText() { Width = 300, Height = 50 };
var viewModel = new MapModelText(new MapBindControl()) { Position = new Rect(0, 0, view.Width, view.Height) };
viewModel.MapBindControl = new MapBindControlOne();
view.DataContext = viewModel;
Content = new MapContentB2(viewModel, view);
  1. Add View to main View(Image_2).

Image_2

I bind changing of the text and size of view. When text is changing, I recalculate current size of text and inform View about changing(Image_3 - 2) of width. even breack-point(Image_3 - 3) of property detect enter to the getter of property(This ViewModel-Property bind only with this View-Property). Buuut nothing is happening until I change any option of binding this property(or delete or add), after this all changing of size work fine. I don't know what is the problem.

private const double MIN_WIDTH_LOCK = 200; 

public double WidthBlock
{
    get => Position.Width;
    private set
    {
        if (value < MIN_WIDTH_LOCK)
            _position.Width = MIN_WIDTH_LOCK;
        else
            _position.Width = value;
        OnPropertyChanged(nameof(WidthBlock));
        OnPropertyChanged(nameof(WidthTextBlock));
    }
}

Image_3


I was trying to add some combination of binding-property parameters, but the result is the same.

  • Binding Path=WidthBlock, UpdateSourceTrigger=PropertyChanged, Mode=OneWay
  • Binding Path=WidthBlock, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay
  • Binding Path=WidthBlock

    <UserControl x:Class="MapControls.MapControlText"
                 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:MapControls" xmlns:zoompanel="clr-namespace:ZoomPanel;assembly=ZoomPanel"
                 mc:Ignorable="d" 
                 d:DesignWidth="300" d:DesignHeight="80"  
                 Width="{Binding Path=WidthBlock, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Height="{Binding Path=Position.Height}">
        <UserControl.Resources>
            <ResourceDictionary>
                <Style x:Key="sContentControl" TargetType="ContentControl">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=Status}" Value="Edited">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <TextBox Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" FontSize="30" BorderThickness="0"
                                                    VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
                                                    VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=Status}" Value="Selected">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <TextBlock Text="{Binding Path=Text}" Focusable="True" Background="Transparent" FontSize="30" 
                                                    VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=Status}" Value="None">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <TextBlock Text="{Binding Path=Text}" Focusable="True" Background="Transparent" FontSize="30" 
                                                    VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
                <Style x:Key="sRectangle" TargetType="Rectangle">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=Status}" Value="None">
                            <Setter Property="Stroke" Value="Gray"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=Status}" Value="Edited">
                            <Setter Property="Stroke" Value="Blue"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=Status}" Value="Selected">
                            <Setter Property="Stroke" Value="Green"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ResourceDictionary>
        </UserControl.Resources>
        <Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
            <Canvas VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                <Rectangle x:Name="xRectangle" Fill="WhiteSmoke" 
                        StrokeThickness="3"
                        Style="{StaticResource sRectangle}"
                        Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MapControlText}, AncestorLevel=1},Path=Width}" 
                        Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MapControlText}, AncestorLevel=1}, Path=Height}"
                        RadiusX="20"
                        RadiusY="{Binding RelativeSource={RelativeSource Self}, Path=RadiusX}"/>
            </Canvas>
            <ContentControl Style="{StaticResource sContentControl}"
                VerticalAlignment="Center" HorizontalAlignment="Center" 
                Height="40"  Width="{Binding Path=WidthTextBlock, UpdateSourceTrigger=PropertyChanged}"/>
        </Grid>
    </UserControl>

Could someone explain me, What I do wrong?



Solution 1:[1]

I found a solution and thought there was a bug in framework. The solution is to create a ViewModel before the View and install View.DataContext at the same time as creating the View. Error - If we create a view and only then set the DataContext property, the view components have already been created, and the new DataContext value does not update some OnPropertyChanged links or does not execute them. And when I changed XAML under debug, all started wark because components and them bindings reinitializated.

Before was like this (with bug):

var view = new MapControlText() { Width = 300, Height = 50 };
var viewModel = new MapModelText(new MapBindControl()) { Position = new Rect(0, 0, view.Width, view.Height) };
viewModel.MapBindControl = new MapBindControlOne();
view.DataContext = viewModel;

Now it is like this:

var viewModel = new MapModelText(new MapBindControl())
{
    Position = new Rect(0, 0, 300, 50),
    MapBindControl = new MapBindControlOne()
};
var view = new MapControlText() { DataContext = viewModel };

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ouflak