我没有找到任何可以帮助我解决这个问题的东西。我正在使用“MVVM”来构建WPF测试应用程序。当消息显示在ListBox中时,应用程序应该根据特定的正则表达式模式读取消息并创建链接/按钮,并允许用户单击它们以采取进一步的操作。
我遇到的问题是在将消息绑定到ListBox项之后创建这样的按钮时,我希望绑定工作或抛出错误,但这些都没有发生,现在我很困惑为什么。我唯一的猜测就是“绑定”无法找到命令并且无法慷慨地失败。
所以关于我做错了什么的想法,或者我怎么能做到这一点?
所以这是代码:
XAML PART
<ListBox x:Name="lsbMessages" Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Messages}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock local:TextBlockExtension.FormattedText="{Binding}" />
<TextBlock Text="{Binding Path=Date}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
背后的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
视图模型:
public class TestViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Message> _messages;
public ObservableCollection<Message> Messages
{
get
{
if (_messages == null)
{
_messages = new ObservableCollection<Message>();
}
return _messages;
}
}
private string _message;
public string Message {
get
{
return this._message;
}
set
{
if (value != this._message)
{
this._message = value;
NotifyPropertyChanged();
}
}
}
private List<string> _filters = new List<string>();
public IAsyncCommand ChannelCommand { get; set; }
public TestViewModel()
{
ChannelCommand = new AsyncCommand(ChannelSelected);
PropertyChanged += TestViewModel_PropertyChanged;
_filters.Add(@"(?:#(\w+))");
_filters.Add(@"(?:@(\w+)(?:\s))");
_filters.Add(@"(#(\d{1,2}\/\d{1,2}\/\d{1,4})(\s\d{1,2}:\d{1,2}(?:PM|AM)?))");
}
private async void TestViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Message":
await RunFilters();
break;
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public async Task ChannelSelected(object parameter)
{
System.Windows.MessageBox.Show(parameter.ToString());
}
public async Task RunFilters()
{
foreach(string filter in _filters)
{
await Filter(filter);
}
}
public async Task Filter(string filter)
{
Regex reg = new Regex(filter);
var matches = reg.Matches(Message);
foreach (Match match in matches)
{
if (!Finds.Contains(match.Value))
{
Finds.Add(match.Value);
}
}
}
public async Task AddTags(Message message)
{
foreach (string filter in _filters)
{
Regex reg = new Regex(filter);
var matches = reg.Matches(Message);
foreach (Match match in matches)
{
Tag tag = new Tag()
{
Type = "Channel"
,
Value = match.Value
};
message.Tags.Add(tag);
}
}
}
}
TextBlock EXTENSION:
public static class TextBlockExtension
{
public static Message GetFormattedText(DependencyObject obj)
{ return (Message)obj.GetValue(FormattedTextProperty); }
public static void SetFormattedText(DependencyObject obj, Message value)
{ obj.SetValue(FormattedTextProperty, value); }
public static readonly DependencyProperty FormattedTextProperty =
DependencyProperty.RegisterAttached("FormattedText", typeof(Message), typeof(TextBlockExtension),
new PropertyMetadata(null, (sender, e) =>
{
Message message = e.NewValue as Message;
var textBl = sender as TextBlock;
if (textBl != null)
{
textBl.Inlines.Clear();
foreach (Tag tag in message.Tags)
{
Regex regx = new Regex($"({tag.Value})", RegexOptions.IgnoreCase);
var str = regx.Split(message.Body);
for (int i = 0; i < str.Length; i++)
if (i % 2 == 0)
textBl.Inlines.Add(new Run { Text = str[i] });
else
{
Hyperlink link = new Hyperlink { CommandParameter = str[i]};
link.Inlines.Add(str[i]);
switch (tag.Type)
{
case "channel":
Binding myBinding = new Binding("DataContext.ChannelCommand")
{
RelativeSource = new RelativeSource() { AncestorType = typeof(Window), Mode=RelativeSourceMode.FindAncestor }
};
link.SetBinding(Hyperlink .CommandProperty, myBinding);
break;
}
textBl.Inlines.Add(link);
}
}
}
}));
}
对于命令实现,我使用了此处描述的代码https://msdn.microsoft.com/en-us/magazine/dn630647.aspx,并添加了以下支持参数:
private readonly Func<object, Task> _commandWithParameter;
public AsyncCommand(Func<object, Task> command)
{
_commandWithParameter = command;
}
public override Task ExecuteAsync(object parameter)
{
if (_commandWithParameter != null)
{
return _commandWithParameter(parameter);
}
else
{
return _command();
}
}
希望我能在这里得到一切。