Put the view in a grid, instead of a stackpanel. This allows the Datagrid to stetch into parent container.

Add, Edit, Delete buttons in a horizontal stackpanel.
Changed some properties into fields.
Press delete when nothing is selected no longer crashes the UI.
pull/60/head
Stefan Roelofs 4 years ago
parent 848d1d06f9
commit 729a8a7e28

@ -3,24 +3,27 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
MaxWidth="800"
x:Class="UserInterface.Views.CommandSettings" >
<StackPanel Margin="30" HorizontalAlignment="Left" >
<ContentControl FontSize="18" Margin="0 0 0 15" FontWeight="Bold">Commands</ContentControl>
<DataGrid x:Name="Grid" IsVisible="{Binding ConfiguredCommands.Count}" AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single" Items="{Binding ConfiguredCommands}">
x:Class="UserInterface.Views.CommandSettings">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"
Width="1*" />
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="1*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock IsVisible="{Binding !ConfiguredCommands.Count}">Add some commands by clicking the "Add" button. </TextBlock>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Add">Add</Button>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Delete">Delete</Button>
</StackPanel>
</UserControl>
<Grid RowDefinitions="Auto, *, Auto, Auto" Margin="30 30 30 10" >
<TextBlock Grid.Row="0" Margin="0 0 0 15" FontSize="18" FontWeight="Bold" Text="Commands"/>
<DataGrid Grid.Row="1" x:Name="Grid" IsVisible="{Binding ConfiguredCommands.Count}"
AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single"
Items="{Binding ConfiguredCommands}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"
Width="1*" />
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="1*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock Grid.Row="2" IsVisible="{Binding !ConfiguredCommands.Count}" Text="Add some commands by clicking the 'Add' button."/>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Width="75" Margin="10 10 0 0" Click="AddCommand" Content="Add"/>
<Button Width="75" Margin="10 10 0 0" Click="EditCommand" Content="Edit" IsVisible="False"/>
<Button Width="75" Margin="10 10 0 0" Click="DeleteCommand" Content="Delete"/>
</StackPanel>
</Grid>
</UserControl>

