complete the branch
This commit is contained in:
1 parent
2c0889f64b
commit
cb20ea41f6
29 files changed
+426
-115
No files matched your search
@@ -34,31 +34,33 @@ namespace HandyControl.Controls
|
||||
if (!IsSelected)
|
||||
{
|
||||
IsSelected = true;
|
||||
RaiseEvent(new RoutedEventArgs(SelectedEvent, this));
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else if (CanDeselect)
|
||||
{
|
||||
IsSelected = false;
|
||||
RaiseEvent(new RoutedEventArgs(DeselectedEvent, this));
|
||||
OnSelected(new RoutedEventArgs(DeselectedEvent, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CanDeselect)
|
||||
{
|
||||
RaiseEvent(IsSelected
|
||||
OnSelected(IsSelected
|
||||
? new RoutedEventArgs(DeselectedEvent, this)
|
||||
: new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseEvent(new RoutedEventArgs(SelectedEvent, this));
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
}
|
||||
_isMouseLeftButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e);
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
|
||||
"IsSelected", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class ChatBubble : ContentControl
|
||||
public class ChatBubble : SelectableItem
|
||||
{
|
||||
public static readonly DependencyProperty RoleProperty = DependencyProperty.Register(
|
||||
"Role", typeof(ChatRoleType), typeof(ChatBubble), new PropertyMetadata(default(ChatRoleType)));
|
||||
@@ -14,5 +14,39 @@ namespace HandyControl.Controls
|
||||
get => (ChatRoleType) GetValue(RoleProperty);
|
||||
set => SetValue(RoleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(
|
||||
"Type", typeof(ChatMessageType), typeof(ChatBubble), new PropertyMetadata(default(ChatMessageType)));
|
||||
|
||||
public ChatMessageType Type
|
||||
{
|
||||
get => (ChatMessageType) GetValue(TypeProperty);
|
||||
set => SetValue(TypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsReadProperty = DependencyProperty.Register(
|
||||
"IsRead", typeof(bool), typeof(ChatBubble), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsRead
|
||||
{
|
||||
get => (bool) GetValue(IsReadProperty);
|
||||
set => SetValue(IsReadProperty, value);
|
||||
}
|
||||
|
||||
public static void SetMaxWidth(DependencyObject element, double value)
|
||||
=> element.SetValue(MaxWidthProperty, value);
|
||||
|
||||
public static double GetMaxWidth(DependencyObject element)
|
||||
=> (double) element.GetValue(MaxWidthProperty);
|
||||
|
||||
public Action<object> ReadAction { get; set; }
|
||||
|
||||
protected override void OnSelected(RoutedEventArgs e)
|
||||
{
|
||||
base.OnSelected(e);
|
||||
|
||||
IsRead = true;
|
||||
ReadAction?.Invoke(Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ namespace HandyControl.Controls
|
||||
throw new InvalidEnumArgumentException(nameof(defaultResult), (int)defaultResult, typeof(MessageBoxResult));
|
||||
}
|
||||
|
||||
var ownerWindow = owner ?? Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
|
||||
var ownerWindow = owner ?? VisualHelper.GetActiveWindow();
|
||||
var ownerIsNull = ownerWindow is null;
|
||||
|
||||
return new MessageBox
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace HandyControl.Data
|
||||
{
|
||||
public enum ChatMessageType
|
||||
{
|
||||
String,
|
||||
Image,
|
||||
Audio,
|
||||
Custom
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@
|
||||
<Compile Include="Controls\Window\BlurWindow.cs" />
|
||||
<Compile Include="Controls\Window\MessageBox.cs" />
|
||||
<Compile Include="Data\Args\CancelRoutedEventArgs.cs" />
|
||||
<Compile Include="Data\Enum\ChatMessageType.cs" />
|
||||
<Compile Include="Data\Enum\ChatRoleType.cs" />
|
||||
<Compile Include="Data\Enum\InfoType.cs" />
|
||||
<Compile Include="Data\Enum\ResultType.cs" />
|
||||
|
||||
@@ -3,48 +3,134 @@
|
||||
xmlns:controls="clr-namespace:HandyControl.Controls">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Basic/Converters.xaml"/>
|
||||
<ResourceDictionary Source="../../Basic/Geometries.xaml"/>
|
||||
<ResourceDictionary Source="../../Basic/Sizes.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ControlTemplate x:Key="ChatBubbleSenderBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<ControlTemplate x:Key="ChatBubbleStringBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<Grid>
|
||||
<Path Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15"/>
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="15" Margin="0,0,3,0">
|
||||
<ContentPresenter Name="Presenter" Margin="{TemplateBinding Padding}" VerticalAlignment="Center">
|
||||
<ContentPresenter.OpacityMask>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Border Background="White" CornerRadius="10" Width="{Binding ActualWidth,ElementName=Presenter}" Height="{Binding ActualHeight,ElementName=Presenter}"/>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</ContentPresenter.OpacityMask>
|
||||
</ContentPresenter>
|
||||
<Path Name="Tail" Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15" RenderTransformOrigin="0.5,0.5"/>
|
||||
<Border Name="Body" Background="{TemplateBinding Background}" CornerRadius="15" Margin="0,0,3,0">
|
||||
<TextBlock TextWrapping="Wrap" Text="{TemplateBinding Content}" VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Role" Value="Receiver">
|
||||
<Setter TargetName="Tail" Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter TargetName="Tail" Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="Body" Property="Margin" Value="3,0,0,0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="ChatBubbleReceiverBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<ControlTemplate x:Key="ChatBubbleImageBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<Grid>
|
||||
<Path Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Left" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15" RenderTransformOrigin="0.5,0.5">
|
||||
<Path.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Path.RenderTransform>
|
||||
</Path>
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="15" Margin="3,0,0,0">
|
||||
<ContentPresenter Name="Presenter" Margin="{TemplateBinding Padding}" VerticalAlignment="Center">
|
||||
<ContentPresenter.OpacityMask>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Border Background="White" CornerRadius="10" Width="{Binding ActualWidth,ElementName=Presenter}" Height="{Binding ActualHeight,ElementName=Presenter}"/>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</ContentPresenter.OpacityMask>
|
||||
</ContentPresenter>
|
||||
<Path Name="Tail" Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15" RenderTransformOrigin="0.5,0.5"/>
|
||||
<Border Name="Body" Background="{TemplateBinding Background}" CornerRadius="15" Margin="0,0,3,0">
|
||||
<Grid>
|
||||
<Image Margin="{TemplateBinding Padding}" VerticalAlignment="Center" Source="{TemplateBinding Content}"/>
|
||||
<Border BorderThickness="{TemplateBinding Padding}" BorderBrush="{TemplateBinding Background}" Background="{x:Null}" CornerRadius="15"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Role" Value="Receiver">
|
||||
<Setter TargetName="Tail" Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter TargetName="Tail" Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="Body" Property="Margin" Value="3,0,0,0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="ChatBubbleAudioBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12" Name="Definition1"/>
|
||||
<ColumnDefinition Name="Definition2"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Name="Dot" VerticalAlignment="Top" Fill="{DynamicResource DangerBrush}" Width="6" Height="6" Visibility="{TemplateBinding IsRead,Converter={StaticResource Boolean2BooleanReConverter}}" Margin="0,0,6,0"/>
|
||||
<Path Name="Tail" Grid.Column="1" Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15" RenderTransformOrigin="0.5,0.5"/>
|
||||
<Border Name="Body" Grid.Column="1" Background="{TemplateBinding Background}" CornerRadius="15" Margin="0,0,3,0">
|
||||
<Grid VerticalAlignment="Center" Margin="{TemplateBinding Padding}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentPresenter Name="Presenter" VerticalAlignment="Center"/>
|
||||
<Path Name="Audio" Grid.Column="1" Data="{StaticResource AudioGeometry}" Fill="{TemplateBinding Foreground}" Width="16" Height="16" Margin="6,0,0,0" RenderTransformOrigin="0.5,0.5">
|
||||
<Path.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Path.RenderTransform>
|
||||
</Path>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Role" Value="Receiver">
|
||||
<Setter TargetName="Tail" Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter TargetName="Tail" Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="Tail" Property="Grid.Column" Value="0"/>
|
||||
<Setter TargetName="Dot" Property="Grid.Column" Value="1"/>
|
||||
<Setter TargetName="Dot" Property="Margin" Value="6,0,0,0"/>
|
||||
<Setter TargetName="Body" Property="Margin" Value="3,0,0,0"/>
|
||||
<Setter TargetName="Body" Property="Grid.Column" Value="0"/>
|
||||
<Setter TargetName="Definition1" Property="Width" Value="Auto"/>
|
||||
<Setter TargetName="Definition2" Property="Width" Value="12"/>
|
||||
<Setter TargetName="Audio" Property="Grid.Column" Value="0"/>
|
||||
<Setter TargetName="Audio" Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter TargetName="Audio" Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="1"/>
|
||||
</TransformGroup>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="Presenter" Property="Grid.Column" Value="1"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="ChatBubbleCustomBaseTemplate" TargetType="controls:ChatBubble">
|
||||
<Grid>
|
||||
<Path Name="Tail" Data="{StaticResource BubbleTailGeometry}" Fill="{TemplateBinding Background}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Bottom" Width="15" Height="15" RenderTransformOrigin="0.5,0.5"/>
|
||||
<Border Name="Body" Background="{TemplateBinding Background}" CornerRadius="15" Margin="0,0,3,0">
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Role" Value="Receiver">
|
||||
<Setter TargetName="Tail" Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter TargetName="Tail" Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleY="1" ScaleX="-1"/>
|
||||
</TransformGroup>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="Body" Property="Margin" Value="3,0,0,0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="ChatBubbleBaseStyle" TargetType="controls:ChatBubble">
|
||||
@@ -54,14 +140,25 @@
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
<Setter Property="Margin" Value="10"/>
|
||||
<Setter Property="MinHeight" Value="{StaticResource DefaultControlHeight}"/>
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleSenderBaseTemplate}"/>
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleStringBaseTemplate}"/>
|
||||
<Setter Property="IsRead" Value="{Binding IsSelected,RelativeSource={RelativeSource Self}}"/>
|
||||
<Setter Property="MaxWidth" Value="280"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Role" Value="Receiver">
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleReceiverBaseTemplate}"/>
|
||||
<Setter Property="Background" Value="{DynamicResource BorderBrush}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
</Trigger>
|
||||
<Trigger Property="Type" Value="Image">
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleImageBaseTemplate}"/>
|
||||
<Setter Property="MaxHeight" Value="280"/>
|
||||
</Trigger>
|
||||
<Trigger Property="Type" Value="Audio">
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleAudioBaseTemplate}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="Type" Value="Custom">
|
||||
<Setter Property="Template" Value="{StaticResource ChatBubbleCustomBaseTemplate}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
|
||||
@@ -9,7 +9,22 @@
|
||||
<ResourceDictionary Source="ListBox.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style TargetType="controls:Carousel" BasedOn="{StaticResource StackPanelListBox}">
|
||||
<Style x:Key="CarouselListBoxItemStyle" BasedOn="{StaticResource ListBoxItemCustom}" TargetType="ListBoxItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Height" Value="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
|
||||
</Style>
|
||||
|
||||
<ItemsPanelTemplate x:Key="CarouselListBoxItemPanelTemplate">
|
||||
<StackPanel FocusVisualStyle="{x:Null}" Orientation="Horizontal" HorizontalAlignment="Left"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<Style x:Key="CarouselListBox" BasedOn="{StaticResource ListBoxBaseStyle}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource CarouselListBoxItemPanelTemplate}"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource CarouselListBoxItemStyle}"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="controls:Carousel" BasedOn="{StaticResource CarouselListBox}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:Carousel">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<!--默认样式-->
|
||||
<Style BasedOn="{StaticResource ListBoxBaseStyle}" TargetType="ListBox"/>
|
||||
|
||||
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
|
||||
<Style x:Key="ListBoxItemCustom" TargetType="ListBoxItem">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
@@ -26,28 +26,41 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ListBoxItemFullStyle" BasedOn="{StaticResource ListBoxItemStyle}" TargetType="ListBoxItem">
|
||||
<Style x:Key="ListBoxCustom" TargetType="ListBox">
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource ListBoxItemCustom}"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Height" Value="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
|
||||
</Style>
|
||||
|
||||
<ItemsPanelTemplate x:Key="WrapPanelItemsPanelTemplate">
|
||||
<ItemsPanelTemplate x:Key="WrapPanelHorizontalItemsPanelTemplate">
|
||||
<WrapPanel FocusVisualStyle="{x:Null}"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<Style x:Key="WrapPanelListBox" BasedOn="{StaticResource ListBoxBaseStyle}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource WrapPanelItemsPanelTemplate}"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource ListBoxItemStyle}"/>
|
||||
<Style x:Key="WrapPanelHorizontalListBox" BasedOn="{StaticResource ListBoxCustom}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource WrapPanelHorizontalItemsPanelTemplate}"/>
|
||||
</Style>
|
||||
|
||||
<ItemsPanelTemplate x:Key="StackPanelItemsPanelTemplate">
|
||||
<StackPanel FocusVisualStyle="{x:Null}" Orientation="Horizontal" HorizontalAlignment="Left"/>
|
||||
<ItemsPanelTemplate x:Key="WrapPanelVerticalItemsPanelTemplate">
|
||||
<WrapPanel FocusVisualStyle="{x:Null}" Orientation="Vertical"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<Style x:Key="StackPanelListBox" BasedOn="{StaticResource ListBoxBaseStyle}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource StackPanelItemsPanelTemplate}"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource ListBoxItemFullStyle}"/>
|
||||
<Style x:Key="WrapPanelVerticalListBox" BasedOn="{StaticResource ListBoxCustom}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource WrapPanelVerticalItemsPanelTemplate}"/>
|
||||
</Style>
|
||||
|
||||
<ItemsPanelTemplate x:Key="StackPanelHorizontalItemsPanelTemplate">
|
||||
<StackPanel FocusVisualStyle="{x:Null}" Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<Style x:Key="StackPanelHorizontalListBox" BasedOn="{StaticResource ListBoxCustom}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource StackPanelHorizontalItemsPanelTemplate}"/>
|
||||
</Style>
|
||||
|
||||
<ItemsPanelTemplate x:Key="StackPanelVerticalItemsPanelTemplate">
|
||||
<StackPanel FocusVisualStyle="{x:Null}" HorizontalAlignment="Stretch"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<Style x:Key="StackPanelVerticalListBox" BasedOn="{StaticResource ListBoxCustom}" TargetType="ListBox">
|
||||
<Setter Property="ItemsPanel" Value="{StaticResource StackPanelVerticalItemsPanelTemplate}"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -4,9 +4,9 @@ using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal class VisualHelper
|
||||
public class VisualHelper
|
||||
{
|
||||
public static VisualStateGroup TryGetVisualStateGroup(DependencyObject dependencyObject, string groupName)
|
||||
internal static VisualStateGroup TryGetVisualStateGroup(DependencyObject dependencyObject, string groupName)
|
||||
{
|
||||
var root = GetImplementationRoot(dependencyObject);
|
||||
if (root == null)
|
||||
@@ -20,11 +20,13 @@ namespace HandyControl.Tools
|
||||
.FirstOrDefault(group => string.CompareOrdinal(groupName, group.Name) == 0);
|
||||
}
|
||||
|
||||
public static FrameworkElement GetImplementationRoot(DependencyObject dependencyObject)
|
||||
internal static FrameworkElement GetImplementationRoot(DependencyObject dependencyObject)
|
||||
{
|
||||
return 1 == VisualTreeHelper.GetChildrenCount(dependencyObject)
|
||||
? VisualTreeHelper.GetChild(dependencyObject, 0) as FrameworkElement
|
||||
: null;
|
||||
}
|
||||
|
||||
public static Window GetActiveWindow() => Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace HandyControlDemo.Data
|
||||
{
|
||||
internal class AppConfig
|
||||
{
|
||||
public static string SavePath = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json";
|
||||
public static readonly string SavePath = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json";
|
||||
|
||||
public string Lang { get; set; } = "zh-cn";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace HandyControlDemo.Data
|
||||
|
||||
@@ -146,11 +146,7 @@
|
||||
|
||||
public static readonly string ClearLeftSelected = nameof(ClearLeftSelected);
|
||||
|
||||
public static readonly string SendChatString = nameof(SendChatString);
|
||||
|
||||
public static readonly string SendChatImage = nameof(SendChatImage);
|
||||
|
||||
public static readonly string SendChatAudio = nameof(SendChatAudio);
|
||||
public static readonly string SendChatMessage = nameof(SendChatMessage);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -85,9 +85,7 @@ var messageList = new List<string>
|
||||
"FullSwitch",
|
||||
"ContributorsView",
|
||||
"ClearLeftSelected",
|
||||
"SendChatString",
|
||||
"SendChatImage",
|
||||
"SendChatAudio"
|
||||
"SendChatMessage"
|
||||
};
|
||||
#>
|
||||
namespace HandyControlDemo.Data
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
namespace HandyControlDemo.Data
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControlDemo.Data
|
||||
{
|
||||
public class ChatInfoModel
|
||||
public struct ChatInfoModel
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public object Message { get; set; }
|
||||
|
||||
public string SenderId { get; set; }
|
||||
|
||||
public ChatRoleType Role { get; set; }
|
||||
|
||||
public ChatMessageType Type { get; set; }
|
||||
|
||||
public object Enclosure { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -118,9 +118,10 @@
|
||||
<DependentUpon>Lang.en.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Service\DataService.cs" />
|
||||
<Compile Include="Tools\AssemblyHelper.cs" />
|
||||
<Compile Include="Tools\CommonHelper.cs" />
|
||||
<Compile Include="Tools\Helper\AssemblyHelper.cs" />
|
||||
<Compile Include="Tools\Helper\CommonHelper.cs" />
|
||||
<Compile Include="Tools\Converter\StringRepeatConverter.cs" />
|
||||
<Compile Include="Tools\Helper\ExternDllHelper.cs" />
|
||||
<Compile Include="UserControl\Basic\Avatar.xaml.cs">
|
||||
<DependentUpon>Avatar.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -836,5 +837,6 @@
|
||||
<Name>HandyControl</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -915,6 +915,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 秒 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Second {
|
||||
get {
|
||||
return ResourceManager.GetString("Second", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 选中 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -492,4 +492,7 @@
|
||||
<data name="PushToTalk" xml:space="preserve">
|
||||
<value>Push to talk</value>
|
||||
</data>
|
||||
<data name="Second" xml:space="preserve">
|
||||
<value>Sec</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -492,4 +492,7 @@
|
||||
<data name="PushToTalk" xml:space="preserve">
|
||||
<value>按住说话</value>
|
||||
</data>
|
||||
<data name="Second" xml:space="preserve">
|
||||
<value>秒</value>
|
||||
</data>
|
||||
</root>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 49 KiB |
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,12 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControlDemo.Tools
|
||||
{
|
||||
internal class ExternDllHelper
|
||||
{
|
||||
private const string Winmm = "winmm.dll";
|
||||
|
||||
[DllImport(Winmm, EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
|
||||
public static extern int MciSendString(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
|
||||
xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:command="http://www.galasoft.ch/mvvmlight"
|
||||
xmlns:interactivity="clr-namespace:HandyControl.Interactivity;assembly=HandyControl"
|
||||
mc:Ignorable="d"
|
||||
Height="486"
|
||||
Effect="{StaticResource EffectShadow5}"
|
||||
@@ -18,13 +17,18 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel>
|
||||
<controls:ChatBubble Role="Receiver" Content="123123123123"/>
|
||||
<controls:ChatBubble Content="123123123123"/>
|
||||
<controls:ChatBubble Role="Receiver">
|
||||
<Image Width="200" Source="/HandyControlDemo;component/Resources/Img/b1.jpg"/>
|
||||
</controls:ChatBubble>
|
||||
</StackPanel>
|
||||
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.CanContentScroll="False" Background="Transparent" controls:ChatBubble.MaxWidth="300" BorderThickness="0" Style="{StaticResource StackPanelVerticalListBox}" ItemsSource="{Binding ChatInfos}">
|
||||
<interactivity:Interaction.Triggers>
|
||||
<interactivity:RoutedEventTrigger RoutedEvent="controls:ChatBubble.Selected">
|
||||
<interactivity:EventToCommand Command="{Binding ReadMessageCmd}" PassEventArgsToCommand="True" />
|
||||
</interactivity:RoutedEventTrigger>
|
||||
</interactivity:Interaction.Triggers>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:ChatBubble Role="{Binding Role}" Type="{Binding Type}" Content="{Binding Message}" Tag="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Border Background="{DynamicResource DarkDefaultBrush}" Grid.Row="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -34,14 +38,23 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToggleButton Name="ToggleButtonAudio" controls:BorderElement.CornerRadius="15" Width="30" Height="30" Padding="7" Margin="6" controls:IconSwitchElement.Geometry="{StaticResource AudioGeometry}" controls:IconSwitchElement.GeometrySelected="{StaticResource KeyboardGeometry}" Style="{StaticResource ToggleButtonIcon}"/>
|
||||
<Button Command="{Binding OpenImageCmd}" Grid.Column="2" Margin="6,0,6,0" controls:BorderElement.CornerRadius="15" Width="30" Height="30" Padding="7" controls:IconElement.Geometry="{StaticResource ImageGeometry}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ChatString}" Visibility="{Binding IsChecked,ElementName=ToggleButtonAudio,Converter={StaticResource Boolean2VisibilityReConverter}}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="KeyDown">
|
||||
<command:EventToCommand Command="{Binding SendStringCmd}" PassEventArgsToCommand="True" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<TextBox Grid.Column="1" Text="{Binding ChatString,UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding IsChecked,ElementName=ToggleButtonAudio,Converter={StaticResource Boolean2VisibilityReConverter}}">
|
||||
<interactivity:Interaction.Triggers>
|
||||
<interactivity:EventTrigger EventName="KeyDown">
|
||||
<interactivity:EventToCommand Command="{Binding SendStringCmd}" PassEventArgsToCommand="True" />
|
||||
</interactivity:EventTrigger>
|
||||
</interactivity:Interaction.Triggers>
|
||||
</TextBox>
|
||||
<Button Grid.Column="1" Visibility="{Binding IsChecked,ElementName=ToggleButtonAudio,Converter={StaticResource Boolean2VisibilityConverter}}" Content="{x:Static langs:Lang.PushToTalk}" HorizontalAlignment="Stretch"/>
|
||||
<Button Grid.Column="1" Visibility="{Binding IsChecked,ElementName=ToggleButtonAudio,Converter={StaticResource Boolean2VisibilityConverter}}" Content="{x:Static langs:Lang.PushToTalk}" HorizontalAlignment="Stretch">
|
||||
<interactivity:Interaction.Triggers>
|
||||
<interactivity:EventTrigger EventName="PreviewMouseLeftButtonDown">
|
||||
<interactivity:EventToCommand Command="{Binding StartRecordCmd}"/>
|
||||
</interactivity:EventTrigger>
|
||||
<interactivity:EventTrigger EventName="PreviewMouseLeftButtonUp">
|
||||
<interactivity:EventToCommand Command="{Binding StopRecordCmd}"/>
|
||||
</interactivity:EventTrigger>
|
||||
</interactivity:Interaction.Triggers>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:userControl="clr-namespace:HandyControlDemo.UserControl"
|
||||
DataContext="{Binding ContributorsView,Source={StaticResource Locator}}"
|
||||
Background="{DynamicResource SecondaryRegionBrush}">
|
||||
<ListBox Background="{DynamicResource GitHubDrawingBrush}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" BorderThickness="0" ItemsSource="{Binding DataList}" ItemsPanel="{StaticResource FluidMoveBehaviorWrapPanelItemsPanelTemplate}">
|
||||
<ListBox Background="{DynamicResource GitHubDrawingBrush}" ItemContainerStyle="{StaticResource ListBoxItemCustom}" BorderThickness="0" ItemsSource="{Binding DataList}" ItemsPanel="{StaticResource FluidMoveBehaviorWrapPanelItemsPanelTemplate}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<userControl:Avatar UserName="{Binding UserName}" Link="{Binding Link}" Source="{Binding AvatarUri}"/>
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Media;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Imaging;
|
||||
using GalaSoft.MvvmLight;
|
||||
using GalaSoft.MvvmLight.CommandWpf;
|
||||
using GalaSoft.MvvmLight.Messaging;
|
||||
using HandyControl.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControlDemo.Data;
|
||||
using HandyControlDemo.Tools;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace HandyControlDemo.ViewModel
|
||||
{
|
||||
public class ChatBoxViewModel : ViewModelBase
|
||||
{
|
||||
private static readonly string AutioCachePath = $"{AppDomain.CurrentDomain.BaseDirectory}Cache";
|
||||
|
||||
private readonly string _id = Guid.NewGuid().ToString();
|
||||
|
||||
private readonly Stopwatch _stopwatch = new Lazy<Stopwatch>(() => new Stopwatch()).Value;
|
||||
|
||||
public ChatBoxViewModel()
|
||||
{
|
||||
Messenger.Default.Register<ChatInfoModel>(this, MessageToken.SendChatString, ReceiveString);
|
||||
Messenger.Default.Register<ChatInfoModel>(this, MessageToken.SendChatImage, ReceiveImage);
|
||||
Messenger.Default.Register<ChatInfoModel>(this, MessageToken.SendChatAudio, ReceiveAudio);
|
||||
Messenger.Default.Register<ChatInfoModel>(this, MessageToken.SendChatMessage, ReceiveMessage);
|
||||
}
|
||||
|
||||
private void ReceiveString(ChatInfoModel info)
|
||||
private void ReceiveMessage(ChatInfoModel info)
|
||||
{
|
||||
if (!_id.Equals(info.SenderId)) return;
|
||||
}
|
||||
|
||||
private void ReceiveImage(ChatInfoModel info)
|
||||
{
|
||||
if (!_id.Equals(info.SenderId)) return;
|
||||
}
|
||||
|
||||
private void ReceiveAudio(ChatInfoModel info)
|
||||
{
|
||||
if (!_id.Equals(info.SenderId)) return;
|
||||
if (_id.Equals(info.SenderId)) return;
|
||||
info.Role = ChatRoleType.Receiver;
|
||||
ChatInfos.Add(info);
|
||||
}
|
||||
|
||||
private string _chatString;
|
||||
@@ -43,6 +47,8 @@ namespace HandyControlDemo.ViewModel
|
||||
set => Set(ref _chatString, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<ChatInfoModel> ChatInfos { get; set; } = new ObservableCollection<ChatInfoModel>();
|
||||
|
||||
public RelayCommand<KeyEventArgs> SendStringCmd => new Lazy<RelayCommand<KeyEventArgs>>(() =>
|
||||
new RelayCommand<KeyEventArgs>(SendString)).Value;
|
||||
|
||||
@@ -51,15 +57,94 @@ namespace HandyControlDemo.ViewModel
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ChatString)) return;
|
||||
Messenger.Default.Send(new ChatInfoModel
|
||||
var info = new ChatInfoModel
|
||||
{
|
||||
Message = ChatString,
|
||||
SenderId = _id
|
||||
}, MessageToken.SendChatString);
|
||||
SenderId = _id,
|
||||
Type = ChatMessageType.String,
|
||||
Role = ChatRoleType.Sender
|
||||
};
|
||||
ChatInfos.Add(info);
|
||||
Messenger.Default.Send(info, MessageToken.SendChatMessage);
|
||||
ChatString = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand<RoutedEventArgs> ReadMessageCmd => new Lazy<RelayCommand<RoutedEventArgs>>(() =>
|
||||
new RelayCommand<RoutedEventArgs>(ReadMessage)).Value;
|
||||
|
||||
private void ReadMessage(RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is FrameworkElement element && element.Tag is ChatInfoModel info)
|
||||
{
|
||||
if (info.Type == ChatMessageType.Image)
|
||||
{
|
||||
new ImageBrowser(new Uri(info.Enclosure.ToString()))
|
||||
{
|
||||
Owner = VisualHelper.GetActiveWindow()
|
||||
}.Show();
|
||||
}
|
||||
else if (info.Type == ChatMessageType.Audio)
|
||||
{
|
||||
var player = new SoundPlayer(info.Enclosure.ToString());
|
||||
player.PlaySync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand StartRecordCmd => new Lazy<RelayCommand>(() =>
|
||||
new RelayCommand(StartRecord)).Value;
|
||||
|
||||
private void StartRecord()
|
||||
{
|
||||
ExternDllHelper.MciSendString("set wave bitpersample 8", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("set wave samplespersec 20000", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("set wave channels 2", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("set wave format tag pcm", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("open new type WAVEAudio alias movie", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("record movie", "", 0, 0);
|
||||
|
||||
_stopwatch.Reset();
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
public RelayCommand StopRecordCmd => new Lazy<RelayCommand>(() =>
|
||||
new RelayCommand(StopRecord)).Value;
|
||||
|
||||
private void StopRecord()
|
||||
{
|
||||
if (!Directory.Exists(AutioCachePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(AutioCachePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Growl.Error(e.Message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var cachePath = $"{AutioCachePath}\\{Guid.NewGuid().ToString()}";
|
||||
ExternDllHelper.MciSendString("stop movie", "", 0, 0);
|
||||
ExternDllHelper.MciSendString($"save movie {cachePath}", "", 0, 0);
|
||||
ExternDllHelper.MciSendString("close movie", "", 0, 0);
|
||||
|
||||
_stopwatch.Stop();
|
||||
|
||||
var info = new ChatInfoModel
|
||||
{
|
||||
Message = $"{_stopwatch.Elapsed.Seconds.ToString()} {Properties.Langs.Lang.Second}",
|
||||
SenderId = _id,
|
||||
Type = ChatMessageType.Audio,
|
||||
Role = ChatRoleType.Sender,
|
||||
Enclosure = cachePath
|
||||
};
|
||||
ChatInfos.Add(info);
|
||||
Messenger.Default.Send(info, MessageToken.SendChatMessage);
|
||||
}
|
||||
|
||||
public RelayCommand OpenImageCmd => new Lazy<RelayCommand>(() =>
|
||||
new RelayCommand(OpenImage)).Value;
|
||||
|
||||
@@ -71,11 +156,16 @@ namespace HandyControlDemo.ViewModel
|
||||
var fileName = dialog.FileName;
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
Messenger.Default.Send(new ChatInfoModel
|
||||
var info = new ChatInfoModel
|
||||
{
|
||||
Message = fileName,
|
||||
SenderId = _id
|
||||
}, MessageToken.SendChatImage);
|
||||
Message = BitmapFrame.Create(new Uri(fileName)),
|
||||
SenderId = _id,
|
||||
Type = ChatMessageType.Image,
|
||||
Role = ChatRoleType.Sender,
|
||||
Enclosure = fileName
|
||||
};
|
||||
ChatInfos.Add(info);
|
||||
Messenger.Default.Send(info, MessageToken.SendChatMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace HandyControlDemo.ViewModel
|
||||
|
||||
public PaginationDemoViewModel PaginationDemo => ServiceLocator.Current.GetInstance<PaginationDemoViewModel>();
|
||||
|
||||
public ChatBoxViewModel ChatBox => ServiceLocator.Current.GetInstance<ChatBoxViewModel>();
|
||||
public ChatBoxViewModel ChatBox => new ChatBoxViewModel();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
## Latest examples
|
||||
|
||||
### ChatBubble
|
||||
|
||||

|
||||
|
||||
### Transfer
|
||||
|
||||

|
||||
@@ -26,12 +30,12 @@
|
||||
|
||||

|
||||
|
||||
## History publication
|
||||
|
||||
### WaterfallPanel
|
||||
|
||||

|
||||
|
||||
## History publication
|
||||
|
||||
### Rate
|
||||
|
||||

|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 310 KiB |
Reference in new issue
Block a user