WPF: OneWay-Binding durch Benutzereingabe zerstört?

09/07/2009 - 23:10 von Michaela Meier | Report spam
Hallo,

Meine Nerven, meine Nerven. Jetzt dachte ich schon, ich hàtte die Sache
mit dem Binding endlich verstanden und dann passiert sowas :-(

Mit dem unten angehàngte Minimal-Projekt làßt sich leicht
nachvollziehen, womit ich zu kàmpfen habe.

Bedienungsanleitung:
Ein Klick auf "neues Item" generiert jeweils einen neuen Eintrag und
zeigt diesen an. Mit "+/-1" kann man in der so erzeugten Liste vor- und
zurücklaufen.

Dabei ist A - wie angezeigt - per TwoWay-Binding an die Liste
angeschlossen, B im OneWay-Modus.

Damit das Verhàngnis seinen Lauf nimmt, àndere man nun einen Eintrag von
z.B. A5/B5 in A55555/B55555 und laufe danach wieder mit "+/-1" durch die
Liste.

Warum, um alles in der Welt, ist TextBox B nun "kaputt"?
A wird weiterhin angezeigt, die Änderung wurde entsprechend des
TwoWay-Modus auch übernommen. In der Liste (wenn man mal in den Code
schaut) steht nach wie vor der alte Wert von B - völlig korrekt, denn es
ist ja OneWay. Aber warum wird das nicht mehr angezeigt?

Kann mir bitte jemand mit einfachen Worten erklàren, wieso dies
geschieht - und (mir im Augenblick noch viel wichtiger) wie ich das
reparieren kann?
TwoWay kommt leider nicht in Frage. Die Änderung soll im echten Projekt
nàmlich erst dann in die Liste übernommen werden (oder auch nicht), wenn
der Benutzer auf "Speichern? ja/nein" geantwortet hat.

Danke





C#:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;


namespace WpfApplication1
{
/// <summary>
/// Interaktionslogik für Window1.xaml
/// </summary>
public partial class Window1 : Window
{


private List<AB> _ablist = new List<AB>();
public List<AB> AbList
{
get { return _ablist; }
set { _ablist = value; }
}


private AB _selectedab;
public AB SelectedAB
{
get { return _selectedab; }
set
{
_selectedab = value;
}
}


private int _index;


public Window1()
{
InitializeComponent();
}


private void Button_Click(object sender, RoutedEventArgs e)
{
int i = _ablist.Count;
_ablist.Add(new AB(string.Format("A{0}", i), string.Format
("B{0}", i)));
SelectedAB = _ablist[i];
DataContext = null;
DataContext = this;
_index = i;
}


private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (_index <= 0)
{
return;
}
_index--;
SelectedAB = _ablist[_index];
DataContext = null;
DataContext = this;
}


private void Button_Click_2(object sender, RoutedEventArgs e)
{
if (_index >= _ablist.Count - 1)
{
return;
}
_index++;
SelectedAB = _ablist[_index];
DataContext = null;
DataContext = this;
}
}
public class AB : INotifyPropertyChanged
{
private string _a;
public string A
{
get { return _a; }
set
{
_a = value;
NotifyPropertyChanged("A");
}
}

private string _b;
public string B
{
get { return _b; }
set
{
_b = value;
NotifyPropertyChanged("B");
}
}

public AB(string a, string b)
{
_a = a;
_b = b;
}

public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs
(info));
}
}
}
}



XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/...tion"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0" Margin="5">A (TwoWay):
</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1" Margin="5" Text="{Binding
Path=SelectedAB.A}" />
<TextBlock Grid.Row="1" Grid.Column="0" Margin="5">B (OneWay):
</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" Margin="5" Text="{Binding
Path=SelectedAB.B, Mode=OneWay}" />
<Button Grid.Row="2" Content="neues Item" Click="Button_Click"
Margin="5" Grid.ColumnSpan="2" />
<Button Grid.Row="3" HorizontalAlignment="Left" Width="75"
Content="-1" Click="Button_Click_1" Margin="5,5,0,5" Grid.ColumnSpan="2" />
<Button Grid.Row="3" Content="+1" Width="75"
HorizontalAlignment="Right" Click="Button_Click_2" Margin="0,5,5,5"
Grid.Column="1" />
</Grid>
</Window>
 

Lesen sie die antworten

#1 Carl-Christian Schaffert
10/07/2009 - 06:48 | Warnen spam
Hallo Michaela,


Warum, um alles in der Welt, ist TextBox B nun "kaputt"?
A wird weiterhin angezeigt, die Änderung wurde entsprechend des
TwoWay-Modus auch übernommen. In der Liste (wenn man mal in den Code
schaut) steht nach wie vor der alte Wert von B - völlig korrekt, denn es
ist ja OneWay. Aber warum wird das nicht mehr angezeigt?

Kann mir bitte jemand mit einfachen Worten erklàren, wieso dies
geschieht - und (mir im Augenblick noch viel wichtiger) wie ich das
reparieren kann?
TwoWay kommt leider nicht in Frage. Die Änderung soll im echten Projekt
nàmlich erst dann in die Liste übernommen werden (oder auch nicht), wenn
der Benutzer auf "Speichern? ja/nein" geantwortet hat.



Kurz und Schmerzlos *g*:
Bei OneWay werden nach Änderung im Zielobjekt die Verbindungen zum
Quellobjekt gekappt... daher passiert da nichts mehr ;-)

Die für dich besser Lösung würde darin liegen TwoWay Bindungen zu benutzen
und den UpdateSource Trigger auf Explicit festzulegen. Desweiteren wàre es
besser in deinen Entitàten auch das IEditable Interface zu implementieren,
dabei kannst du dir auch Clones erstellen, womit du ne ganze Ecke flexibler
wirst. Wàre letztendlich auch die durchgàngigere Lösung.

Hier kannst auch zum UpdateSourceTrigger etwas nachlesen:
http://msdn.microsoft.com/de-de/lib...ource.aspx

Viele Grüße Carl

Ähnliche fragen