我的双向绑定问题从源到目标都很好,但目标上的更新永远不会传播到源。
我在DataGrid中显示一个自定义UserControl,显示星级评分:
* View.xaml
<DataGrid x:Name="Datagrid" Style="{StaticResource ResourceKey=DataGridStyle}" Grid.Row="1" AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding Path=GameList}" SelectedItem="{Binding Path=SelectedGame}" SelectionChanged="datagrid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding Title}" />
<DataGridTemplateColumn Header="Rating" SortMemberPath="Rating">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:RatingControl NumberOfStars="{Binding Path=Rating}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
* RatingControl.xaml.cs
public partial class RatingControl : UserControl
{
#region Public Dependency properties
public int NumberOfStars
{
get { return (int)GetValue(NumberOfStarsProperty); }
set { if ((int)GetValue(NumberOfStarsProperty) != value) { SetValue(NumberOfStarsProperty, value); } }
}
public static readonly DependencyProperty NumberOfStarsProperty =
DependencyProperty.Register("NumberOfStars", typeof(int), typeof(RatingControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRatingChanged));
#endregion
[...]
private void Border_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
NumberOfStars = tempRating;
}
* Game.cs
public class Game : INotifyPropertyChanged
{
private int _rating;
public int Rating
{
get { return _rating; }
set { _rating = value; RaiseChangedEvent("Rating"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseChangedEvent(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
当我点击RatingControl上的星号时,我更新了NumberOfStars依赖项属性,但我的模型的Rating属性未更新。我错过了什么?
答案 0 :(得分:2)
使用单元格模板等时,这似乎是DataGrid中的一个错误。无论出于何种原因,除非明确设置UpdateSourceTrigger,否则不会更新源代码。奇怪的是,UpdateSourceTrigger将被设置为&#39; Default&#39;但是它的行为设置为&#39;明确&#39;。
为了演示错误或意外行为,我已经举了你的例子,并稍微调整了一下。您可以单击各种用户控件,并查看默认的双向绑定是否适用于所有内容,但网格中的项目除外。
注意:
这个答案的其余部分只是一个代码转储,所以如果你对这个答案感到满意,请不要再读了。
<强> MainWindow.xaml 强>
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<DataGrid x:Name="grid" Grid.Row="1" AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding Path=GameList}" MinHeight="100" >
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding Title}" />
<DataGridTemplateColumn Header="Rating">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:MyControl Number="{Binding Path=Rating}" Loaded="TemplateControlLoaded" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<ListBox Name="lst" ItemsSource="{Binding GameList}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<local:MyControl Number="{Binding Rating}" />
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<local:MyControl x:Name="ctl" Loaded="MyControl_Loaded" Number="{Binding Path=Rating}" />
</StackPanel>
</Window>
<强> MainWindow.xaml.cs 强>
// ============================================================================================================================
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
grid.DataContext = new MyClassContainer();
lst.DataContext = new MyClassContainer();
ctl.DataContext = new MyClass();
}
private void TemplateControlLoaded(object sender, RoutedEventArgs e)
{
BindingExpression be = (sender as FrameworkElement).GetBindingExpression(MyControl.NumberProperty);
Console.WriteLine("Template trigger = " + be.ParentBinding.UpdateSourceTrigger.ToString());
}
private void MyControl_Loaded(object sender, RoutedEventArgs e)
{
BindingExpression be = (sender as FrameworkElement).GetBindingExpression(MyControl.NumberProperty);
Console.WriteLine("Instance trigger = " + be.ParentBinding.UpdateSourceTrigger.ToString());
}
}
// ============================================================================================================================
public class MyClassContainer
{
public List<MyClass> GameList { get; set; }
public MyClassContainer()
{
GameList = new List<MyClass>();
GameList.Add(new MyClass()
{
Rating = 150
});
}
}
// ============================================================================================================================
public class MyClass : INotifyPropertyChanged
{
private int _Rating;
public int Rating
{
get { return _Rating; }
set
{
_Rating = value; NotifyChange("Rating");
Console.WriteLine("changed!");
}
}
private void NotifyChange(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
<强> MyControl.xaml 强>
<UserControl x:Class="WpfApplication1.MyControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" x:Name="this">
<Grid Background="Red" PreviewMouseDown="Grid_PreviewMouseDown">
<TextBlock Text="{Binding ElementName=this, Path=Number}" FontWeight="Bold" />
</Grid>
</UserControl>
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public static readonly DependencyProperty NumberProperty = DependencyProperty.Register("Number", typeof(int), typeof(MyControl), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public int Number
{
get { return (int)GetValue(NumberProperty); }
set { SetValue(NumberProperty, value); }
}
private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
this.Number = 1000;
}
}
答案 1 :(得分:0)
将 StaticResource 更改为 DynamicResource 。