1
0
mirror of synced 2024-11-14 09:29:17 +00: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) protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{ {
var handler = PropertyChanged; 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)); handler(this, new PropertyChangedEventArgs(propertyName));
} }
} }

View File

@ -7,5 +7,22 @@
public int Port { get; set; } public int Port { get; set; }
public string Username { get; set; } public string Username { get; set; }
public string Password { 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 namespace PettingZoo.Model
{ {
public class MessageReceivedEventArgs : EventArgs
{
public MessageInfo MessageInfo { get; private set; }
public MessageReceivedEventArgs(MessageInfo messageInfo)
{
MessageInfo = messageInfo;
}
}
public interface IConnection : IDisposable 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 public class RabbitMQClientConnection : IConnection
{ {
private readonly CancellationTokenSource timer;
public RabbitMQClientConnection(ConnectionInfo connectionInfo) 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() public void Dispose()
{ {
timer.Cancel();
} }
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
} }
} }

View File

@ -54,6 +54,10 @@
</StartupObject> </StartupObject>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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"> <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> <HintPath>packages\SimpleInjector.3.1.5\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -101,6 +105,8 @@
<Compile Include="Model\IConnectionFactory.cs" /> <Compile Include="Model\IConnectionFactory.cs" />
<Compile Include="Model\IConnectionInfoBuilder.cs" /> <Compile Include="Model\IConnectionInfoBuilder.cs" />
<Compile Include="Model\ConnectionInfo.cs" /> <Compile Include="Model\ConnectionInfo.cs" />
<Compile Include="Model\MessageBodyRenderer.cs" />
<Compile Include="Model\MessageInfo.cs" />
<Compile Include="Model\RabbitMQClientConnection.cs" /> <Compile Include="Model\RabbitMQClientConnection.cs" />
<Compile Include="Model\RabbitMQClientConnectionFactory.cs" /> <Compile Include="Model\RabbitMQClientConnectionFactory.cs" />
<Compile Include="ViewModel\ConnectionViewModel.cs" /> <Compile Include="ViewModel\ConnectionViewModel.cs" />

View File

@ -158,5 +158,41 @@ namespace PettingZoo.Properties {
return ResourceManager.GetString("MainWindowTitle", resourceCulture); 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"> <data name="MainWindowTitle" xml:space="preserve">
<value>Petting Zoo - a RabbitMQ Message Viewer</value> <value>Petting Zoo - a RabbitMQ Message Viewer</value>
</data> </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> </root>

View File

@ -11,6 +11,16 @@
</Style> </Style>
<!-- Explicit styling --> <!-- 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}"> <Style x:Key="FooterPanel" TargetType="{x:Type Panel}">
<Setter Property="Margin" Value="0,8,0,0" /> <Setter Property="Margin" Value="0,8,0,0" />
</Style> </Style>
@ -23,4 +33,11 @@
<Style x:Key="Form" TargetType="{x:Type infrastructure:GridLayout}"> <Style x:Key="Form" TargetType="{x:Type infrastructure:GridLayout}">
<Setter Property="ChildMargin" Value="4"/> <Setter Property="ChildMargin" Value="4"/>
</Style> </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> </ResourceDictionary>

View File

@ -17,7 +17,7 @@
FocusManager.FocusedElement="{Binding ElementName=HostTextBox}"> FocusManager.FocusedElement="{Binding ElementName=HostTextBox}">
<DockPanel Margin="8"> <DockPanel Margin="8">
<UniformGrid DockPanel.Dock="Bottom" HorizontalAlignment="Right" Rows="1" Columns="2" Style="{StaticResource FooterPanel}"> <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}"/> <Button IsCancel="True" Content="{x:Static res:Resources.ButtonCancel}" Style="{StaticResource FooterButton}"/>
</UniformGrid> </UniformGrid>
@ -37,18 +37,18 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="{x:Static res:Resources.ConnectionHost}"/> <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="1" Content="{x:Static res:Resources.ConnectionPort}"/>
<Label Grid.Column="0" Grid.Row="2" Content="{x:Static res:Resources.ConnectionVirtualHost}"/> <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}"/> <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}"/> <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}"/> <Label Grid.Column="0" Grid.Row="6" Content="{x:Static res:Resources.ConnectionExchange}"/>
<TextBox Grid.Column="1" Grid.Row="6" Text="{Binding Exchange}"/> <TextBox Grid.Column="1" Grid.Row="6" Text="{Binding Exchange}"/>