@ -1,82 +1,97 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using hass_workstation_service.Communication.NamedPipe;
using JKang.IpcServiceFramework.Client;
using System.Threading.Tasks;
using Avalonia.Interactivity;
using System.Reactive.Linq;
using UserInterface.ViewModels;
using System.Security;
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
namespace UserInterface.Views
{
public class CommandSettings : UserControl
{
private readonly IIpcClient<ServiceContractInterfaces> client;
private DataGrid _dataGrid { get; set; }
private bool sensorsNeedToRefresh { get; set; }
public CommandSettings()
{
this.InitializeComponent();
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("commands", pipeName: "pipeinternal")
.BuildServiceProvider();
// resolve IPC client factory
IIpcClientFactory<ServiceContractInterfaces> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<ServiceContractInterfaces>>();
// create client
this.client = clientFactory.CreateClient("commands");
DataContext = new CommandSettingsViewModel();
GetConfiguredCommands();
this._dataGrid = this.FindControl<DataGrid>("Grid");
}
public async void GetConfiguredCommands()
{
sensorsNeedToRefresh = false;
List<ConfiguredCommandModel> status = await this.client.InvokeAsync(x => x.GetConfiguredCommands());
((CommandSettingsViewModel)this.DataContext).ConfiguredCommands = status.Select(s => new CommandViewModel() { Name = s.Name, Type = s.Type, Id = s.Id}).ToList();
}
public void Delete(object sender, RoutedEventArgs args)
{
var item = ((CommandViewModel)this._dataGrid.SelectedItem);
this.client.InvokeAsync(x => x.RemoveCommandById(item.Id));
((CommandSettingsViewModel)this.DataContext).ConfiguredCommands.Remove(item);
this._dataGrid.SelectedIndex = -1;
((CommandSettingsViewModel)this.DataContext).TriggerUpdate();
}
public async void Add(object sender, RoutedEventArgs args)
{
AddCommandDialog dialog = new AddCommandDialog();
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
sensorsNeedToRefresh = true;
GetConfiguredCommands();
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using hass_workstation_service.Communication.NamedPipe;
using JKang.IpcServiceFramework.Client;
using System.Threading.Tasks;
using Avalonia.Interactivity;
using System.Reactive.Linq;
using UserInterface.ViewModels;
using System.Security;
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
namespace UserInterface.Views
{
public class CommandSettings : UserControl
{
private readonly IIpcClient<ServiceContractInterfaces> _client;
private readonly DataGrid _dataGrid;
private bool _sensorsNeedToRefresh;
public CommandSettings()
{
this.InitializeComponent();
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("commands", pipeName: "pipeinternal")
.BuildServiceProvider();
// resolve IPC client factory
IIpcClientFactory<ServiceContractInterfaces> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<ServiceContractInterfaces>>();
// create client
this._client = clientFactory.CreateClient("commands");
DataContext = new CommandSettingsViewModel();
GetConfiguredCommands();
this._dataGrid = this.FindControl<DataGrid>("Grid");
}
public async void GetConfiguredCommands()
{
_sensorsNeedToRefresh = false;
List<ConfiguredCommandModel> status = await this._client.InvokeAsync(x => x.GetConfiguredCommands());
((CommandSettingsViewModel)this.DataContext).ConfiguredCommands = status.Select(s =>
new CommandViewModel()
{
Name = s.Name,
Type = s.Type,
Id = s.Id
}).ToList();
}
public async void AddCommand(object sender, RoutedEventArgs args)
{
var dialog = new AddCommandDialog();
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
_sensorsNeedToRefresh = true;
GetConfiguredCommands();
}
}
public void EditCommand(object sender, RoutedEventArgs args)
{
}
public void DeleteCommand(object sender, RoutedEventArgs args)
{
if (_dataGrid.SelectedItem is not CommandViewModel item)
return;
this._client.InvokeAsync(x => x.RemoveCommandById(item.Id));
if (DataContext is not CommandSettingsViewModel viewModel)
return;
viewModel.ConfiguredCommands.Remove(item);
_dataGrid.SelectedIndex = -1;
viewModel.TriggerUpdate();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

@ -3,30 +3,33 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
MaxWidth="800"
x:Class="UserInterface.Views.SensorSettings" >
<StackPanel Margin="30" HorizontalAlignment="Left" >
<ContentControl FontSize="18" Margin="0 0 0 15" FontWeight="Bold">Sensors</ContentControl>
<DataGrid x:Name="Grid" IsVisible="{Binding ConfiguredSensors.Count}" AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single" Items="{Binding ConfiguredSensors}">
x:Class="UserInterface.Views.SensorSettings">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"
Width="1*" />
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="1*" />
<DataGridTextColumn Header="Update Interval"
Binding="{Binding UpdateInterval}"
Width="1*" />
<DataGridTextColumn Header="Value"
Binding="{Binding ValueString}"
Width="2*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock IsVisible="{Binding !ConfiguredSensors.Count}">Add some sensors by clicking the "Add" button. </TextBlock>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="AddSensor">Add</Button>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Delete">Delete</Button>
</StackPanel>
</UserControl>
<Grid RowDefinitions="Auto, *, Auto, Auto" Margin="30 30 30 10" >
<TextBlock Grid.Row="0" Margin="0 0 0 15" FontSize="18" FontWeight="Bold" Text="Sensors"/>
<DataGrid Grid.Row="1" x:Name="Grid" IsVisible="{Binding ConfiguredSensors.Count}"
AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single"
Items="{Binding ConfiguredSensors}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"
Width="1*" />
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="1*" />
<DataGridTextColumn Header="Update Interval"
Binding="{Binding UpdateInterval}"
Width="1*" />
<DataGridTextColumn Header="Value"
Binding="{Binding ValueString}"
Width="2*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock Grid.Row="2" IsVisible="{Binding !ConfiguredSensors.Count}" Text="Add some sensors by clicking the 'Add' button."/>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Width="75" Margin="10 10 0 0" Click="AddSensor" Content="Add"/>
<Button Width="75" Margin="10 10 0 0" Click="EditSensor" Content="Edit" IsVisible="False"/>
<Button Width="75" Margin="10 10 0 0" Click="DeleteSensor" Content="Delete"/>
</StackPanel>
</Grid>
</UserControl>

@ -1,104 +1,123 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using hass_workstation_service.Communication.NamedPipe;
using JKang.IpcServiceFramework.Client;
using System.Threading.Tasks;
using Avalonia.Interactivity;
using System.Reactive.Linq;
using UserInterface.ViewModels;
using System.Security;
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
namespace UserInterface.Views
{
public class SensorSettings : UserControl
{
private readonly IIpcClient<ServiceContractInterfaces> client;
private DataGrid _dataGrid { get; set; }
private bool sensorsNeedToRefresh { get; set; }
public SensorSettings()
{
this.InitializeComponent();
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("sensors", pipeName: "pipeinternal")
.BuildServiceProvider();
// resolve IPC client factory
IIpcClientFactory<ServiceContractInterfaces> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<ServiceContractInterfaces>>();
// create client
this.client = clientFactory.CreateClient("sensors");
DataContext = new SensorSettingsViewModel();
GetConfiguredSensors();
this._dataGrid = this.FindControl<DataGrid>("Grid");
}
public async void GetConfiguredSensors()
{
sensorsNeedToRefresh = false;
List<ConfiguredSensorModel> status = await this.client.InvokeAsync(x => x.GetConfiguredSensors());
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors = status.Select(s => new SensorViewModel() { Name = s.Name, Type = s.Type, Value = s.Value, Id = s.Id, UpdateInterval = s.UpdateInterval, UnitOfMeasurement = s.UnitOfMeasurement }).ToList();
while (!sensorsNeedToRefresh)
{
await Task.Delay(1000);
List<ConfiguredSensorModel> statusUpdated = await this.client.InvokeAsync(x => x.GetConfiguredSensors());
var configuredSensors = ((SensorSettingsViewModel)this.DataContext).ConfiguredSensors;
// this is a workaround for the list showing before it has been completely loaded in the service
if (statusUpdated.Count != configuredSensors.Count) {
sensorsNeedToRefresh = true;
GetConfiguredSensors();
}
statusUpdated.ForEach(s =>
{
var configuredSensor = configuredSensors.FirstOrDefault(cs => cs.Id == s.Id);
if (configuredSensor != null)
{
configuredSensor.Value = s.Value;
configuredSensors.FirstOrDefault(cs => cs.Id == s.Id).Value = s.Value;
}
});
}
}
public void Delete(object sender, RoutedEventArgs args)
{
var item = ((SensorViewModel)this._dataGrid.SelectedItem);
this.client.InvokeAsync(x => x.RemoveSensorById(item.Id));
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors.Remove(item);
this._dataGrid.SelectedIndex = -1;
((SensorSettingsViewModel)this.DataContext).TriggerUpdate();
}
public async void AddSensor(object sender, RoutedEventArgs args)
{
AddSensorDialog dialog = new AddSensorDialog();
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
sensorsNeedToRefresh = true;
GetConfiguredSensors();
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using hass_workstation_service.Communication.NamedPipe;
using JKang.IpcServiceFramework.Client;
using System.Threading.Tasks;
using Avalonia.Interactivity;
using System.Reactive.Linq;
using UserInterface.ViewModels;
using System.Security;
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
namespace UserInterface.Views
{
public class SensorSettings : UserControl
{
private readonly IIpcClient<ServiceContractInterfaces> _client;
private readonly DataGrid _dataGrid;
private bool _sensorsNeedToRefresh;
public SensorSettings()
{
this.InitializeComponent();
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("sensors", pipeName: "pipeinternal")
.BuildServiceProvider();
// resolve IPC client factory
IIpcClientFactory<ServiceContractInterfaces> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<ServiceContractInterfaces>>();
// create client
this._client = clientFactory.CreateClient("sensors");
DataContext = new SensorSettingsViewModel();
GetConfiguredSensors();
this._dataGrid = this.FindControl<DataGrid>("Grid");
}
public async void GetConfiguredSensors()
{
_sensorsNeedToRefresh = false;
List<ConfiguredSensorModel> status = await this._client.InvokeAsync(x => x.GetConfiguredSensors());
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors = status.Select(s =>
new SensorViewModel()
{
Name = s.Name,
Type = s.Type,
Value = s.Value,
Id = s.Id,
UpdateInterval = s.UpdateInterval,
UnitOfMeasurement = s.UnitOfMeasurement
}).ToList();
while (!_sensorsNeedToRefresh)
{
await Task.Delay(1000);
List<ConfiguredSensorModel> statusUpdated = await this._client.InvokeAsync(x => x.GetConfiguredSensors());
var configuredSensors = ((SensorSettingsViewModel)this.DataContext).ConfiguredSensors;
// this is a workaround for the list showing before it has been completely loaded in the service
if (statusUpdated.Count != configuredSensors.Count)
{
_sensorsNeedToRefresh = true;
GetConfiguredSensors();
}
statusUpdated.ForEach(s =>
{
var configuredSensor = configuredSensors.FirstOrDefault(cs => cs.Id == s.Id);
if (configuredSensor != null)
{
configuredSensor.Value = s.Value;
configuredSensors.FirstOrDefault(cs => cs.Id == s.Id).Value = s.Value;
}
});
}
}
public async void AddSensor(object sender, RoutedEventArgs args)
{
var dialog = new AddSensorDialog();
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
_sensorsNeedToRefresh = true;
GetConfiguredSensors();
}
}
public void EditSensor(object sender, RoutedEventArgs args)
{
}
public void DeleteSensor(object sender, RoutedEventArgs args)
{
if (_dataGrid.SelectedItem is not SensorViewModel item)
return;
this._client.InvokeAsync(x => x.RemoveSensorById(item.Id));
if (DataContext is not SensorSettingsViewModel viewModel)
return;
viewModel.ConfiguredSensors.Remove(item);
_dataGrid.SelectedIndex = -1;
viewModel.TriggerUpdate();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
Loading…
Cancel
Save