1
0
mirror of synced 2024-11-25 04:03:08 +01:00

More UI work, mock message events

This commit is contained in:
PsychoMark 2016-06-20 12:30:03 +02:00
parent 9a864f14f1
commit e6fa2ee1d9
15 changed files with 349 additions and 26 deletions

View File

@ -10,7 +10,15 @@ namespace PettingZoo.Infrastructure
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void RaiseOtherPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

View File

@ -7,5 +7,22 @@
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Exchange { get; set; }
public string RoutingKey { get; set; }
public static ConnectionInfo Default()
{
return new ConnectionInfo()
{
Host = "localhost",
Port = 5672,
VirtualHost = "/",
Username = "guest",
Password = "guest",
RoutingKey = "#"
};
}
}
}

View File

@ -2,7 +2,20 @@
namespace PettingZoo.Model
{
public class MessageReceivedEventArgs : EventArgs
{
public MessageInfo MessageInfo { get; private set; }
public MessageReceivedEventArgs(MessageInfo messageInfo)
{
MessageInfo = messageInfo;
}
}
public interface IConnection : IDisposable
{
event EventHandler<MessageReceivedEventArgs> MessageReceived;
}
}

22
Model/MessageInfo.cs Normal file
View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace PettingZoo.Model
{
public class MessageInfo
{
public string RoutingKey { get; set; }
public byte[] Body { get; set; }
public Dictionary<string, string> Properties;
public string ContentType
{
get
{
return Properties != null && Properties.ContainsKey("content-type")
? Properties["content-type"]
: "";
}
}
}
}

View File