View File

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

View File

@ -24,12 +24,55 @@
<TextBlock /> <TextBlock />
</StatusBarItem> </StatusBarItem>
</StatusBar> </StatusBar>
<Grid> <Grid Margin="4">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="200" /> <ColumnDefinition Width="300" />
</Grid.ColumnDefinitions> </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> </Grid>
</DockPanel> </DockPanel>
</Window> </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 namespace PettingZoo.ViewModel
{ {
public class ConnectionViewModel 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 Exchange { get; set; }
public string RoutingKey { 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 System.Windows.Input;
using PettingZoo.Infrastructure; using PettingZoo.Infrastructure;
using PettingZoo.Model; using PettingZoo.Model;
@ -6,11 +11,14 @@ namespace PettingZoo.ViewModel
{ {
public class MainViewModel : BaseViewModel public class MainViewModel : BaseViewModel
{ {
private readonly TaskScheduler uiScheduler;
private readonly IConnectionInfoBuilder connectionInfoBuilder; private readonly IConnectionInfoBuilder connectionInfoBuilder;
private readonly IConnectionFactory connectionFactory; private readonly IConnectionFactory connectionFactory;
private ConnectionInfo connectionInfo; private ConnectionInfo connectionInfo;
private IConnection connection; private IConnection connection;
private readonly ObservableCollection<MessageInfo> messages;
private MessageInfo selectedMessage;
private readonly DelegateCommand connectCommand; private readonly DelegateCommand connectCommand;
private readonly DelegateCommand disconnectCommand; private readonly DelegateCommand disconnectCommand;
@ -18,20 +26,49 @@ namespace PettingZoo.ViewModel
public ConnectionInfo ConnectionInfo { public ConnectionInfo ConnectionInfo {
get get { return connectionInfo; }
{
return connectionInfo;
}
private set private set
{ {
if (value != connectionInfo) if (value == connectionInfo)
{ return;
connectionInfo = value;
RaisePropertyChanged(); 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 ConnectCommand { get { return connectCommand; } }
public ICommand DisconnectCommand { get { return disconnectCommand; } } public ICommand DisconnectCommand { get { return disconnectCommand; } }
public ICommand ClearCommand { get { return clearCommand; } } public ICommand ClearCommand { get { return clearCommand; } }
@ -39,9 +76,13 @@ namespace PettingZoo.ViewModel
public MainViewModel(IConnectionInfoBuilder connectionInfoBuilder, IConnectionFactory connectionFactory) public MainViewModel(IConnectionInfoBuilder connectionInfoBuilder, IConnectionFactory connectionFactory)
{ {
uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.connectionInfoBuilder = connectionInfoBuilder; this.connectionInfoBuilder = connectionInfoBuilder;
this.connectionFactory = connectionFactory; this.connectionFactory = connectionFactory;
messages = new ObservableCollection<MessageInfo>();
connectCommand = new DelegateCommand(ConnectExecute); connectCommand = new DelegateCommand(ConnectExecute);
disconnectCommand = new DelegateCommand(DisconnectExecute, DisconnectCanExecute); disconnectCommand = new DelegateCommand(DisconnectExecute, DisconnectCanExecute);
clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute); clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute);
@ -56,6 +97,7 @@ namespace PettingZoo.ViewModel
ConnectionInfo = newInfo; ConnectionInfo = newInfo;
connection = connectionFactory.CreateConnection(connectionInfo); connection = connectionFactory.CreateConnection(connectionInfo);
connection.MessageReceived += ConnectionMessageReceived;
disconnectCommand.RaiseCanExecuteChanged(); disconnectCommand.RaiseCanExecuteChanged();
} }
@ -70,6 +112,7 @@ namespace PettingZoo.ViewModel
} }
ConnectionInfo = null; ConnectionInfo = null;
disconnectCommand.RaiseCanExecuteChanged();
} }
@ -88,5 +131,17 @@ namespace PettingZoo.ViewModel
{ {
return false; 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"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="AutoMapper" version="4.2.1" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.5" targetFramework="net45" /> <package id="SimpleInjector" version="3.1.5" targetFramework="net45" />
</packages> </packages>