我发布了关于codereview的问题(https://codereview.stackexchange.com/questions/124300/reactiveui-and-wpf-reusing-a-value-to-update-multiple-properties)。我在回答这个问题上的最新努力使我得到了下面的代码,这似乎工作,但我不知道什么机制实际上提供了功能!ReactiveUI - 为什么这些{绑定}工作?
MainWindow.xaml
<Window x:Class="TestHumanName.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="392" Width="391">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Label Content="Full" />
<TextBox Width="100" Text="{Binding Full, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Go"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Title" />
<TextBox Width="100" Text="{Binding NameObject.Title, Mode=OneWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="First" />
<TextBox Width="100" Text="{Binding NameObject.First, Mode=OneWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Middle" />
<TextBox Width="100" Text="{Binding NameObject.Middle, Mode=OneWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Last" />
<TextBox Width="100" Text="{Binding NameObject.Last, Mode=OneWay}"/>
</StackPanel>
</StackPanel>
</Window>
MainWindow.xaml.cs:
using System.Windows;
using TestHumanName.ViewModel;
namespace TestHumanName
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}
MainViewModel.cs
public class MainViewModel : ReactiveObject
{
public MainViewModel()
{
this.WhenAnyValue(x => x.Full).Where(x => x != null).Select(x => ParseName(x))
.ToProperty(this, x => x.NameObject, out __oapName);
}
private string __sFull;
public string Full
{
get { return __sFull; }
set { this.RaiseAndSetIfChanged(ref __sFull, value); }
}
readonly ObservableAsPropertyHelper<Name> __oapName;
public Name NameObject { get { return __oapName.Value; } }
//NAME PARSING CODE BELOW THIS LINE
public class Name
{
public string Title { get; set; }
public string First { get; set; }
public string Middle { get; set; }
public string Last { get; set; }
public string Suffix { get; set; }
}
public Name ParseName(string s)
{
Name n = new Name();
// Split on period, commas or spaces, but don't remove from results.
List<string> parts = Regex.Split(s, @"(?<=[., ])").ToList();
// Remove any empty parts
for (int x = parts.Count - 1; x >= 0; x--)
if (parts[x].Trim() == "")
parts.RemoveAt(x);
if (parts.Count > 0)
{
// Might want to add more to this list
string[] prefixes = { "mr", "mrs", "ms", "dr", "miss", "sir", "madam", "mayor", "president" };
// If first part is a prefix, set prefix and remove part
string normalizedPart = parts.First().Replace(".", "").Replace(",", "").Trim().ToLower();
if (prefixes.Contains(normalizedPart))
{
n.Title = parts[0].Trim();
parts.RemoveAt(0);
}
}
if (parts.Count > 0)
{
// Might want to add more to this list, or use code/regex for roman-numeral detection
string[] suffixes = { "jr", "sr", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv" };
// If last part is a suffix, set suffix and remove part
string normalizedPart = parts.Last().Replace(".", "").Replace(",", "").Trim().ToLower();
if (suffixes.Contains(normalizedPart))
{
n.Suffix = parts.Last().Replace(",", "").Trim();
parts.RemoveAt(parts.Count - 1);
}
}
// Done, if no more parts
if (parts.Count == 0)
return n;
// If only one part left...
if (parts.Count == 1)
{
// If no prefix, assume first name, otherwise last
// i.e.- "Dr Jones", "Ms Jones" -- likely to be last
if (n.Title == "")
n.First = parts.First().Replace(",", "").Trim();
else
n.Last = parts.First().Replace(",", "").Trim();
}
// If first part ends with a comma, assume format:
// Last, First [...First...]
else if (parts.First().EndsWith(","))
{
n.Last = parts.First().Replace(",", "").Trim();
for (int x = 1; x < parts.Count; x++)
n.First += parts[x].Replace(",", "").Trim() + " ";
n.First = n.First.Trim();
}
// Otherwise assume format:
// First [...Middle...] Last
else
{
n.First = parts.First().Replace(",", "").Trim();
n.Last = parts.Last().Replace(",", "").Trim();
for (int x = 1; x < parts.Count - 1; x++)
n.Middle += parts[x].Replace(",", "").Trim() + " ";
if (n.Middle != null) n.Middle = n.Middle.Trim();
}
return n;
}
}
}
我不明白的是我如何替换NameObject
属性的值,并且{Binding ...}s
神奇地知道他们应该更新。当然,替换NameObject
属性的内容不会在它的子属性上调用OnPropertyChanged ... Name
类甚至不实现INotifyPropertyChanged。
那么,这是怎么回事?
谢谢。
,窗口有一个Paint事件时,窗口得到更新控制。当数据在标准Net Library类中更改时,Paint事件被调用。如果你建立你自己的类,那么你必须调用Window Paint Event。 – jdweng
我看不出涂料事件与{绑定}有什么关系? –
这不是不工作的绑定。这是没有发生的更新。更改绑定不会自动更改窗口中显示的内容。必须调用Paint来指示窗口更新。 – jdweng