mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Fixed plugin binding and reworked some interfaces to abstract classes
This commit is contained in:
parent
571a3fe168
commit
3689db9325
@ -102,6 +102,7 @@
|
|||||||
<Compile Include="Events\DeviceEventArgs.cs" />
|
<Compile Include="Events\DeviceEventArgs.cs" />
|
||||||
<Compile Include="Exceptions\ArtemisCoreException.cs" />
|
<Compile Include="Exceptions\ArtemisCoreException.cs" />
|
||||||
<Compile Include="Models\DataModelDescription.cs" />
|
<Compile Include="Models\DataModelDescription.cs" />
|
||||||
|
<Compile Include="Plugins\Abstract\ModuleDataModel.cs" />
|
||||||
<Compile Include="Plugins\Abstract\ModuleViewModel.cs" />
|
<Compile Include="Plugins\Abstract\ModuleViewModel.cs" />
|
||||||
<Compile Include="Plugins\Abstract\ProfileModule.cs" />
|
<Compile Include="Plugins\Abstract\ProfileModule.cs" />
|
||||||
<Compile Include="Plugins\Exceptions\ArtemisPluginException.cs" />
|
<Compile Include="Plugins\Exceptions\ArtemisPluginException.cs" />
|
||||||
@ -110,8 +111,6 @@
|
|||||||
<Compile Include="Plugins\Interfaces\ILayerType.cs" />
|
<Compile Include="Plugins\Interfaces\ILayerType.cs" />
|
||||||
<Compile Include="Plugins\Interfaces\ILayerTypeConfiguration.cs" />
|
<Compile Include="Plugins\Interfaces\ILayerTypeConfiguration.cs" />
|
||||||
<Compile Include="Plugins\Interfaces\IModule.cs" />
|
<Compile Include="Plugins\Interfaces\IModule.cs" />
|
||||||
<Compile Include="Plugins\Interfaces\IModuleDataModel.cs" />
|
|
||||||
<Compile Include="Plugins\Interfaces\IModuleViewModel.cs" />
|
|
||||||
<Compile Include="Plugins\Interfaces\IPlugin.cs" />
|
<Compile Include="Plugins\Interfaces\IPlugin.cs" />
|
||||||
<Compile Include="Plugins\Models\PluginInfo.cs" />
|
<Compile Include="Plugins\Models\PluginInfo.cs" />
|
||||||
<Compile Include="ProfileElements\Folder.cs" />
|
<Compile Include="ProfileElements\Folder.cs" />
|
||||||
|
|||||||
15
src/Artemis.Core/Plugins/Abstract/ModuleDataModel.cs
Normal file
15
src/Artemis.Core/Plugins/Abstract/ModuleDataModel.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Artemis.Core.Plugins.Interfaces;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Plugins.Abstract
|
||||||
|
{
|
||||||
|
public abstract class ModuleDataModel
|
||||||
|
{
|
||||||
|
protected ModuleDataModel(IModule module)
|
||||||
|
{
|
||||||
|
Module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IModule Module { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,8 +4,13 @@ using Stylet;
|
|||||||
|
|
||||||
namespace Artemis.Core.Plugins.Abstract
|
namespace Artemis.Core.Plugins.Abstract
|
||||||
{
|
{
|
||||||
public abstract class ModuleViewModel : Screen, IModuleViewModel
|
public abstract class ModuleViewModel : Screen
|
||||||
{
|
{
|
||||||
public PluginInfo PluginInfo { get; set; }
|
protected ModuleViewModel(IModule module)
|
||||||
|
{
|
||||||
|
Module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IModule Module { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,6 +11,9 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
{
|
{
|
||||||
public Profile ActiveProfile { get; private set; }
|
public Profile ActiveProfile { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract string DisplayName { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public abstract bool ExpandsMainDataModel { get; }
|
public abstract bool ExpandsMainDataModel { get; }
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,12 @@ namespace Artemis.Core.Plugins.Interfaces
|
|||||||
public interface IModule : IPlugin
|
public interface IModule : IPlugin
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wether or not this module expands upon the main data model. If set to true any data in main data model can be
|
/// The modules display name that's shown in the menu
|
||||||
|
/// </summary>
|
||||||
|
string DisplayName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not this module expands upon the main data model. If set to true any data in main data model can be
|
||||||
/// accessed by profiles in this module
|
/// accessed by profiles in this module
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ExpandsMainDataModel { get; }
|
bool ExpandsMainDataModel { get; }
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
namespace Artemis.Core.Plugins.Interfaces
|
|
||||||
{
|
|
||||||
public interface IModuleDataModel
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
using Artemis.Core.Plugins.Models;
|
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.Core.Plugins.Interfaces
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Allows you to create a view model for a module
|
|
||||||
/// </summary>
|
|
||||||
public interface IModuleViewModel : IScreen
|
|
||||||
{
|
|
||||||
PluginInfo PluginInfo { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,6 +7,11 @@ namespace Artemis.Core.Plugins.Models
|
|||||||
{
|
{
|
||||||
public class PluginInfo
|
public class PluginInfo
|
||||||
{
|
{
|
||||||
|
public PluginInfo()
|
||||||
|
{
|
||||||
|
Instances = new List<IPlugin>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugins GUID
|
/// The plugins GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -68,13 +68,29 @@ namespace Artemis.Core.Services
|
|||||||
throw new ArtemisPluginException(pluginInfo, "Couldn't find the plugins main entry at " + mainFile);
|
throw new ArtemisPluginException(pluginInfo, "Couldn't find the plugins main entry at " + mainFile);
|
||||||
|
|
||||||
// Load the plugin, all types implementing IPlugin and register them with DI
|
// Load the plugin, all types implementing IPlugin and register them with DI
|
||||||
var assembly = Assembly.LoadFile(mainFile);
|
Assembly assembly;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
assembly = Assembly.LoadFile(mainFile);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new ArtemisPluginException(pluginInfo, "Failed to load the plugins assembly", e);
|
||||||
|
}
|
||||||
|
|
||||||
var pluginTypes = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToArray();
|
var pluginTypes = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToArray();
|
||||||
foreach (var pluginType in pluginTypes)
|
foreach (var pluginType in pluginTypes)
|
||||||
{
|
{
|
||||||
_childKernel.Bind(pluginType).To<IPlugin>().InSingletonScope();
|
_childKernel.Bind<IPlugin>().To(pluginType).InSingletonScope();
|
||||||
|
try
|
||||||
|
{
|
||||||
pluginInfo.Instances.Add((IPlugin) _childKernel.Get(pluginType));
|
pluginInfo.Instances.Add((IPlugin) _childKernel.Get(pluginType));
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new ArtemisPluginException(pluginInfo, "Failed to instantiate the plugin", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_plugins.Add(pluginInfo);
|
_plugins.Add(pluginInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
using Artemis.Core.Attributes;
|
using Artemis.Core.Attributes;
|
||||||
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Interfaces;
|
using Artemis.Core.Plugins.Interfaces;
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General
|
namespace Artemis.Plugins.Modules.General
|
||||||
{
|
{
|
||||||
public class GeneralDataModel : IModuleDataModel
|
public class GeneralDataModel : ModuleDataModel
|
||||||
{
|
{
|
||||||
[DataModelProperty(DisplayName = "Unique boolean")]
|
[DataModelProperty(DisplayName = "Unique boolean")]
|
||||||
public bool PropertyUniqueToThisDm { get; set; }
|
public bool PropertyUniqueToThisDm { get; set; }
|
||||||
|
|
||||||
|
public GeneralDataModel(IModule module) : base(module)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,23 +13,20 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
{
|
{
|
||||||
public class GeneralModule : IModule
|
public class GeneralModule : IModule
|
||||||
{
|
{
|
||||||
private readonly IRgbService _rgbService;
|
|
||||||
private readonly RGBSurface _surface;
|
private readonly RGBSurface _surface;
|
||||||
private Dictionary<Led, Color> _colors;
|
private Dictionary<Led, Color> _colors;
|
||||||
|
|
||||||
public GeneralModule()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public GeneralModule(IRgbService rgbService)
|
public GeneralModule(IRgbService rgbService)
|
||||||
{
|
{
|
||||||
_rgbService = rgbService;
|
var rgbService1 = rgbService;
|
||||||
_surface = _rgbService.Surface;
|
_surface = rgbService1.Surface;
|
||||||
_colors = new Dictionary<Led, Color>();
|
_colors = new Dictionary<Led, Color>();
|
||||||
|
|
||||||
_rgbService.FinishedLoadedDevices += (sender, args) => PopulateColors();
|
rgbService1.FinishedLoadedDevices += (sender, args) => PopulateColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string DisplayName => "General";
|
||||||
|
|
||||||
// True since the main data model is all this module shows
|
// True since the main data model is all this module shows
|
||||||
public bool ExpandsMainDataModel => true;
|
public bool ExpandsMainDataModel => true;
|
||||||
|
|
||||||
@ -58,7 +55,7 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
|
|
||||||
public IScreen GetMainViewModel()
|
public IScreen GetMainViewModel()
|
||||||
{
|
{
|
||||||
return new GeneralViewModel();
|
return new GeneralViewModel(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
using Artemis.Core.Plugins.Interfaces;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Interfaces;
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General.ViewModels
|
namespace Artemis.Plugins.Modules.General.ViewModels
|
||||||
{
|
{
|
||||||
public class GeneralViewModel : Screen, IModuleViewModel
|
public class GeneralViewModel : ModuleViewModel
|
||||||
{
|
{
|
||||||
public PluginInfo PluginInfo { get; set; }
|
public GeneralViewModel(IModule module) : base(module)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,5 +6,7 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.Plugins.Modules.General.Views"
|
xmlns:local="clr-namespace:Artemis.Plugins.Modules.General.Views"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid />
|
<Grid>
|
||||||
|
<Label>Test</Label>
|
||||||
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,8 +1,4 @@
|
|||||||
using System.IO;
|
using Stylet;
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Markup;
|
|
||||||
using Artemis.Core.Plugins.Interfaces;
|
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Stylet
|
namespace Artemis.UI.Stylet
|
||||||
{
|
{
|
||||||
@ -10,30 +6,7 @@ namespace Artemis.UI.Stylet
|
|||||||
{
|
{
|
||||||
public ArtemisViewManager(ViewManagerConfig config) : base(config)
|
public ArtemisViewManager(ViewManagerConfig config) : base(config)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public override UIElement CreateViewForModel(object model)
|
|
||||||
{
|
|
||||||
if (model is IModuleViewModel)
|
|
||||||
return CreateViewForPlugin(model);
|
|
||||||
|
|
||||||
return base.CreateViewForModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UIElement CreateViewForPlugin(object model)
|
|
||||||
{
|
|
||||||
var viewName = model.GetType().Name.Replace("Model", "");
|
|
||||||
var pluginInfo = ((IModuleViewModel) model).PluginInfo;
|
|
||||||
var viewPath = $"{pluginInfo.Folder}{viewName}.xaml";
|
|
||||||
// There doesn't have to be a view so make sure one exists
|
|
||||||
if (!File.Exists(viewPath))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Compile the view if found, must be done on UI thread sadly
|
|
||||||
object view = null;
|
|
||||||
Execute.OnUIThread(() => view = XamlReader.Parse(File.ReadAllText(viewPath)));
|
|
||||||
|
|
||||||
return (UIElement) view;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,11 +31,10 @@ namespace Artemis.UI.Stylet
|
|||||||
ViewFactory = GetInstance,
|
ViewFactory = GetInstance,
|
||||||
ViewAssemblies = new List<Assembly> {GetType().Assembly}
|
ViewAssemblies = new List<Assembly> {GetType().Assembly}
|
||||||
};
|
};
|
||||||
kernel.Bind<IViewManager>().ToConstant(new ArtemisViewManager(viewManagerConfig));
|
kernel.Bind<IViewManager>().ToConstant(new ViewManager(viewManagerConfig));
|
||||||
|
|
||||||
kernel.Bind<IWindowManagerConfig>().ToConstant(this).InTransientScope();
|
kernel.Bind<IWindowManagerConfig>().ToConstant(this).InTransientScope();
|
||||||
kernel.Bind<IWindowManager>().ToMethod(c => new WindowManager(c.Kernel.Get<IViewManager>(),
|
kernel.Bind<IWindowManager>().ToMethod(c => new WindowManager(c.Kernel.Get<IViewManager>(),() => c.Kernel.Get<IMessageBoxViewModel>(), c.Kernel.Get<IWindowManagerConfig>())).InSingletonScope();
|
||||||
() => c.Kernel.Get<IMessageBoxViewModel>(), c.Kernel.Get<IWindowManagerConfig>())).InSingletonScope();
|
|
||||||
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
|
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
|
||||||
kernel.Bind<IMessageBoxViewModel>().To<MessageBoxViewModel>(); // Not singleton!
|
kernel.Bind<IMessageBoxViewModel>().To<MessageBoxViewModel>(); // Not singleton!
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<materialDesign:PackIcon Kind="Discord" Width="140" Height="140"
|
<materialDesign:PackIcon Kind="Discord" Width="140" Height="140"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
<StackPanel Grid.Column="1">
|
<StackPanel Grid.Row="0" Grid.Column="1">
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadlineTextBlock}" Margin="16 16 16 8">Have a chat</TextBlock>
|
<TextBlock Style="{StaticResource MaterialDesignHeadlineTextBlock}" Margin="16 16 16 8">Have a chat</TextBlock>
|
||||||
<TextBlock TextWrapping="Wrap" Margin="16 0 16 8"
|
<TextBlock TextWrapping="Wrap" Margin="16 0 16 8"
|
||||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||||
@ -75,7 +75,7 @@
|
|||||||
<Run Text=". " />
|
<Run Text=". " />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Border Grid.Row="1" Grid.ColumnSpan="2" BorderThickness="0 1 0 0"
|
<Border Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="0" BorderThickness="0 1 0 0"
|
||||||
BorderBrush="{DynamicResource MaterialDesignDivider}" Padding="8">
|
BorderBrush="{DynamicResource MaterialDesignDivider}" Padding="8">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Grid Margin="8">
|
<Grid Margin="8">
|
||||||
@ -92,7 +92,7 @@
|
|||||||
<TextBlock Margin="8 0 0 0" VerticalAlignment="Center">GitHub</TextBlock>
|
<TextBlock Margin="8 0 0 0" VerticalAlignment="Center">GitHub</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Style="{DynamicResource MaterialDesignFlatButton}"
|
<Button Grid.Row="0" Style="{DynamicResource MaterialDesignFlatButton}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
x:Name="TwitterButton" Command="{s:Action OpenUrl}"
|
x:Name="TwitterButton" Command="{s:Action OpenUrl}"
|
||||||
CommandParameter="https://twitter.com/spoinkynl">
|
CommandParameter="https://twitter.com/spoinkynl">
|
||||||
@ -136,7 +136,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<materialDesign:PackIcon Kind="GithubCircle" Width="160" Height="160"
|
<materialDesign:PackIcon Kind="GithubCircle" Width="160" Height="160"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
<StackPanel Grid.Column="1">
|
<StackPanel Grid.Row="0" Grid.Column="1">
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadlineTextBlock}" Margin="16 16 16 8">Open Source</TextBlock>
|
<TextBlock Style="{StaticResource MaterialDesignHeadlineTextBlock}" Margin="16 16 16 8">Open Source</TextBlock>
|
||||||
<TextBlock TextWrapping="Wrap" Margin="16 0 16 8"
|
<TextBlock TextWrapping="Wrap" Margin="16 0 16 8"
|
||||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||||
@ -146,7 +146,7 @@
|
|||||||
<Run Text=". You can also make your own modules!" />
|
<Run Text=". You can also make your own modules!" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Border Grid.Row="1" Grid.ColumnSpan="2" BorderThickness="0 1 0 0"
|
<Border Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="0" BorderThickness="0 1 0 0"
|
||||||
BorderBrush="{DynamicResource MaterialDesignDivider}" Padding="8">
|
BorderBrush="{DynamicResource MaterialDesignDivider}" Padding="8">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Button Style="{DynamicResource MaterialDesignFlatButton}"
|
<Button Style="{DynamicResource MaterialDesignFlatButton}"
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:vms="clr-namespace:Artemis.UI.ViewModels"
|
xmlns:vms="clr-namespace:Artemis.UI.ViewModels"
|
||||||
xmlns:models="clr-namespace:Artemis.Core.Plugins.Models;assembly=Artemis.Core"
|
xmlns:models="clr-namespace:Artemis.Core.Plugins.Models;assembly=Artemis.Core"
|
||||||
|
xmlns:interfaces="clr-namespace:Artemis.Core.Plugins.Interfaces;assembly=Artemis.Core"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
GlowBrush="{DynamicResource AccentColorBrush}"
|
GlowBrush="{DynamicResource AccentColorBrush}"
|
||||||
FontFamily="{StaticResource DefaultFont}"
|
FontFamily="{StaticResource DefaultFont}"
|
||||||
@ -126,13 +127,13 @@
|
|||||||
SelectedItem="{Binding SelectedModule}"
|
SelectedItem="{Binding SelectedModule}"
|
||||||
DockPanel.Dock="Top">
|
DockPanel.Dock="Top">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="models:PluginInfo">
|
<DataTemplate DataType="interfaces:IModule">
|
||||||
<DockPanel HorizontalAlignment="Stretch"
|
<DockPanel HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Margin="0">
|
Margin="0">
|
||||||
<materialDesign:PackIcon Kind="Home"
|
<materialDesign:PackIcon Kind="Home"
|
||||||
Margin="0,0,8,0" />
|
Margin="0,0,8,0" />
|
||||||
<TextBlock Text="{Binding Name}" />
|
<TextBlock Text="{Binding DisplayName}" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user