@ -1,15 +1,50 @@
namespace PettingZoo.Model
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PettingZoo.Model
{
public class RabbitMQClientConnection : IConnection
{
private readonly CancellationTokenSource timer;
public RabbitMQClientConnection(ConnectionInfo connectionInfo)
{
timer = new CancellationTokenSource();
var token = timer.Token;
Task.Run(() =>
{
while (true)
{
if (token.IsCancellationRequested)
break;
if (MessageReceived != null)
MessageReceived(null, new MessageReceivedEventArgs(new MessageInfo()
{
RoutingKey = "test",
Body = Encoding.UTF8.GetBytes("{ \"hello\": \"world\" }"),
Properties = new Dictionary<string, string>
{
{ "content-type", "application/json" },
{ "classType", "LEF.Messaging.Internal.ActieNewMessage" }
}
}));
Thread.Sleep(1000);
}
}, token);
}
public void Dispose()
{
timer.Cancel();
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
}
}

View File

@ -54,6 +54,10 @@
</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=4.2.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>packages\AutoMapper.4.2.1\lib\net45\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SimpleInjector, Version=3.1.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>packages\SimpleInjector.3.1.5\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
@ -101,6 +105,8 @@
<Compile Include="Model\IConnectionFactory.cs" />
<Compile Include="Model\IConnectionInfoBuilder.cs" />
<Compile Include="Model\ConnectionInfo.cs" />
<Compile Include="Model\MessageBodyRenderer.cs" />
<Compile Include="Model\MessageInfo.cs" />
<Compile Include="Model\RabbitMQClientConnection.cs" />
<Compile Include="Model\RabbitMQClientConnectionFactory.cs" />
<Compile Include="ViewModel\ConnectionViewModel.cs" />

View File

@ -158,5 +158,41 @@ namespace PettingZoo.Properties {
return ResourceManager.GetString("MainWindowTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Body.
/// </summary>
public static string PanelTitleBody {
get {
return ResourceManager.GetString("PanelTitleBody", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Properties.
/// </summary>
public static string PanelTitleProperties {
get {
return ResourceManager.GetString("PanelTitleProperties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Name.
/// </summary>
public static string PropertyName {
get {
return ResourceManager.GetString("PropertyName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Value.
/// </summary>
public static string PropertyValue {
get {
return ResourceManager.GetString("PropertyValue", resourceCulture);
}
}
}
}

View File

@ -150,4 +150,16 @@
<data name="MainWindowTitle" xml:space="preserve">
<value>Petting Zoo - a RabbitMQ Message Viewer</value>
</data>
<data name="PanelTitleBody" xml:space="preserve">
<value>Body</value>
</data>
<data name="PanelTitleProperties" xml:space="preserve">
<value>Properties</value>
</data>
<data name="PropertyName" xml:space="preserve">
<value>Name</value>
</data>
<data name="PropertyValue" xml:space="preserve">
<value>Value</value>
</data>
</root>

View File

@ -11,6 +11,16 @@
</Style>
<!-- Explicit styling -->
<Style x:Key="SidePanel" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Style>
<Style x:Key="HeaderLabel" TargetType="{x:Type Label}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.InactiveCaptionBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveCaptionTextBrushKey}}"/>
</Style>
<Style x:Key="FooterPanel" TargetType="{x:Type Panel}">
<Setter Property="Margin" Value="0,8,0,0" />
</Style>
@ -23,4 +33,11 @@
<Style x:Key="Form" TargetType="{x:Type infrastructure:GridLayout}">
<Setter Property="ChildMargin" Value="4"/>
</Style>
<Style x:Key="Properties" TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="HorizontalGridLinesBrush" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="VerticalGridLinesBrush" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Style>
</ResourceDictionary>

View File

@ -17,7 +17,7 @@
FocusManager.FocusedElement="{Binding ElementName=HostTextBox}">
<DockPanel Margin="8">
<UniformGrid DockPanel.Dock="Bottom" HorizontalAlignment="Right" Rows="1" Columns="2" Style="{StaticResource FooterPanel}">
<Button IsDefault="True" Content="{x:Static res:Resources.ButtonOK}" Style="{StaticResource FooterButton}"/>
<Button IsDefault="True" Content="{x:Static res:Resources.ButtonOK}" Style="{StaticResource FooterButton}" Command="{Binding OkCommand}"/>
<Button IsCancel="True" Content="{x:Static res:Resources.ButtonCancel}" Style="{StaticResource FooterButton}"/>
</UniformGrid>
@ -37,18 +37,18 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="{x:Static res:Resources.ConnectionHost}"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding ConnectionInfo.Host}" Name="HostTextBox" />
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Host}" Name="HostTextBox" />
<Label Grid.Column="0" Grid.Row="1" Content="{x:Static res:Resources.ConnectionPort}"/>
<Label Grid.Column="0" Grid.Row="2" Content="{x:Static res:Resources.ConnectionVirtualHost}"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding ConnectionInfo.VirtualHost}"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding VirtualHost}"/>
<Label Grid.Column="0" Grid.Row="3" Content="{x:Static res:Resources.ConnectionUsername}"/>
<TextBox Grid.Column="1" Grid.Row="3" Text="{Binding ConnectionInfo.Username}"/>
<TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Username}"/>
<Label Grid.Column="0" Grid.Row="4" Content="{x:Static res:Resources.ConnectionPassword}"/>
<PasswordBox Grid.Column="1" Grid.Row="4" infrastructure:PasswordBoxAssistant.BindPassword="true" infrastructure:PasswordBoxAssistant.BoundPassword="{Binding Path=ConnectionInfo.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<PasswordBox Grid.Column="1" Grid.Row="4" infrastructure:PasswordBoxAssistant.BindPassword="true" infrastructure:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Column="0" Grid.Row="6" Content="{x:Static res:Resources.ConnectionExchange}"/>
<TextBox Grid.Column="1" Grid.Row="6" Text="{Binding Exchange}"/>

View File

@ -8,16 +8,19 @@ namespace PettingZoo.View
{
public ConnectionInfo Build()
{
var viewModel = new ConnectionViewModel();
var viewModel = new ConnectionViewModel(ConnectionInfo.Default());
var dialog = new ConnectionWindow(viewModel)
{
Owner = Application.Current.MainWindow
};
if (!dialog.ShowDialog().GetValueOrDefault())
return null;
viewModel.CloseWindow += (sender, args) =>
{
dialog.DialogResult = true;
};
return viewModel.ConnectionInfo;
return dialog.ShowDialog().GetValueOrDefault() ? viewModel.ToModel() : null;
}
}

View File

@ -24,12 +24,55 @@
<TextBlock />
</StatusBarItem>
</StatusBar>
<Grid>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" Grid.Row="0"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Messages}"
SelectedItem="{Binding Path=SelectedMessage, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding RoutingKey}"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<GridSplitter Width="5" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Grid Grid.Column="2" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Border Grid.Column="0" Grid.Row="0" Style="{StaticResource SidePanel}">
<DockPanel>
<Label DockPanel.Dock="Top" Style="{StaticResource HeaderLabel}" Content="{x:Static res:Resources.PanelTitleBody}"/>
<TextBox
Text="{Binding SelectedMessageBody, Mode=OneWay}"
BorderThickness="0"
IsReadOnly="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"/>
</DockPanel>
</Border>
<GridSplitter HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="1" Height="5" ResizeDirection="Rows"/>
<Border Grid.Column="0" Grid.Row="2" Style="{StaticResource SidePanel}">
<DockPanel>
<Label DockPanel.Dock="Top" Style="{StaticResource HeaderLabel}" Content="{x:Static res:Resources.PanelTitleProperties}"/>
<DataGrid ItemsSource="{Binding SelectedMessageProperties}" AutoGenerateColumns="False" IsReadOnly="True" Style="{StaticResource Properties}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Key}" Header="{x:Static res:Resources.PropertyName}" Width="100"/>
<DataGridTextColumn Binding="{Binding Value}" Header="{x:Static res:Resources.PropertyValue}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Border>
</Grid>
</Grid>
</DockPanel>
</Window>

View File

@ -1,11 +1,66 @@
using PettingZoo.Model;
using System;
using System.Windows.Input;
using AutoMapper;
using PettingZoo.Infrastructure;
using PettingZoo.Model;
namespace PettingZoo.ViewModel
{
public class ConnectionViewModel
{
public ConnectionInfo ConnectionInfo { get; set; }
private static IMapper modelMapper = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ConnectionInfo, ConnectionViewModel>();
cfg.CreateMap<ConnectionViewModel, ConnectionInfo>();
}).CreateMapper();
private readonly DelegateCommand okCommand;
public string Host { get; set; }
public string VirtualHost { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Exchange { get; set; }
public string RoutingKey { get; set; }
public ICommand OkCommand { get { return okCommand; } }
public event EventHandler CloseWindow;
public ConnectionViewModel()
{
okCommand = new DelegateCommand(OkExecute, OkCanExecute);
}
public ConnectionViewModel(ConnectionInfo model) : this()
{
modelMapper.Map(model, this);
}
public ConnectionInfo ToModel()
{
return modelMapper.Map<ConnectionInfo>(this);
}
private void OkExecute()
{
if (CloseWindow != null)
CloseWindow(this, EventArgs.Empty);
}
private bool OkCanExecute()
{
return true;
}
}
}

View File

@ -1,3 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using PettingZoo.Infrastructure;
using PettingZoo.Model;
@ -6,11 +11,14 @@ namespace PettingZoo.ViewModel
{
public class MainViewModel : BaseViewModel
{
private readonly TaskScheduler uiScheduler;
private readonly IConnectionInfoBuilder connectionInfoBuilder;
private readonly IConnectionFactory connectionFactory;
private ConnectionInfo connectionInfo;
private IConnection connection;
private readonly ObservableCollection<MessageInfo> messages;
private MessageInfo selectedMessage;
private readonly DelegateCommand connectCommand;
private readonly DelegateCommand disconnectCommand;
@ -18,20 +26,49 @@ namespace PettingZoo.ViewModel
public ConnectionInfo ConnectionInfo {
get
{
return connectionInfo;
}
get { return connectionInfo; }
private set
{
if (value != connectionInfo)
{
connectionInfo = value;
RaisePropertyChanged();
}
if (value == connectionInfo)
return;
connectionInfo = value;
RaisePropertyChanged();
}
}
public ObservableCollection<MessageInfo> Messages { get { return messages; } }
public MessageInfo SelectedMessage
{
get { return selectedMessage; }
set
{
if (value == selectedMessage)
return;
selectedMessage = value;
RaisePropertyChanged();
RaiseOtherPropertyChanged("SelectedMessageBody");
RaiseOtherPropertyChanged("SelectedMessageProperties");
}
}
public string SelectedMessageBody
{
get
{
return SelectedMessage != null
? MessageBodyRenderer.Render(SelectedMessage.Body, SelectedMessage.ContentType)
: "";
}
}
public Dictionary<string, string> SelectedMessageProperties
{
get { return SelectedMessage != null ? SelectedMessage.Properties : null; }
}
public ICommand ConnectCommand { get { return connectCommand; } }
public ICommand DisconnectCommand { get { return disconnectCommand; } }
public ICommand ClearCommand { get { return clearCommand; } }
@ -39,9 +76,13 @@ namespace PettingZoo.ViewModel
public MainViewModel(IConnectionInfoBuilder connectionInfoBuilder, IConnectionFactory connectionFactory)
{
uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.connectionInfoBuilder = connectionInfoBuilder;
this.connectionFactory = connectionFactory;
messages = new ObservableCollection<MessageInfo>();
connectCommand = new DelegateCommand(ConnectExecute);
disconnectCommand = new DelegateCommand(DisconnectExecute, DisconnectCanExecute);
clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute);
@ -56,6 +97,7 @@ namespace PettingZoo.ViewModel
ConnectionInfo = newInfo;
connection = connectionFactory.CreateConnection(connectionInfo);
connection.MessageReceived += ConnectionMessageReceived;
disconnectCommand.RaiseCanExecuteChanged();
}
@ -70,6 +112,7 @@ namespace PettingZoo.ViewModel
}
ConnectionInfo = null;
disconnectCommand.RaiseCanExecuteChanged();
}
@ -88,5 +131,17 @@ namespace PettingZoo.ViewModel
{
return false;
}
private void ConnectionMessageReceived(object sender, MessageReceivedEventArgs e)
{
RunFromUiScheduler(() => messages.Add(e.MessageInfo));
}
private void RunFromUiScheduler(Action action)
{
Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}
}
}

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="4.2.1" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.5" targetFramework="net45" />
</packages>