Laden...

Databinding OneWayToSource funktioniert nicht

Erstellt von hypersurf vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.072 Views
H
hypersurf Themenstarter:in
523 Beiträge seit 2008
vor 12 Jahren
Databinding OneWayToSource funktioniert nicht

Hallo Leute,

ich arbeite mit dem 3.5er Framework zur Zeit an einem Editor, in dem der Benutzer verschiedene grafische Elemente verschieben, verändern und miteinander verbinden kann.

Leider funktionieren einige Databindings nicht und ich kann nicht nachvollziehen warum nicht. Vielleicht habt Ihr eine Idee 😃

Die Oberfläche enthält verschiedene Objekte, die alle in einer Collection meines ViewModels enthalten sind. Über DataTemplates werden die verschiedenen Objekte in dem ItemsControl dargestellt:


<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Hidden">
                    <ItemsControl ItemsSource="{Binding Path=VisualItems}"
                                  x:Name="ItemsContainer">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <Canvas AllowDrop="true"
                                        x:Name="MyCanvas"
                                        Loaded="MyCanvas_Loaded"
                                        Background="White"
                                        Height="10000"
                                        PreviewMouseLeftButtonDown="MyCanvas_PreviewMouseLeftButtonDown"
                                        PreviewMouseLeftButtonUp="MyCanvas_PreviewMouseLeftButtonUp"
                                        PreviewMouseMove="MyCanvas_PreviewMouseMove">
                                    
                                        <Canvas.LayoutTransform>
                                            <ScaleTransform ScaleX="{Binding Path=CurrentZoomfaktor}"
                                                            ScaleY="{Binding Path=CurrentZoomfaktor}"/>
                                        </Canvas.LayoutTransform>
                                    </Canvas>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>

                        <ItemsControl.ItemTemplateSelector>
                            <local:ControlTemplateSelector/>
                        </ItemsControl.ItemTemplateSelector>

                        <ItemsControl.ItemContainerStyle>
                            <Style TargetType="{x:Type ContentPresenter}">
                                <Setter Property="Canvas.Left" Value="{Binding Path=X, Mode=TwoWay}"/>
                                <Setter Property="Canvas.Top" Value="{Binding Path=Y, Mode=TwoWay}"/>
                            </Style>
                        </ItemsControl.ItemContainerStyle>
                    </ItemsControl>
                </ScrollViewer>


Das betroffene Datatemplate (es geht speziell um die Breite und Höhe des Borders):

Width="{Binding Path=TitleWidth, Mode=OneWayToSource}"
Height="{Binding Path=TitleHeight, Mode=OneWayToSource}"


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:Workflowdesigner"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <local:PointsCollectionConverter x:Key="converter"/>
    <local:TextToVisibilityConverter x:Key="TextVisibleConverter"/>
    
    <DataTemplate x:Key="Connections.TwoPoints">
        <Canvas Height="0" Width="0">
            <Polygon Stroke="Black" 
                     StrokeLineJoin="Round"
                     Points="{Binding Path=PointsLinie, Converter={StaticResource converter}}"/>
            <Polygon Stroke="Red" Fill="Red" 
                     Points="{Binding Path=PointsDreieck, Converter={StaticResource converter}}"/>
            
            <!-- OneWayToSource sendet den Wert immer nur zur gebundenen Instanz zurück -->
            <Border Canvas.Left="{Binding Path=TitleX}"
                    Canvas.Top="{Binding Path=TitleY}"
                    Width="{Binding Path=TitleWidth, Mode=OneWayToSource}"
                    Height="{Binding Path=TitleHeight, Mode=OneWayToSource}"
                    BorderBrush="#5F5F5F"
                    Background="#E9E9E9"
                    BorderThickness="1"
                    Visibility="{Binding Path=Title, Converter={StaticResource TextVisibleConverter}}">

                <TextBlock Text="{Binding Path=Title}"
                           Margin="5"
                           FontWeight="Bold"
                           Background="#E9E9E9">
                </TextBlock>
            </Border>
        </Canvas>
    </DataTemplate>
</ResourceDictionary>

Wenn ich jetzt die Attribute TitleWidth und TitleHeight in meinem ViewModel abfrage, sind diese beim ersten Mal 0,00 beim zweiten Mal NaN.


        private double _TitleWidth;
        public double TitleWidth
        {
            get { return _TitleWidth; }
            set { 
                    _TitleWidth = value;
                    this.ValueChanged("TitleWidth");
                }
        }

        private double _TitleHeight;
        public double TitleHeight
        {
            get { return _TitleHeight; }
            set { 
                    _TitleHeight = value;
                    this.ValueChanged("TitleHeight");
                }
        }

Wenn ich den Inhalt (also auch die Breite des Textblocks ändere) müsste die das View die beiden Werte ja an das ViewModel zurückmelden. Tut es aber nicht.


            this.TitleX = this.StartpunktX + (this.EndpunktX - this.StartpunktX) - this.TitleWidth / 2;
            this.TitleY = this.StartpunktY + (this.EndpunktY - this.StartpunktY) - this.TitleHeight / 2;

Implementierung der INotifyPropertyChanged-Schnittstelle ist selbstverständlich vorhanden und funktioniert auch bei den anderen Attributen.


INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void ValueChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

Habt Ihr eine Idee woran das liegen könnte?

109 Beiträge seit 2011
vor 12 Jahren

Hallo,

nur zum Verständnis: wenn du die Größe änderst wird nicht in die Setter der beiden Properties gesprungen, richtig?
Hast du schon mal im Ausgabefenster geschaut ob es da irgendwelche Fehlermeldungen zu sehen gibt?

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

6.862 Beiträge seit 2003
vor 12 Jahren

Hallo,

dein Binding funktioniert tadellos. Erst steht 0 drin, das ist der Initialisierungswert und dann wird über das Binding Double.NaN gesetzt und das ist der Wert der Standard bei der TextBox ist, sollte Height und Width nicht anders gesetzt werden.

Und dass sich danach nichts mehr tut ist normal. Du benutzt für dein Vorhaben die falschen Properties. Nicht umsonst steht bei Width und Height in der Doku

The return value of this property is always the same as any value that was set to it. Das wird sich nie ändern. In der Doku steht erklärt warum das so ist und auch was du benutzen musst für das was du vorhast.[/

Baka wa shinanakya naoranai.

Mein XING Profil.

H
hypersurf Themenstarter:in
523 Beiträge seit 2008
vor 12 Jahren

Das direkte Binden einer ReadOnly-Property geht trotz des OneWayToSource nicht:


ActualWidth="{Binding Path=TitleWidth, Mode=OneWayToSource}"
ActualHeight="{Binding Path=TitleHeight, Mode=OneWayToSource}"

Die Eigenschaft "ActualWidth" ist schreibgeschützt und kann nicht von einem Markup aus festgelegt werden.

Dieses Verhalten macht doch keinen Sinn, wenn der Binding-Mode schon auf OneWayToSource steht. Das scheint ein Bug vom Framework zu sein: Siehe hier

Edit sagt: Hier ist die Lösung die ich nun verwende